// src/backend-contract/operations.ts import type { BleErrorCode } from './errors' import type { BackendOperationHandle, BorrowedBytes, Capacity, Deadline, OperationCorrelation, OwnedBytes } from './primitives' import type { OverflowPolicy } from './streams' export interface PublicOperationOptions { readonly signal: AbortSignal | null readonly deadline: Deadline | null } export type WriteMode = 'with-response' | 'without-response' export interface WritePolicy extends PublicOperationOptions { readonly mode: WriteMode } export interface OperationOptions extends PublicOperationOptions { readonly correlation: OperationCorrelation } export type OperationTerminalOutcome = | 'succeeded' | 'failed' | 'aborted' | 'timed-out' | 'disconnected' | 'reset' | 'adapter-unavailable' | 'destroyed' export interface OperationTerminalRecord { readonly correlation: OperationCorrelation readonly outcome: OperationTerminalOutcome readonly cause: BleErrorCode | null } export interface CancellationAcknowledgement { readonly handle: BackendOperationHandle readonly state: 'cancellation-requested' | 'already-terminal' | 'not-cancellable' } /** Resolves after backend-owned/native resources for one dispatch have retired. */ export type BackendOperationPhysicalSettlement = Promise export interface BackendOperationDispatch { readonly handle: BackendOperationHandle readonly completion: Promise readonly physicalSettlement?: BackendOperationPhysicalSettlement requestCancellation(): Promise> } export function createBackendOperationDispatch( handle: BackendOperationHandle, completion: Promise, requestCancellation: () => Promise>, physicalSettlement?: BackendOperationPhysicalSettlement ): BackendOperationDispatch { const dispatch = { handle, completion, requestCancellation } return physicalSettlement === undefined ? dispatch : { ...dispatch, physicalSettlement } } export interface OperationSettlementCoordinator { complete(result: Result): Result acknowledgeCancellation( state: CancellationAcknowledgement['state'] ): CancellationAcknowledgement } class DefaultOperationSettlementCoordinator implements OperationSettlementCoordinator { private settled = false private cancellationAcknowledgement: CancellationAcknowledgement | null = null constructor(private readonly handle: BackendOperationHandle) {} complete(result: Result): Result { if (this.settled) { throw new Error('operation completion was already settled') } this.settled = true return result } acknowledgeCancellation( state: CancellationAcknowledgement['state'] ): CancellationAcknowledgement { if (this.cancellationAcknowledgement !== null) { return this.cancellationAcknowledgement } this.cancellationAcknowledgement = { handle: this.handle, state: this.settled ? 'already-terminal' : state } return this.cancellationAcknowledgement } } export function createOperationSettlementCoordinator( handle: BackendOperationHandle ): OperationSettlementCoordinator { return new DefaultOperationSettlementCoordinator(handle) } export interface WriteReceipt { readonly terminal: OperationTerminalRecord readonly commitState: 'confirmed' | 'unknown' } /** Policy for the portable core-emulated sequential chunked write operation. */ export interface LongWritePolicy extends WritePolicy { readonly chunkSize?: number } /** One chunk state in an immutable long-write receipt. */ export interface LongWriteChunkProgress { readonly index: number readonly byteOffset: number readonly byteLength: number readonly state: 'confirmed' | 'uncertain' | 'not-started' } /** * A receipt whose terminal occurred before a maximum-write-length observation * established a chunk plan. Its zero chunk values are explicit non-claims. */ export interface LongWriteNotPlannedReceipt { readonly terminal: OperationTerminalRecord readonly planState: 'not-planned' readonly commitState: 'not-started' readonly totalBytes: number readonly chunkSize: 0 readonly totalChunks: 0 readonly chunks: readonly LongWriteChunkProgress[] readonly completedChunks: 0 readonly committedBytes: 0 readonly failedChunkIndex: null } /** A receipt whose maximum-write-length observation produced an exact chunk plan. */ export interface LongWritePlannedReceipt { readonly terminal: OperationTerminalRecord readonly planState: 'planned' readonly commitState: 'confirmed' | 'unknown' readonly totalBytes: number readonly chunkSize: number readonly totalChunks: number readonly chunks: readonly LongWriteChunkProgress[] readonly completedChunks: number readonly committedBytes: number readonly failedChunkIndex: number | null } /** * Stable terminal receipt for a chunked write. It resolves for all operation * terminals so callers can decide how to recover from a partially committed * value without relying on an exception's incidental shape. */ export type LongWriteReceipt = | LongWriteNotPlannedReceipt | LongWritePlannedReceipt export interface SubscriptionOptions extends PublicOperationOptions { readonly delivery: { readonly itemCapacity: Capacity readonly byteCapacity: Capacity readonly reservedControlCapacity: Capacity readonly overflowPolicy: OverflowPolicy } readonly deliveryMode?: 'prefer-notification' | 'prefer-indication' | 'require-notification' | 'require-indication' } export interface SubscribeRequest { readonly operation: OperationOptions readonly options: SubscriptionOptions } export interface ReadRequest { readonly operation: OperationOptions } export interface WriteRequest { readonly operation: OperationOptions readonly bytes: BorrowedBytes readonly mode: WriteMode } export interface ReadResult { readonly value: OwnedBytes readonly terminal: OperationTerminalRecord } export type WriteResult = WriteReceipt