import type { JsonValue } from "../../core/types.js"; import type { LocusActionPayloads, LocusClientActionMessage, LocusClientMessage, LocusClientRecoverMessage, LocusConnectionContext, LocusDisposer, LocusIncarnationId, LocusLogicalMapId, LocusServerMessage, LocusSessionId, } from "../../types/locus.types.js"; /** @internal Finite commands, queries, and session-control requests. */ export type LocusFiniteOperationRequest< TActions extends LocusActionPayloads = LocusActionPayloads, > = LocusClientActionMessage | Extract, { type: "action-status" | "session-create" | "session-attach" | "session-goodbye"; }>; /** @internal Typed finite authority outcomes and session-control outcomes. */ export type LocusFiniteOperationOutcome = Extract; /** @internal Recovery establishment and recovery-transfer output. */ export type LocusSynchronizationOutput = Extract; /** @internal Ordered canonical publication after a caught-up boundary. */ export type LocusCanonicalPublication = Extract; /** @internal Non-canonical application event output. */ export type LocusTransientEventOutput = Extract; /** * Internal typed downstream sink. Transport adapters frame these semantic * outputs; Locus authority never needs to know how their bytes are carried. */ export type LocusDownstreamSink< TSynchronization = LocusSynchronizationOutput, TPublication = LocusCanonicalPublication, > = Readonly<{ finite: (outcome: LocusFiniteOperationOutcome) => void; synchronization: (output: TSynchronization) => void; publication: (publication: TPublication) => void; event: (event: LocusTransientEventOutput) => void; }>; /** @internal Authority/session evidence shared by operations and synchronization. */ export type LocusAuthoritySessionBinding = Readonly<{ principalId: string | undefined; logicalMapId: LocusLogicalMapId; incarnationId: LocusIncarnationId; readonly sessionId: LocusSessionId | undefined; readonly attachmentEpoch: number | undefined; readonly attached: boolean; }>; /** * Internal semantic attachment. A WebSocket is one adapter for this shape; * future finite-operation and synchronization transports may be composed * around the same authority/session binding. */ export type LocusSemanticAttachment< TActions extends LocusActionPayloads = LocusActionPayloads, TSynchronizationRequest = LocusClientRecoverMessage, > = Readonly<{ binding: LocusAuthoritySessionBinding; operations: Readonly<{ submit: (request: LocusFiniteOperationRequest) => void | Promise; }>; synchronization: Readonly<{ begin: (request: TSynchronizationRequest) => void; cancel: () => void; }>; emit_event: (event: string, payload: JsonValue) => void; close: (hostShutdown?: boolean) => void; }>; export type LocusSemanticAttachmentOptions = Readonly<{ downstream: LocusDownstreamSink; connection?: LocusConnectionContext; /** Adapter-owned physical listener cleanup, invoked when the attachment ends. */ onClose?: LocusDisposer; }>; type BoundSemanticAttachmentFactory = ( options: LocusSemanticAttachmentOptions, ) => LocusSemanticAttachment; const semanticAttachmentFactories = new WeakMap(); export function register_locus_semantic_attachment_internal< TActions extends LocusActionPayloads = LocusActionPayloads, >( locus: object, factory: (options: LocusSemanticAttachmentOptions) => LocusSemanticAttachment, ): void { semanticAttachmentFactories.set(locus, factory as unknown as BoundSemanticAttachmentFactory); } /** Attach typed operation and synchronization capabilities to one Locus authority. */ export function attach_locus_semantic_transport_internal< TActions extends LocusActionPayloads = LocusActionPayloads, >( locus: object, options: LocusSemanticAttachmentOptions, ): LocusSemanticAttachment { const factory = semanticAttachmentFactories.get(locus); if (factory === undefined) throw new Error("Locus semantic attachment authority is unavailable."); return factory(options) as LocusSemanticAttachment; } /** Deliver one typed server output to its semantic downstream capability. */ export function deliver_locus_downstream_internal( sink: LocusDownstreamSink, message: LocusServerMessage, ): void { if (message.type === "commit") { sink.publication(message); return; } if (message.type === "event") { sink.event(message); return; } if (message.type === "recovery-plan" || message.type === "recovery-commit" || message.type === "recovery-snapshot" || message.type === "recovery-caught-up" || message.type === "recovery-error") { sink.synchronization(message); return; } if (message.type === "patch") { throw new Error("Legacy patch messages are not finite operation outcomes."); } sink.finite(message); } /** @internal Transport adapters classify decoded client input at this boundary. */ export function is_locus_synchronization_request_internal< TActions extends LocusActionPayloads, >(message: LocusClientMessage): message is LocusClientRecoverMessage { return message.type === "recover"; } /** @internal No-op attachment returned by unavailable authority runtimes. */ export function inert_locus_semantic_attachment_internal< TActions extends LocusActionPayloads = LocusActionPayloads, >( logicalMapId: LocusLogicalMapId, incarnationId: LocusIncarnationId, principalId?: string, ): LocusSemanticAttachment { const binding = Object.freeze({ principalId, logicalMapId, incarnationId, get sessionId() { return undefined; }, get attachmentEpoch() { return undefined; }, get attached() { return false; }, }); return Object.freeze({ binding, operations: Object.freeze({ submit: () => {} }), synchronization: Object.freeze({ begin: () => {}, cancel: () => {} }), emit_event: () => {}, close: () => {}, }); }