@nice-code/action 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -109
- package/build/{ActionDevtoolsCore-D_JvgPmz.d.mts → ActionDevtoolsCore-CQ0vrvPD.d.cts} +2 -2
- package/build/{ActionDevtoolsCore-dV-IVPcP.d.cts → ActionDevtoolsCore-CiLBYC3K.d.mts} +2 -2
- package/build/{ActionPayload.types-CnfWlkA1.d.cts → ActionPayload.types-Dx1JPyfs.d.mts} +292 -222
- package/build/{ActionPayload.types-D0DM-g65.d.mts → ActionPayload.types-L9k0LyBd.d.cts} +292 -222
- package/build/devtools/browser/index.d.cts +1 -1
- package/build/devtools/browser/index.d.mts +1 -1
- package/build/devtools/server/index.d.cts +1 -1
- package/build/devtools/server/index.d.mts +1 -1
- package/build/httpAcceptorCarrier-DL8lf0xB.mjs +3906 -0
- package/build/httpAcceptorCarrier-DL8lf0xB.mjs.map +1 -0
- package/build/httpAcceptorCarrier-OnJxzsAD.cjs +4291 -0
- package/build/httpAcceptorCarrier-OnJxzsAD.cjs.map +1 -0
- package/build/index.cjs +395 -4125
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +2 -2
- package/build/index.d.mts +2 -2
- package/build/index.mjs +331 -4058
- package/build/index.mjs.map +1 -1
- package/build/platform/cloudflare/index.cjs +30 -2
- package/build/platform/cloudflare/index.cjs.map +1 -1
- package/build/platform/cloudflare/index.d.cts +55 -2
- package/build/platform/cloudflare/index.d.mts +55 -2
- package/build/platform/cloudflare/index.mjs +28 -2
- package/build/platform/cloudflare/index.mjs.map +1 -1
- package/build/react-query/index.d.cts +1 -1
- package/build/react-query/index.d.mts +1 -1
- package/package.json +4 -4
- package/build/wsAcceptorCarrier-BDJRIPfu.cjs +0 -103
- package/build/wsAcceptorCarrier-BDJRIPfu.cjs.map +0 -1
- package/build/wsAcceptorCarrier-CW2qX25W.mjs +0 -80
- package/build/wsAcceptorCarrier-CW2qX25W.mjs.map +0 -1
package/build/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["DEFAULT_SERVER_SECURITY_LEVELS","ENVELOPE","ENVELOPE_LENGTH","textEncoder","textDecoder","normalizeFrame"],"sources":["../src/nice_action.static.ts","../src/ActionRuntime/utils/runtimeCoordinateToStringIds.ts","../src/ActionRuntime/RuntimeCoordinate.ts","../src/ActionDefinition/Action/ActionBase.ts","../src/ActionDefinition/Action/Context/ActionContext.ts","../src/ActionDefinition/Action/Payload/ActionPayload.ts","../src/utils/hashPayloadData.ts","../src/ActionDefinition/Action/Payload/ActionPayload.types.ts","../src/ActionDefinition/Action/Payload/ActionPayload_Progress.ts","../src/ActionDefinition/Action/Payload/ActionPayload_Result.ts","../src/ActionDefinition/Action/Payload/ActionPayload_Request.ts","../src/ActionDefinition/Action/Core/ActionCore.ts","../src/ActionDefinition/Action/RunningAction.ts","../src/errors/err_nice_action.ts","../src/utils/isAction_Base_JsonObject.ts","../src/utils/isActionPayload_Result_JsonObject.ts","../src/ActionDefinition/Schema/ActionSchema.ts","../src/utils/getAssumedRuntimeEnvironment.ts","../src/utils/isActionPayload_Progress_JsonObject.ts","../src/utils/isActionPayload_Request_JsonObject.ts","../src/utils/isActionPayload_Any_JsonObject.ts","../src/ActionRuntime/HandlerCallStack.ts","../src/ActionRuntime/Handler/PeerLink/Connector/err_nice_external_client.ts","../src/ActionRuntime/Transport/err_nice_transport.ts","../src/ActionRuntime/Transport/ConnectionTransportManager.ts","../src/ActionRuntime/ActionDomainManager.ts","../src/ActionRuntime/Routing/ActionRouter.ts","../src/ActionRuntime/Handler/ActionHandler.ts","../src/ActionRuntime/Handler/PeerLink/PeerLinkHandler.ts","../src/ActionRuntime/Handler/PeerLink/Connector/ConnectorHandler.ts","../src/ActionRuntime/ActionRuntime.ts","../src/ActionRuntime/Handler/Local/ActionLocalHandler.ts","../src/utils/isAction_Context_JsonObject.ts","../src/utils/isAction_Core_JsonObject.ts","../src/utils/isAction_Any_JsonObject.ts","../src/utils/assertIsActionJson.ts","../src/utils/isAction_Any_Instance.ts","../src/ActionDefinition/Domain/ActionDomainBase.ts","../src/ActionRuntime/ActionRuntimeManager.ts","../src/ActionDefinition/Domain/ActionRootDomain.ts","../src/ActionDefinition/Domain/ActionDomain.ts","../src/ActionDefinition/Domain/helpers/createRootActionDomain.ts","../src/ActionRuntime/Transport/crypto/actionHandshake.ts","../src/utils/decodeActionFrame.ts","../src/ActionRuntime/Transport/crypto/actionFrameCrypto.ts","../src/ActionRuntime/Transport/crypto/frameBytes.ts","../src/ActionRuntime/Transport/SecureSession/frameCryptoPipe.ts","../src/ActionRuntime/Transport/SecureSession/acceptorSecureSession.ts","../src/ActionRuntime/Handler/PeerLink/Acceptor/AcceptorHandler.ts","../src/ActionRuntime/Handler/PeerLink/Acceptor/createSecureActionServer.ts","../src/ActionRuntime/Channel/ActionChannel.ts","../src/ActionRuntime/Transport/codec/actionWireCodec.ts","../src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.ts","../src/ActionRuntime/Channel/secureChannel.ts","../src/ActionRuntime/Transport/SecureSession/exchangeProtocol.ts","../src/ActionRuntime/Transport/SecureSession/exchangeAcceptor.ts","../src/ActionRuntime/Handler/PeerLink/Acceptor/createActionFetchHandler.ts","../src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/ConnectionStateStore.ts","../src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/createHibernatableWsServerAdapter.ts","../src/ActionRuntime/Channel/serveChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/inMemory/createInMemoryChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/inMemory/inMemoryCarrier.ts","../src/ActionRuntime/Transport/Carrier/duplex/rtc/rtcDataChannelByteChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/rtc/rtcCarrier.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/err_nice_transport_ws.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/ws_util.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/webSocketByteChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/wsCarrier.ts","../src/ActionRuntime/Transport/Carrier/exchange/http/httpAcceptorCarrier.ts","../src/ActionRuntime/Transport/Carrier/exchange/http/httpCarrier.ts","../src/ActionRuntime/Transport/codec/createBinaryWireAdapter.ts","../src/ActionRuntime/Transport/Transport.ts","../src/ActionRuntime/Transport/SecureSession/establishExchangeSession.ts","../src/ActionRuntime/Transport/helpers/addTransportStatusMetadata.ts","../src/ActionRuntime/Transport/TransportConnection.ts","../src/ActionRuntime/Transport/Exchange/ExchangeConnection.ts","../src/ActionRuntime/Transport/Exchange/ExchangeTransport.ts","../src/ActionRuntime/Transport/helpers/createUnsetTransportResolvers.ts","../src/ActionRuntime/Transport/SecureSession/establishLinkSession.ts","../src/ActionRuntime/Transport/Link/LinkConnection.ts","../src/ActionRuntime/Transport/Link/LinkTransport.ts","../src/ActionRuntime/Transport/Carrier/Carrier.types.ts","../src/ActionRuntime/Transport/plainTransport.ts","../src/ActionRuntime/Transport/secureTransport.ts"],"sourcesContent":["export const DEFAULT_TRANSPORT_TIMEOUT = 10000; // 10 seconds\nexport const UNSET_RUNTIME_ENV_ID = \"_unset_\";\nexport const UNSET_RUNTIME_PER_ID = \"_0_0_\";\n","import type { IRuntimeCoordinate, TRuntimeCoordinateStringId } from \"../RuntimeCoordinate\";\n\nexport function runtimeCoordinateToStringIds(\n coordinate: IRuntimeCoordinate,\n): TRuntimeCoordinateStringId[] {\n return [\n `envId[${coordinate.envId}]perId[${coordinate.perId ?? \"_\"}]:insId[${coordinate.insId ?? \"_\"}]`,\n `envId[${coordinate.envId}]perId[${coordinate.perId ?? \"_\"}]:insId[_]`,\n `envId[${coordinate.envId}]perId[_]:insId[_]`,\n ];\n}\n","import { UNSET_RUNTIME_ENV_ID } from \"../nice_action.static\";\nimport { runtimeCoordinateToStringIds } from \"./utils/runtimeCoordinateToStringIds\";\n\nexport interface IRuntimeCoordinateSpecifics {\n /**\n * A unique and persistent client ID (should stay the same between runtime instance reloads)\n */\n perId?: string;\n /**\n * A unique instance (or \"memory-only\") ID (unique for each instance of an action runtime, which should generally\n * not persist between reloads, depending on the architecture)\n */\n insId?: string;\n}\n\nexport interface IRuntimeCoordinate extends IRuntimeCoordinateSpecifics {\n /**\n * A static runtime environment identifier (e.g. \"web_app_v1\", \"backend_analytics\")\n */\n envId: string;\n}\n\nexport type TRuntimeCoordinateEnvId = `envId[${string}]`;\n\nexport type TRuntimeCoordinateStringId =\n `${TRuntimeCoordinateEnvId}perId[${string | \"_\"}]:insId[${string | \"_\"}]`;\n\nexport interface IRuntimeFullCoordinates extends Required<IRuntimeCoordinate> {}\n\nexport class RuntimeCoordinate implements IRuntimeCoordinate {\n readonly envId: string;\n readonly perId?: string;\n readonly insId?: string;\n\n static get unknown(): RuntimeCoordinate {\n return new RuntimeCoordinate({\n envId: UNSET_RUNTIME_ENV_ID,\n });\n }\n\n static env(envId: string): RuntimeCoordinate {\n return new RuntimeCoordinate({\n envId: envId,\n });\n }\n\n withPersistentId(perId: string): RuntimeCoordinate {\n return this.specify({ perId });\n }\n\n constructor({ envId, perId, insId }: IRuntimeCoordinate) {\n this.envId = envId;\n this.perId = perId;\n this.insId = insId;\n }\n\n specify(specifics: IRuntimeCoordinateSpecifics): RuntimeCoordinate {\n return new RuntimeCoordinate({\n envId: this.envId,\n perId: this.perId,\n insId: this.insId,\n ...specifics,\n });\n }\n\n specifyIfUnset(specifics: IRuntimeCoordinateSpecifics): RuntimeCoordinate {\n return new RuntimeCoordinate({\n envId: this.envId,\n perId: this.perId ?? specifics.perId,\n insId: this.insId ?? specifics.insId,\n });\n }\n\n toJsonObject(): IRuntimeCoordinate {\n return {\n envId: this.envId,\n perId: this.perId,\n insId: this.insId,\n };\n }\n\n isExactlySame(other: IRuntimeCoordinate): boolean {\n return this.envId === other.envId && this.perId === other.perId && this.insId === other.insId;\n }\n\n isSameFor(other: IRuntimeCoordinate): { id: boolean; perId: boolean; insId: boolean } {\n return {\n id: this.envId === other.envId,\n perId: this.envId === other.envId && this.perId === other.perId,\n insId: this.envId === other.envId && this.perId === other.perId && this.insId === other.insId,\n };\n }\n\n similarityLevel(other: IRuntimeCoordinate): number {\n const sameFor = this.isSameFor(other);\n if (sameFor.insId) return 3;\n if (sameFor.perId) return 2;\n if (sameFor.id) return 1;\n return 0;\n }\n\n get stringId(): TRuntimeCoordinateStringId {\n return `envId[${this.envId}]perId[${this.perId ?? \"_\"}]:insId[${this.insId ?? \"_\"}]`;\n }\n\n /**\n * Takes the \"Runtime Coordinate\" and generates a list of full coordinate IDs representing the runtime\n * with decreasing levels of specificity.\n *\n * The first full coordinate ID is the most specific (including instance ID), while the last ID is\n * the least specific (only environment ID).\n *\n * Example output for a RuntimeCoordinate with envId \"web_app\", perId \"user123\", and insId \"instance456\":\n * [\n * \"envId[web_app]perId[user123]:insId[instance456]\",\n * \"envId[web_app]perId[user123]:insId[_]\",\n * \"envId[web_app]perId[_]:insId[_]\"\n * ]\n *\n * @returns a list of \"full\" runtime coordinate IDs with decreasing accuracy for targeting a runtime.\n */\n toStringIds(): TRuntimeCoordinateStringId[] {\n return runtimeCoordinateToStringIds(this);\n }\n}\n","import type { ActionDomain } from \"../Domain/ActionDomain\";\nimport type { IActionDomain } from \"../Domain/ActionDomain.types\";\nimport type { EActionForm, IActionBase, IActionBase_JsonObject } from \"./ActionBase.types\";\n\nexport abstract class ActionBase<\n FORM extends EActionForm,\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n> implements IActionBase<FORM, DOM, ID>\n{\n readonly domain: DOM[\"domain\"];\n readonly allDomains: DOM[\"allDomains\"];\n readonly schema: DOM[\"actionSchema\"][ID];\n\n constructor(\n readonly form: FORM,\n readonly _domain: ActionDomain<DOM>,\n readonly id: ID,\n ) {\n this.domain = _domain.domain;\n this.allDomains = _domain.allDomains;\n this.schema = _domain.actionSchema[id];\n }\n\n protected toJsonObject(): IActionBase_JsonObject<FORM, DOM, ID> {\n return {\n form: this.form,\n domain: this.domain,\n allDomains: this.allDomains,\n id: this.id,\n };\n }\n\n protected toJsonString(): string {\n return JSON.stringify(this.toJsonObject());\n }\n}\n","import { RuntimeCoordinate } from \"../../../ActionRuntime/RuntimeCoordinate\";\nimport type { ActionDomain } from \"../../Domain/ActionDomain\";\nimport type {\n IActionDomain,\n TInferInputFromSchema,\n TInferOutputFromSchema,\n} from \"../../Domain/ActionDomain.types\";\nimport { ActionBase } from \"../ActionBase\";\nimport { EActionForm } from \"../ActionBase.types\";\nimport type {\n IActionContext,\n IActionContext_Data,\n IActionContext_Data_JsonObject,\n IActionContext_JsonObject,\n IActionRouteItem,\n} from \"./ActionContext.types\";\n\nexport class ActionContext<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n >\n extends ActionBase<EActionForm.context, DOM, ID>\n implements IActionContext<DOM, ID>\n{\n readonly form = EActionForm.context;\n readonly _routing: IActionRouteItem[];\n readonly timeCreated: number;\n readonly cuid: string;\n originClient: RuntimeCoordinate;\n\n constructor(\n readonly _domain: ActionDomain<DOM>,\n id: ID,\n hydrationData: IActionContext_Data,\n ) {\n super(EActionForm.context, _domain, id);\n this.timeCreated = hydrationData.timeCreated;\n this.cuid = hydrationData.cuid;\n this._routing = hydrationData.routing;\n this.originClient = hydrationData.originClient;\n }\n\n _setOriginClient(client: RuntimeCoordinate): void {\n this.originClient = client;\n }\n\n toJsonString(): string {\n return JSON.stringify(this.toJsonObject());\n }\n\n toContextDataJsonObject(): IActionContext_Data_JsonObject {\n return {\n timeCreated: this.timeCreated,\n cuid: this.cuid,\n routing: this.routing.map((item) => ({\n runtime: item.runtime.toJsonObject(),\n handler: item.handler,\n time: item.time,\n })),\n originClient: this.originClient.toJsonObject(),\n };\n }\n\n toJsonObject(): IActionContext_JsonObject<DOM, ID> {\n return {\n ...super.toJsonObject(),\n ...this.toContextDataJsonObject(),\n };\n }\n\n get routing(): IActionRouteItem[] {\n return this._routing;\n }\n\n addRouteItem(item: IActionRouteItem): void {\n this._routing.push(item);\n }\n\n deserializeInput(\n serialized: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.deserializeInput(serialized);\n }\n\n serializeInput(\n raw: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"] {\n return this.schema.serializeInput(raw);\n }\n\n validateInput(input: unknown): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.validateInput(input, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n\n validateOutput(output: unknown): TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"] {\n return this.schema.validateOutput(output, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n}\n","import type { IActionDomain } from \"../../Domain/ActionDomain.types\";\nimport { ActionBase } from \"../ActionBase\";\nimport { EActionForm } from \"../ActionBase.types\";\nimport type { ActionContext } from \"../Context/ActionContext\";\nimport type {\n EActionPayloadType,\n IActionPayload_Base,\n IActionPayload_Base_JsonObject,\n IActionPayload_Data_Base,\n} from \"./ActionPayload.types\";\n\nexport abstract class ActionPayload<\n DT extends EActionPayloadType,\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n >\n extends ActionBase<EActionForm.data, DOM, ID>\n implements IActionPayload_Base<DT, DOM, ID>\n{\n readonly form: EActionForm.data = EActionForm.data;\n readonly type: DT;\n readonly context: ActionContext<DOM, ID>;\n readonly time: number;\n\n protected constructor(context: ActionContext<DOM, ID>, type: DT, data: IActionPayload_Data_Base) {\n super(EActionForm.data, context._domain, context.id);\n this.context = context;\n this.type = type;\n this.time = data.time;\n }\n\n protected toBaseJsonObject(): IActionPayload_Base_JsonObject<DT, DOM, ID> {\n return {\n ...super.toJsonObject(),\n type: this.type,\n context: this.context.toContextDataJsonObject(),\n time: this.time,\n };\n }\n\n abstract toJsonObject(): IActionPayload_Base_JsonObject<DT, DOM, ID>;\n}\n","function stableStringify(value: unknown): string {\n if (value === null || value === undefined) return String(value);\n if (typeof value !== \"object\") return JSON.stringify(value) ?? \"undefined\";\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n const keys = Object.keys(value as object).sort();\n return (\n \"{\" +\n keys\n .map((k) => `${JSON.stringify(k)}:${stableStringify((value as Record<string, unknown>)[k])}`)\n .join(\",\") +\n \"}\"\n );\n}\n\nfunction fnv1a32(str: string): string {\n let hash = 2166136261;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash ^ str.charCodeAt(i)) * 16777619) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n\n/**\n * Produces a deterministic 8-char hex hash of any JSON-serializable value.\n * Useful for grouping/comparing action inputs, outputs, and progress payloads.\n */\nexport function hashPayloadData(data: unknown): string {\n return fnv1a32(stableStringify(data));\n}\n","import type { TInferActionError } from \"../../..\";\r\nimport type {\r\n IActionHandler_Local_Json,\r\n IActionHandler_Peer_Json,\r\n} from \"../../../ActionRuntime/Handler/ActionHandler.types\";\r\nimport type {\r\n ETransportShape,\r\n ITransportRouteInfo,\r\n} from \"../../../ActionRuntime/Transport/Transport.types\";\r\nimport type {\r\n IActionDomain,\r\n TInferInputFromSchema,\r\n TInferOutputFromSchema,\r\n} from \"../../Domain/ActionDomain.types\";\r\nimport type { EActionForm, IActionBase, IActionBase_JsonObject } from \"../ActionBase.types\";\r\nimport type { ActionContext } from \"../Context/ActionContext\";\r\nimport type { IActionContext_Data_JsonObject } from \"../Context/ActionContext.types\";\r\nimport type { ActionPayload_Progress } from \"./ActionPayload_Progress\";\r\nimport type { ActionPayload_Request } from \"./ActionPayload_Request\";\r\nimport type { ActionPayload_Result } from \"./ActionPayload_Result\";\r\n\r\nexport enum EActionPayloadType {\r\n request = \"request\",\r\n progress = \"progress\",\r\n result = \"result\",\r\n stream = \"stream\",\r\n push = \"push\",\r\n}\r\n\r\nexport interface IActionPayload_Data_Base {\r\n time: number;\r\n}\r\n\r\nexport interface IActionPayload_Base<\r\n DT extends EActionPayloadType,\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionBase<EActionForm.data, DOM, ID>,\r\n IActionPayload_Data_Base {\r\n readonly type: DT;\r\n readonly context: ActionContext<DOM, ID>;\r\n}\r\n\r\nexport type IActionRouteItemHandler =\r\n | IActionHandler_Local_Json\r\n | (IActionHandler_Peer_Json & {\r\n transShape: ETransportShape;\r\n transOrd: number;\r\n transInfo?: ITransportRouteInfo;\r\n });\r\n\r\n/**\r\n * [ ]\r\n * [ ACTION PAYLOAD TYPES ]\r\n * [ ]\r\n */\r\n\r\n/**\r\n *\r\n * [ RESULT ]\r\n *\r\n */\r\n\r\nexport type TActionResultOutcome<OUT, ERR> = { ok: true; output: OUT } | { ok: false; error: ERR };\r\n\r\nexport interface IActionPayload_Result<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionPayload_Base<EActionPayloadType.result, DOM, ID> {\r\n readonly result: TActionResultOutcome<\r\n TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"],\r\n TInferActionError<DOM[\"actionSchema\"][ID]>\r\n >;\r\n}\r\n\r\n/**\r\n *\r\n * [ PROGRESS ]\r\n *\r\n */\r\n\r\nexport enum EActionProgressType {\r\n none = \"none\",\r\n percentage = \"percentage\",\r\n custom = \"custom\",\r\n}\r\n\r\nexport interface IActionProgress_None {\r\n type: EActionProgressType.none;\r\n}\r\n\r\nexport interface IActionProgress_Percentage {\r\n type: EActionProgressType.percentage;\r\n progress: number; // value between 0 and 100\r\n message?: string; // optional message describing the progress\r\n}\r\n\r\nexport interface IActionProgress_Custom {\r\n type: EActionProgressType.custom;\r\n data: any; // custom data for the progress\r\n}\r\n\r\nexport type TActionProgress =\r\n | IActionProgress_None\r\n | IActionProgress_Percentage\r\n | IActionProgress_Custom;\r\n\r\nexport interface IActionPayload_Progress<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionPayload_Base<EActionPayloadType.progress, DOM, ID> {\r\n readonly progress: TActionProgress;\r\n}\r\n\r\n/**\r\n *\r\n * [ ]\r\n * [ Wire JSON types ]\r\n * [ ]\r\n *\r\n */\r\n\r\nexport interface IActionPayload_Base_JsonObject<\r\n DT extends EActionPayloadType,\r\n DOM extends IActionDomain = IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionBase_JsonObject<EActionForm.data, DOM, ID> {\r\n type: DT;\r\n context: IActionContext_Data_JsonObject;\r\n time: number;\r\n}\r\n\r\nexport interface IActionPayload_Request_JsonObject<\r\n DOM extends IActionDomain = IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionPayload_Base_JsonObject<EActionPayloadType.request, DOM, ID> {\r\n type: EActionPayloadType.request;\r\n input: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"];\r\n inputHash: string;\r\n}\r\n\r\nexport interface IActionPayload_Progress_JsonObject<\r\n DOM extends IActionDomain = IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionPayload_Base_JsonObject<EActionPayloadType.progress, DOM, ID> {\r\n type: EActionPayloadType.progress;\r\n progress: TActionProgress;\r\n}\r\n\r\nexport interface IActionPayload_Result_JsonObject<\r\n DOM extends IActionDomain = IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> extends IActionPayload_Base_JsonObject<EActionPayloadType.result, DOM, ID> {\r\n type: EActionPayloadType.result;\r\n result: TActionResultOutcome<\r\n TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeOutput\"],\r\n TInferActionError<DOM[\"actionSchema\"][ID]>\r\n >;\r\n outputHash: string;\r\n}\r\n\r\n/**\r\n *\r\n * [ ]\r\n * [ COMBINED TYPES ]\r\n * [ ]\r\n *\r\n */\r\n\r\nexport type TActionPayload_Any_Instance<\r\n DOM extends IActionDomain = IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> =\r\n | ActionPayload_Request<DOM, ID>\r\n | ActionPayload_Result<DOM, ID>\r\n | ActionPayload_Progress<DOM, ID>;\r\n\r\nexport type TActionPayload_Any_JsonObject<\r\n DOM extends IActionDomain = IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> =\r\n | IActionPayload_Request_JsonObject<DOM, ID>\r\n | IActionPayload_Progress_JsonObject<DOM, ID>\r\n | IActionPayload_Result_JsonObject<DOM, ID>;\r\n","import type { IActionDomain } from \"../../Domain/ActionDomain.types\";\nimport type { ActionContext } from \"../Context/ActionContext\";\nimport { ActionPayload } from \"./ActionPayload\";\nimport type {\n IActionPayload_Data_Base,\n IActionPayload_Progress,\n IActionPayload_Progress_JsonObject,\n TActionProgress,\n} from \"./ActionPayload.types\";\nimport { EActionPayloadType } from \"./ActionPayload.types\";\nimport { ActionPayload_Request } from \"./ActionPayload_Request\";\n\nexport class ActionPayload_Progress<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n >\n extends ActionPayload<EActionPayloadType.progress, DOM, ID>\n implements IActionPayload_Progress<DOM, ID>\n{\n readonly progress: TActionProgress;\n\n constructor(\n params: { context: ActionContext<DOM, ID> } | ActionPayload_Request<DOM, ID>,\n progress: TActionProgress,\n data: IActionPayload_Data_Base,\n ) {\n super(params.context, EActionPayloadType.progress, data);\n this.progress = progress;\n }\n\n toJsonObject(): IActionPayload_Progress_JsonObject<DOM, ID> {\n return {\n ...this.toBaseJsonObject(),\n progress: this.progress,\n };\n }\n\n toJsonString(): string {\n return JSON.stringify(this.toJsonObject());\n }\n\n toHttpResponse(): Response {\n return new Response(this.toJsonString(), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n}\n","import { hashPayloadData } from \"../../../utils/hashPayloadData\";\nimport type { IActionDomain, TInferOutputFromSchema } from \"../../Domain/ActionDomain.types\";\nimport type { TInferActionError } from \"../../Schema/ActionSchema\";\nimport type { ActionContext } from \"../Context/ActionContext\";\nimport { ActionPayload } from \"./ActionPayload\";\nimport type { IActionPayload_Data_Base, TActionResultOutcome } from \"./ActionPayload.types\";\nimport { EActionPayloadType, type IActionPayload_Result_JsonObject } from \"./ActionPayload.types\";\nimport { ActionPayload_Request } from \"./ActionPayload_Request\";\n\nexport class ActionPayload_Result<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n> extends ActionPayload<EActionPayloadType.result, DOM, ID> {\n readonly result: TActionResultOutcome<\n TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"],\n TInferActionError<DOM[\"actionSchema\"][ID]>\n >;\n readonly outputHash: string;\n\n constructor(\n params: { context: ActionContext<DOM, ID> } | ActionPayload_Request<DOM, ID>,\n result: TActionResultOutcome<\n TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"],\n TInferActionError<DOM[\"actionSchema\"][ID]>\n >,\n data: IActionPayload_Data_Base,\n ) {\n super(params.context, EActionPayloadType.result, data);\n this.result = result;\n this.outputHash = result.ok\n ? hashPayloadData(this.context.schema.serializeOutput(result.output))\n : hashPayloadData(result.error.message);\n }\n\n toJsonObject(): IActionPayload_Result_JsonObject<DOM, ID> {\n const wireResult = this.result.ok\n ? { ok: true as const, output: this.context.schema.serializeOutput(this.result.output) }\n : this.result;\n return {\n ...this.toBaseJsonObject(),\n result: wireResult,\n outputHash: this.outputHash,\n };\n }\n\n toJsonString(): string {\n return JSON.stringify(this.toJsonObject());\n }\n\n toHttpResponse({ useErrorStatus = true }: { useErrorStatus?: boolean } = {}): Response {\n return new Response(this.toJsonString(), {\n status: this.result.ok ? 200 : useErrorStatus ? this.result.error.httpStatusCode : 500,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n}\n","import type { IExecuteActionOptions } from \"../../../ActionRuntime/Handler/ActionHandler.types\";\r\nimport { hashPayloadData } from \"../../../utils/hashPayloadData\";\r\nimport type {\r\n IActionDomain,\r\n TInferInputFromSchema,\r\n TInferOutputFromSchema,\r\n} from \"../../Domain/ActionDomain.types\";\r\nimport type { TInferActionError } from \"../../Schema/ActionSchema\";\r\nimport type { ActionContext } from \"../Context/ActionContext\";\r\nimport type { RunningAction } from \"../RunningAction\";\r\nimport { ActionPayload } from \"./ActionPayload\";\r\nimport type { IActionPayload_Data_Base, TActionProgress } from \"./ActionPayload.types\";\r\nimport { EActionPayloadType, type IActionPayload_Request_JsonObject } from \"./ActionPayload.types\";\r\nimport { ActionPayload_Progress } from \"./ActionPayload_Progress\";\r\nimport { ActionPayload_Result } from \"./ActionPayload_Result\";\r\n\r\nexport class ActionPayload_Request<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\r\n> extends ActionPayload<EActionPayloadType.request, DOM, ID> {\r\n readonly input: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"];\r\n readonly inputHash: string;\r\n _callSite?: string;\r\n\r\n constructor(\r\n params: { context: ActionContext<DOM, ID> },\r\n input: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"],\r\n data: IActionPayload_Data_Base,\r\n ) {\r\n super(params.context, EActionPayloadType.request, data);\r\n this.input = input;\r\n this.inputHash = hashPayloadData(this.context.schema.serializeInput(input));\r\n }\r\n\r\n successResult(\r\n ...args: [TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"]] extends [never]\r\n ? [] | [output: TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"]]\r\n : [output: TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"]]\r\n ): ActionPayload_Result<DOM, ID> {\r\n const output = args[0];\r\n const finalOutput = this.context.schema.validateOutput(output, {\r\n domain: this.domain,\r\n actionId: this.id,\r\n });\r\n return new ActionPayload_Result(this, { ok: true, output: finalOutput }, { time: Date.now() });\r\n }\r\n\r\n errorResult(err: TInferActionError<DOM[\"actionSchema\"][ID]>): ActionPayload_Result<DOM, ID> {\r\n return new ActionPayload_Result(this, { ok: false, error: err }, { time: Date.now() });\r\n }\r\n\r\n progress(progress: TActionProgress): ActionPayload_Progress<DOM, ID> {\r\n return new ActionPayload_Progress(this, progress, { time: Date.now() });\r\n }\r\n\r\n toJsonObject(): IActionPayload_Request_JsonObject<DOM, ID> {\r\n return {\r\n ...super.toBaseJsonObject(),\r\n input: this.context.schema.serializeInput(this.input),\r\n inputHash: this.inputHash,\r\n };\r\n }\r\n\r\n toJsonString(): string {\r\n return JSON.stringify(this.toJsonObject());\r\n }\r\n\r\n async runToOutput(\r\n options?: IExecuteActionOptions<DOM, ID>,\r\n ): Promise<TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"]> {\r\n const running = await this.run(options);\r\n const result = await running.waitForResultPayload();\r\n if (result.result.ok) return result.result.output;\r\n throw result.result.error;\r\n }\r\n\r\n async runToResultPayload(\r\n options?: IExecuteActionOptions<DOM, ID>,\r\n ): Promise<ActionPayload_Result<DOM, ID>> {\r\n const value = await this.run(options);\r\n return value.waitForResultPayload();\r\n }\r\n\r\n async run(options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>> {\r\n if (this._callSite == null) {\r\n this._callSite = new Error().stack;\r\n }\r\n return this._domain.runAction(this, options);\r\n }\r\n}\r\n","import { nanoid } from \"nanoid\";\nimport { RuntimeCoordinate } from \"../../../ActionRuntime/RuntimeCoordinate\";\nimport type { ActionDomain } from \"../../Domain/ActionDomain\";\nimport type {\n IActionDomain,\n TInferInputFromSchema,\n TInferOutputFromSchema,\n} from \"../../Domain/ActionDomain.types\";\nimport type { TNarrowActionType } from \"../Action.combined.types\";\nimport { ActionBase } from \"../ActionBase\";\nimport { EActionForm, type IActionBase, type IActionBase_JsonObject } from \"../ActionBase.types\";\nimport { ActionContext } from \"../Context/ActionContext\";\nimport { ActionPayload } from \"../Payload/ActionPayload\";\nimport { ActionPayload_Request } from \"../Payload/ActionPayload_Request\";\nimport type { IActionCore } from \"./ActionCore.types\";\n\nexport class ActionCore<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n >\n extends ActionBase<EActionForm.core, DOM, ID>\n implements IActionCore<DOM, ID>\n{\n readonly form = EActionForm.core;\n\n constructor(\n readonly _domain: ActionDomain<DOM>,\n id: ID,\n ) {\n super(EActionForm.core, _domain, id);\n }\n\n is<ACT extends IActionBase<any, any, any>>(\n action: ACT | unknown | null | undefined,\n ): action is TNarrowActionType<DOM, ACT, ID> {\n return (\n action instanceof ActionPayload && action.domain === this.domain && action.id === this.id\n );\n }\n\n toJsonObject(): IActionBase_JsonObject<EActionForm.core, DOM, ID> {\n return {\n id: this.id,\n form: this.form,\n domain: this.domain,\n allDomains: this.allDomains,\n };\n }\n\n request(\n ...args: [TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"]] extends [never]\n ? [input?: never]\n : [input: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"]]\n ): ActionPayload_Request<DOM, ID> {\n const input: unknown = args[0];\n const validatedInput = this.schema.validateInput(input, {\n actionId: this.id,\n domain: this.domain,\n });\n\n const context = new ActionContext(this._domain, this.id, {\n cuid: nanoid(),\n timeCreated: Date.now(),\n routing: [],\n originClient: RuntimeCoordinate.unknown,\n });\n\n return new ActionPayload_Request({ context }, validatedInput, {\n time: Date.now(),\n });\n }\n\n // async run(\n // input: TInferInputFromSchema<DOM[\"actions\"][ID]>[\"Input\"],\n // options?: IExecuteActionOptions<DOM, ID>,\n // ): Promise<RunningAction<DOM, ID>> {\n // return this.request(input).run(options);\n // }\n\n // async runToOutput(\n // input: TInferInputFromSchema<DOM[\"actions\"][ID]>[\"Input\"],\n // options?: IExecuteActionOptions<DOM, ID>,\n // ): Promise<TInferOutputFromSchema<DOM[\"actions\"][ID]>[\"Output\"]> {\n // return this.request(input).runToOutput(options);\n // }\n\n // async runToOutputSafe(\n // input: TInferInputFromSchema<DOM[\"actions\"][ID]>[\"Input\"],\n // options?: IExecuteActionOptions<DOM, ID>,\n // ): Promise<\n // TActionResult<\n // TInferOutputFromSchema<DOM[\"actions\"][ID]>[\"Output\"],\n // TInferActionError<DOM[\"actions\"][ID]>\n // >\n // > {\n // return this.request(input).runToOutputSafe(options);\n // }\n\n deserializeInput(\n serialized: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.deserializeInput(serialized);\n }\n\n serializeInput(\n raw: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"] {\n return this.schema.serializeInput(raw);\n }\n\n validateInput(input: unknown): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.validateInput(input, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n\n validateOutput(output: unknown): TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"] {\n return this.schema.validateOutput(output, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n}\n","import type { ActionDomain } from \"../..\";\nimport type { IActionDomain } from \"../Domain/ActionDomain.types\";\nimport type { ActionContext } from \"./Context/ActionContext\";\nimport { type IActionPayload_Result_JsonObject } from \"./Payload/ActionPayload.types\";\nimport type { ActionPayload_Progress } from \"./Payload/ActionPayload_Progress\";\nimport type { ActionPayload_Result } from \"./Payload/ActionPayload_Result\";\nimport {\n ERunningActionFinishedType,\n ERunningActionUpdateType,\n type IRunningActionState,\n type IRunningActionState_ConstructorParams,\n type IRunningActionUserMethods,\n type TRunningActionUpdate,\n type TRunningActionUpdateListener,\n} from \"./RunningAction.types\";\n\nexport class RunningAction<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n> implements IRunningActionUserMethods<DOM, ID>\n{\n protected _state: IRunningActionState<DOM, ID>;\n\n readonly context: ActionContext<DOM, ID>;\n readonly cuid: string;\n readonly id: ID;\n readonly _domain: ActionDomain<DOM>;\n readonly domain: DOM[\"domain\"];\n readonly allDomains: DOM[\"allDomains\"];\n readonly parentCuid?: string;\n readonly callSite?: string;\n\n private readonly _resultPayloadPromise: Promise<ActionPayload_Result<DOM, ID>>;\n private _resolveResult!: (response: ActionPayload_Result<DOM, ID>) => void;\n private _rejectResult!: (reason?: unknown) => void;\n\n private _isAborted = false;\n\n private readonly _updates: TRunningActionUpdate<DOM, ID>[] = [];\n\n private readonly _updateListeners: TRunningActionUpdateListener<DOM, ID>[] = [];\n\n constructor(initialState: IRunningActionState_ConstructorParams<DOM, ID>) {\n this.context = initialState.context;\n this.cuid = initialState.context.cuid;\n this.id = initialState.context.id;\n this.domain = initialState.context.domain;\n this.allDomains = initialState.context.allDomains;\n this._domain = initialState.context._domain;\n this.parentCuid = initialState.parentCuid;\n this.callSite = initialState.callSite;\n\n this._resultPayloadPromise = new Promise<ActionPayload_Result<DOM, ID>>((resolve, reject) => {\n this._resolveResult = resolve;\n this._rejectResult = reject;\n });\n // Prevent unhandled rejection when this RunningAction is aborted/failed but\n // waitForResultPayload() is never called (e.g. error-path in _runAction).\n this._resultPayloadPromise.catch(() => {});\n\n this._state = {\n request: initialState.request,\n progress: initialState.progress ?? [],\n result: initialState.result,\n };\n\n this._sendUpdate({\n type: ERunningActionUpdateType.started,\n runningAction: this,\n time: Date.now(),\n });\n }\n\n get state(): IRunningActionState<DOM, ID> {\n return this._state;\n }\n\n abort(reason?: unknown): void {\n this._abort(reason);\n }\n\n addUpdateListeners(listeners: TRunningActionUpdateListener<DOM, ID>[]): () => void {\n this._updateListeners.push(...listeners);\n // Emit all past events to the new listeners\n for (const event of this._updates) {\n for (const listener of listeners) {\n listener(event);\n }\n }\n return () => {\n for (const listener of listeners) {\n const i = this._updateListeners.indexOf(listener);\n if (i !== -1) this._updateListeners.splice(i, 1);\n }\n };\n }\n\n async *iterateUpdates(): AsyncIterable<TRunningActionUpdate<DOM, ID>> {\n const queue: TRunningActionUpdate<DOM, ID>[] = [];\n let resolveWaiter: (() => void) | null = null;\n\n const unsubscribe = this.addUpdateListeners([\n (event) => {\n queue.push(event);\n // Wake up the while-loop if it's currently paused waiting for an event\n if (resolveWaiter) {\n resolveWaiter();\n resolveWaiter = null;\n }\n },\n ]);\n\n try {\n while (true) {\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n resolveWaiter = resolve;\n });\n }\n\n const event = queue.shift()!;\n yield event;\n\n // Safely terminate the generator when the action concludes\n if (event.type === ERunningActionUpdateType.finished) {\n break;\n }\n }\n } finally {\n unsubscribe();\n }\n }\n\n _sendUpdate(update: TRunningActionUpdate<DOM, ID>): void {\n this._updates.push(update);\n for (const listener of this._updateListeners) listener(update);\n }\n\n _completeWithResult(result: ActionPayload_Result<DOM, ID>): boolean {\n if (this._state.result != null || this._isAborted) return false;\n\n this._state = {\n request: this._state.request,\n progress: this._state.progress,\n result: result,\n };\n\n this._resolveResult(result);\n this._sendUpdate({\n type: ERunningActionUpdateType.finished,\n finishType: ERunningActionFinishedType.success,\n runningAction: this,\n time: Date.now(),\n response: result,\n });\n\n return true;\n }\n\n _abort(reason?: unknown): boolean {\n if (this._state.result != null || this._isAborted) return false;\n this._isAborted = true;\n this._rejectResult(reason);\n\n this._sendUpdate({\n type: ERunningActionUpdateType.finished,\n finishType: ERunningActionFinishedType.aborted,\n runningAction: this,\n time: Date.now(),\n reason,\n });\n\n return true;\n }\n\n _failWithError(error: unknown): boolean {\n if (this._state.result != null || this._isAborted) return false;\n this._isAborted = true;\n this._rejectResult(error);\n\n this._sendUpdate({\n type: ERunningActionUpdateType.finished,\n finishType: ERunningActionFinishedType.failed,\n runningAction: this,\n time: Date.now(),\n error,\n } as any);\n\n return true;\n }\n\n _updateProgress(progress: ActionPayload_Progress<DOM, ID>): void {\n if (this._state.result != null || this._isAborted) return;\n this._state.progress.push(progress);\n\n this._sendUpdate({\n type: ERunningActionUpdateType.progress,\n runningAction: this,\n time: Date.now(),\n progress: progress.progress,\n });\n }\n\n waitForResultPayload(): Promise<ActionPayload_Result<DOM, ID>> {\n return this._resultPayloadPromise;\n }\n\n _resolveFromJson(resultJson: IActionPayload_Result_JsonObject<DOM, ID>): boolean {\n if (this._state.result != null || this._isAborted) return false;\n const result = this._domain.hydrateResultPayload(resultJson);\n return this._completeWithResult(result as unknown as ActionPayload_Result<DOM, ID>);\n }\n}\n","import { err, err_nice } from \"@nice-code/error\";\r\nimport { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\r\nimport { EActionPayloadType } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { IActionRuntimeManagerContext } from \"../ActionRuntime/ActionRuntime.types\";\r\nimport type {\r\n RuntimeCoordinate,\r\n TRuntimeCoordinateStringId,\r\n} from \"../ActionRuntime/RuntimeCoordinate\";\r\n\r\nexport enum EErrId_NiceAction {\r\n not_implemented = \"not_implemented\",\r\n action_id_not_in_domain = \"action_id_not_in_domain\",\r\n domain_already_exists_in_hierarchy = \"domain_already_exists_in_hierarchy\",\r\n domain_no_handler = \"domain_no_handler\",\r\n hydration_domain_mismatch = \"hydration_domain_mismatch\",\r\n hydration_action_state_mismatch = \"hydration_action_state_mismatch\",\r\n hydration_action_id_not_found = \"hydration_action_id_not_found\",\r\n no_action_execution_handler = \"no_action_execution_handler\",\r\n wire_action_not_payload = \"wire_action_not_payload\",\r\n wire_not_action_data = \"wire_not_action_data\",\r\n client_runtime_already_registered = \"client_runtime_already_registered\",\r\n client_runtime_not_registered = \"client_runtime_not_registered\",\r\n runtime_reset = \"runtime_reset\",\r\n no_client_runtimes_registered = \"no_client_runtimes_registered\",\r\n action_input_validation_failed = \"action_input_validation_failed\",\r\n action_input_validation_promise = \"action_input_validation_promise\",\r\n action_output_validation_failed = \"action_output_validation_failed\",\r\n action_output_validation_promise = \"action_output_validation_promise\",\r\n}\r\n\r\nexport const err_nice_action = err_nice.createChildDomain({\r\n domain: \"err_nice_action\",\r\n defaultHttpStatusCode: 500,\r\n schema: {\r\n [EErrId_NiceAction.not_implemented]: err<{ label: string }>({\r\n message: ({ label }) => `The \"${label}\" functionality is not implemented yet.`,\r\n }),\r\n [EErrId_NiceAction.action_id_not_in_domain]: err<{ domain: string; actionId: string }>({\r\n message: ({ actionId, domain }) =>\r\n `Action with id \"${actionId}\" does not exist in domain \"${domain}\".`,\r\n }),\r\n [EErrId_NiceAction.domain_already_exists_in_hierarchy]: err<{\r\n domain: string;\r\n allParentDomains: string[];\r\n parentDomain: string;\r\n }>({\r\n message: ({ domain, allParentDomains, parentDomain }) =>\r\n `Domain \"${domain}\" already exists in the hierarchy under the parent \"${parentDomain}\". All parent domains [\"${allParentDomains.join(\", \")}\"]`,\r\n }),\r\n [EErrId_NiceAction.domain_no_handler]: err<{ domain: string }>({\r\n message: ({ domain }) => `Domain \"${domain}\" has no action handler registered.`,\r\n }),\r\n [EErrId_NiceAction.hydration_domain_mismatch]: err<{\r\n expected: string;\r\n received: string;\r\n }>({\r\n message: ({ expected, received }) =>\r\n `Cannot hydrate action: domain mismatch. Expected \"${expected}\", got \"${received}\".`,\r\n }),\r\n [EErrId_NiceAction.hydration_action_state_mismatch]: err<{\r\n expected: string;\r\n received: string;\r\n }>({\r\n message: ({ expected, received }) =>\r\n `Cannot hydrate action: action state type mismatch. Expected \"${expected}\", got \"${received}\".`,\r\n }),\r\n [EErrId_NiceAction.hydration_action_id_not_found]: err<{\r\n domain: string;\r\n actionId: string;\r\n }>({\r\n message: ({ domain, actionId }) =>\r\n `Cannot hydrate action: id \"${actionId}\" does not exist in domain \"${domain}\".`,\r\n }),\r\n [EErrId_NiceAction.no_action_execution_handler]: err<{\r\n domain: string;\r\n actionId: string;\r\n specifiedClient?: RuntimeCoordinate;\r\n }>({\r\n message: ({ domain, actionId, specifiedClient }) =>\r\n `${specifiedClient ? ` The targeted client runtime [${specifiedClient.stringId}] has no` : \"No\"} action handler registered for \"${actionId}\" in domain \"${domain}\".`,\r\n }),\r\n [EErrId_NiceAction.wire_action_not_payload]: err<{\r\n domain: string;\r\n actionId: string;\r\n actionState: string | undefined;\r\n }>({\r\n message: ({ domain, actionId, actionState }) =>\r\n `Cannot handle wire for action \"${actionId}\" in domain \"${domain}\": expected action form of \"${EActionForm.data}\" and type of \"${EActionPayloadType.request}\", \"${EActionPayloadType.progress}\" or \"${EActionPayloadType.result}\", got \"${actionState}\".`,\r\n }),\r\n [EErrId_NiceAction.wire_not_action_data]: err({\r\n message: () =>\r\n `Cannot handle wire for action: expected an object with a \"domain\" property of type string, a \"form\" property of \"${EActionForm.data}\" and a \"type\" property of \"${EActionPayloadType.request}\", \"${EActionPayloadType.progress}\" or \"${EActionPayloadType.result}\".`,\r\n }),\r\n [EErrId_NiceAction.runtime_reset]: err({\r\n message: () => `Runtime has been reset.`,\r\n }),\r\n [EErrId_NiceAction.client_runtime_already_registered]: err<{\r\n context?: IActionRuntimeManagerContext;\r\n client: RuntimeCoordinate;\r\n }>({\r\n message: ({ context, client }) =>\r\n `Environment is already registered${context?.domain ? ` on domain \"${context.domain}\"` : \"\"} for client [${client.stringId}]. Each client specifier (exact match on all properties) may only be registered once.`,\r\n }),\r\n [EErrId_NiceAction.client_runtime_not_registered]: err<{\r\n context?: IActionRuntimeManagerContext;\r\n clientStringId: TRuntimeCoordinateStringId;\r\n }>({\r\n message: ({ context, clientStringId }) =>\r\n `No runtime registered${context?.domain ? ` on domain \"${context.domain}\"` : \"\"} for client [${clientStringId}].`,\r\n }),\r\n [EErrId_NiceAction.no_client_runtimes_registered]: err<{\r\n context?: IActionRuntimeManagerContext;\r\n }>({\r\n message: ({ context }) =>\r\n `No runtimes registered${context?.domain ? ` on domain \"${context.domain}\"` : \"\"}. Add handlers to a runtime via runtime.addHandlers([handler]) before executing actions.`,\r\n }),\r\n [EErrId_NiceAction.action_input_validation_failed]: err<{\r\n domain: string;\r\n actionId: string;\r\n validationMessage: string;\r\n }>({\r\n message: ({ domain, actionId, validationMessage }) =>\r\n `Input validation failed for action \"${actionId}\" in domain \"${domain}\":\\n${validationMessage}`,\r\n httpStatusCode: 400,\r\n }),\r\n [EErrId_NiceAction.action_input_validation_promise]: err<{\r\n domain: string;\r\n actionId: string;\r\n }>({\r\n message: ({ domain, actionId }) =>\r\n `Input validation for action \"${actionId}\" in domain \"${domain}\" returned a promise, which is not supported.`,\r\n httpStatusCode: 400,\r\n }),\r\n [EErrId_NiceAction.action_output_validation_failed]: err<{\r\n domain: string;\r\n actionId: string;\r\n validationMessage: string;\r\n }>({\r\n message: ({ domain, actionId, validationMessage }) =>\r\n `Output validation failed for action \"${actionId}\" in domain \"${domain}\":\\n${validationMessage}`,\r\n httpStatusCode: 500,\r\n }),\r\n [EErrId_NiceAction.action_output_validation_promise]: err<{\r\n domain: string;\r\n actionId: string;\r\n }>({\r\n message: ({ domain, actionId }) =>\r\n `Output validation for action \"${actionId}\" in domain \"${domain}\" returned a promise, which is not supported.`,\r\n httpStatusCode: 500,\r\n }),\r\n },\r\n});\r\n","import type { IActionBase_JsonObject } from \"../ActionDefinition/Action/ActionBase.types\";\n\nexport const isAction_Base_JsonObject = (obj: unknown): obj is IActionBase_JsonObject => {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n typeof (obj as any).domain === \"string\" &&\n typeof (obj as any).id === \"string\" &&\n typeof (obj as any).form === \"string\"\n );\n};\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionPayload_Result_JsonObject } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { EActionPayloadType } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isActionPayload_Result_JsonObject = (\n obj: unknown,\n): obj is IActionPayload_Result_JsonObject => {\n return (\n isAction_Base_JsonObject(obj) &&\n (obj as any).result != null &&\n (obj as any).form === EActionForm.data &&\n (obj as any).type === EActionPayloadType.result\n );\n};\n","import { extractMessageFromStandardSchema } from \"@nice-code/common-errors\";\r\nimport {\r\n err_cast_not_nice,\r\n type INiceErrorDomainProps,\r\n type InferNiceError,\r\n type NiceErrorDomain,\r\n} from \"@nice-code/error\";\r\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\r\nimport { EErrId_NiceAction, err_nice_action } from \"../../errors/err_nice_action\";\r\nimport type {\r\n IActionErrorDeclaration,\r\n TActionSchemaOptions,\r\n TInferDeclaredErrors,\r\n TTransportedValue,\r\n} from \"./ActionSchema.types\";\r\n\r\n/**\r\n * What a sender should expect back from an action — declared on its schema so both ends agree without\r\n * any wire flag (each derives the mode from the shared `domain:id`).\r\n *\r\n * - `payload` — a typed output (the action has `.output(...)`); the sender awaits it.\r\n * - `ack` — an empty success confirming receipt (no output); the sender may await it to know the\r\n * receiver handled it (or to surface an error). This is the default for an action with no output.\r\n * - `none` — fire-and-forget: the receiver sends no reply and the sender doesn't wait. The sender's\r\n * running action completes as soon as the frame is on the wire (no pending reply, no timeout).\r\n */\r\nexport enum EActionResponseMode {\r\n payload = \"payload\",\r\n ack = \"ack\",\r\n none = \"none\",\r\n}\r\n\r\nexport class ActionSchema<\r\n INPUT extends TTransportedValue<any, any> = never,\r\n OUTPUT extends TTransportedValue<any, any> = never,\r\n ERRORS extends readonly IActionErrorDeclaration<any, any>[] = readonly [],\r\n> {\r\n private _errorDeclarations: IActionErrorDeclaration[] = [];\r\n private inputOptions: TActionSchemaOptions<any, any> | undefined;\r\n private outputOptions: TActionSchemaOptions<any, any> | undefined;\r\n private _responseMode: EActionResponseMode | undefined;\r\n\r\n get inputSchema(): StandardSchemaV1 | undefined {\r\n return this.inputOptions?.schema;\r\n }\r\n\r\n get outputSchema(): StandardSchemaV1 | undefined {\r\n return this.outputOptions?.schema;\r\n }\r\n\r\n /**\r\n * The response contract for this action. Defaults are inferred — `payload` when an output schema is\r\n * declared, otherwise `ack` — and made explicit by {@link ack} / {@link fireAndForget}.\r\n */\r\n get responseMode(): EActionResponseMode {\r\n if (this._responseMode != null) return this._responseMode;\r\n return this.outputOptions != null ? EActionResponseMode.payload : EActionResponseMode.ack;\r\n }\r\n\r\n /**\r\n * Mark this action as expecting only an acknowledgment (an empty success). Mostly for clarity — an\r\n * output-less action already acks by default — but it documents intent and reads as the deliberate\r\n * counterpart to {@link fireAndForget}.\r\n */\r\n ack(): this {\r\n this._responseMode = EActionResponseMode.ack;\r\n return this;\r\n }\r\n\r\n /**\r\n * Mark this action as fire-and-forget: the receiver sends no reply, and the sender's running action\r\n * completes the moment the frame is sent (no awaited reply, no timeout). Ideal for high-frequency\r\n * server→client pushes (presence, ticks) where an ack would only add wire chatter.\r\n */\r\n fireAndForget(): this {\r\n this._responseMode = EActionResponseMode.none;\r\n return this;\r\n }\r\n\r\n /**\r\n * Declare the input schema (JSON-native or with explicit SERDE type param).\r\n * For non-JSON-native inputs, prefer the 3-argument form below to avoid\r\n * needing explicit type parameters.\r\n */\r\n input<VS extends StandardSchemaV1 = StandardSchemaV1, SERDE_IN = any>(\r\n options: TActionSchemaOptions<VS, SERDE_IN>,\r\n ): ActionSchema<TTransportedValue<StandardSchemaV1.InferInput<VS>, SERDE_IN>, OUTPUT, ERRORS> {\r\n this.inputOptions = options;\r\n return this;\r\n }\r\n\r\n /**\r\n * Declare the output schema (JSON-native or with explicit SERDE type param).\r\n * For non-JSON-native outputs, prefer the 3-argument form below to avoid\r\n * needing explicit type parameters.\r\n */\r\n output<VS extends StandardSchemaV1 = StandardSchemaV1, SERDE_OUT = any>(\r\n options: TActionSchemaOptions<VS, SERDE_OUT>,\r\n ): ActionSchema<INPUT, TTransportedValue<StandardSchemaV1.InferInput<VS>, SERDE_OUT>, ERRORS> {\r\n this.outputOptions = options;\r\n return this;\r\n }\r\n\r\n /**\r\n * Declare that this action may throw any error from `domain`.\r\n * `TInferActionError` will include `NiceError<DEF, keyof schema>` in its union.\r\n */\r\n throws<ERR_DEF extends INiceErrorDomainProps>(\r\n domain: NiceErrorDomain<ERR_DEF>,\r\n ): ActionSchema<\r\n INPUT,\r\n OUTPUT,\r\n readonly [...ERRORS, IActionErrorDeclaration<ERR_DEF, keyof ERR_DEF[\"schema\"] & string>]\r\n >;\r\n\r\n /**\r\n * Declare that this action may throw only the listed `ids` from `domain`.\r\n * `TInferActionError` will include `NiceError<DEF, IDS[number]>` narrowed to those IDs.\r\n */\r\n throws<\r\n ERR_DEF extends INiceErrorDomainProps,\r\n IDS extends ReadonlyArray<keyof ERR_DEF[\"schema\"] & string>,\r\n >(\r\n domain: NiceErrorDomain<ERR_DEF>,\r\n ids: IDS,\r\n ): ActionSchema<\r\n INPUT,\r\n OUTPUT,\r\n readonly [...ERRORS, IActionErrorDeclaration<ERR_DEF, IDS[number] & string>]\r\n >;\r\n\r\n throws(domain: NiceErrorDomain<any>, ids?: ReadonlyArray<string>): ActionSchema<any, any, any> {\r\n this._errorDeclarations.push({ _domain: domain, _ids: ids });\r\n return this;\r\n }\r\n\r\n /**\r\n * Serialize raw input to a JSON-serializable form.\r\n * Uses the schema's serialization.serialize if defined; otherwise the input\r\n * is already JSON-native and is returned as-is.\r\n */\r\n serializeInput(rawInput: INPUT[0]): INPUT[1] {\r\n if (this.inputOptions?.serialization) {\r\n return this.inputOptions.serialization.serialize(rawInput);\r\n }\r\n return rawInput;\r\n }\r\n\r\n /**\r\n * Deserialize a JSON value back into the raw input type.\r\n * Uses serialization.deserialize if defined; otherwise the value is cast\r\n * directly (it's already in the correct shape).\r\n */\r\n deserializeInput(serialized: INPUT[1]): INPUT[0] {\r\n if (this.inputOptions?.serialization) {\r\n return this.inputOptions.serialization.deserialize(serialized);\r\n }\r\n return serialized as INPUT[0];\r\n }\r\n\r\n /**\r\n * Validate raw input against the schema defined via `.input({ schema })`.\r\n * Throws `action_input_validation_failed` if validation fails.\r\n * Returns the validated (and possibly coerced) value on success.\r\n * If no input schema was declared, the value is passed through as-is.\r\n */\r\n validateInput(value: unknown, meta: { domain: string; actionId: string }): INPUT[0] {\r\n if (this.inputOptions?.schema == null) {\r\n return value as INPUT[0];\r\n }\r\n const result = this.inputOptions.schema[\"~standard\"].validate(value);\r\n\r\n if (result instanceof Promise) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.action_input_validation_promise, {\r\n domain: meta.domain,\r\n actionId: meta.actionId,\r\n });\r\n }\r\n\r\n if (result.issues != null) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.action_input_validation_failed, {\r\n domain: meta.domain,\r\n actionId: meta.actionId,\r\n validationMessage: extractMessageFromStandardSchema(result),\r\n });\r\n }\r\n\r\n return result.value as INPUT[0];\r\n }\r\n\r\n validateOutput(value: unknown, meta: { domain: string; actionId: string }): OUTPUT[0] {\r\n if (this.outputOptions?.schema == null) {\r\n return value as OUTPUT[0];\r\n }\r\n const result = this.outputOptions.schema[\"~standard\"].validate(value);\r\n\r\n if (result instanceof Promise) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.action_output_validation_promise, {\r\n domain: meta.domain,\r\n actionId: meta.actionId,\r\n });\r\n }\r\n\r\n if (result.issues != null) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.action_output_validation_failed, {\r\n domain: meta.domain,\r\n actionId: meta.actionId,\r\n validationMessage: extractMessageFromStandardSchema(result),\r\n });\r\n }\r\n\r\n return result.value as OUTPUT[0];\r\n }\r\n\r\n /**\r\n * Serialize raw output to a JSON-serializable form.\r\n */\r\n serializeOutput(rawOutput: OUTPUT[0]): OUTPUT[1] {\r\n if (this.outputOptions?.serialization) {\r\n return this.outputOptions.serialization.serialize(rawOutput);\r\n }\r\n return rawOutput as OUTPUT[1];\r\n }\r\n\r\n /**\r\n * Deserialize a JSON value back into the raw output type.\r\n */\r\n deserializeOutput(serialized: OUTPUT[1]): OUTPUT[0] {\r\n if (this.outputOptions?.serialization) {\r\n return this.outputOptions.serialization.deserialize(serialized);\r\n }\r\n return serialized as OUTPUT[0];\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// TInferActionError — lives here (not in .types) to avoid circular imports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type TInferActionError<SCH> =\r\n SCH extends ActionSchema<any, any, infer DECLS>\r\n ? DECLS extends readonly IActionErrorDeclaration[]\r\n ? TInferDeclaredErrors<DECLS> | InferNiceError<typeof err_cast_not_nice>\r\n : InferNiceError<typeof err_cast_not_nice>\r\n : never;\r\n\r\nexport const actionSchema = (): ActionSchema => {\r\n return new ActionSchema();\r\n};\r\n","import { runtime } from \"std-env\";\nimport type { IRuntimeMeta } from \"../ActionRuntime/ActionRuntime.types\";\n\nexport const getAssumedRuntimeInfo = (): IRuntimeMeta => {\n return {\n assumed: true,\n runtimeName: runtime,\n };\n};\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionPayload_Progress_JsonObject } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { EActionPayloadType } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isActionPayload_Progress_JsonObject = (\n obj: unknown,\n): obj is IActionPayload_Progress_JsonObject => {\n return (\n isAction_Base_JsonObject(obj) &&\n \"progress\" in (obj as any) &&\n (obj as any).form === EActionForm.data &&\n (obj as any).type === EActionPayloadType.progress\n );\n};\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionPayload_Request_JsonObject } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { EActionPayloadType } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isActionPayload_Request_JsonObject = (\n obj: unknown,\n): obj is IActionPayload_Request_JsonObject => {\n return (\n isAction_Base_JsonObject(obj) &&\n \"input\" in (obj as any) &&\n (obj as any).form === EActionForm.data &&\n (obj as any).type === EActionPayloadType.request\n );\n};\n","import type { TActionPayload_Any_JsonObject } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { isActionPayload_Progress_JsonObject } from \"./isActionPayload_Progress_JsonObject\";\nimport { isActionPayload_Request_JsonObject } from \"./isActionPayload_Request_JsonObject\";\nimport { isActionPayload_Result_JsonObject } from \"./isActionPayload_Result_JsonObject\";\n\nexport function isActionPayload_Any_JsonObject(obj: unknown): obj is TActionPayload_Any_JsonObject {\n return (\n isActionPayload_Request_JsonObject(obj) ||\n isActionPayload_Result_JsonObject(obj) ||\n isActionPayload_Progress_JsonObject(obj)\n );\n}\n","// Module-level stack tracking which local handler is currently in its synchronous execution phase.\n// Child actions dispatched synchronously from inside a handler capture the top of this stack\n// as their parentCuid. The stack is push/popped around each handler's synchronous phase only.\nconst _stack: string[] = [];\n\nexport function pushHandlerCuid(cuid: string): void {\n _stack.push(cuid);\n}\n\nexport function popHandlerCuid(): void {\n _stack.pop();\n}\n\nexport function peekHandlerCuid(): string | undefined {\n return _stack[_stack.length - 1];\n}\n","import { err_nice_action } from \"../../../../errors/err_nice_action\";\r\n\r\nexport const err_nice_external_client = err_nice_action.createChildDomain({\r\n domain: \"err_nice_external_client\",\r\n schema: {},\r\n});\r\n","import { err } from \"@nice-code/error\";\r\nimport { err_nice_external_client } from \"../Handler/PeerLink/Connector/err_nice_external_client\";\r\nimport type { ETransportShape } from \"./Transport.types\";\r\n\r\nexport enum EErrId_NiceTransport {\r\n timeout = \"timeout\",\r\n not_found = \"not_found\",\r\n unsupported = \"unsupported\",\r\n initialization_failed = \"initialization_failed\",\r\n send_failed = \"send_failed\",\r\n invalid_action_response = \"invalid_action_response\",\r\n}\r\n\r\nexport const err_nice_transport = err_nice_external_client.createChildDomain({\r\n domain: \"err_nice_transport\",\r\n schema: {\r\n [EErrId_NiceTransport.timeout]: err<{ timeout: number }>({\r\n message: ({ timeout }) => `ActionConnect transport timed out after ${timeout}ms.`,\r\n }),\r\n [EErrId_NiceTransport.not_found]: err<{\r\n actionId: string;\r\n }>({\r\n message: ({ actionId }) => `No connected transport found for action \"${actionId}\".`,\r\n }),\r\n [EErrId_NiceTransport.unsupported]: err<{ transportShapes: ETransportShape[] }>({\r\n message: ({ transportShapes }) =>\r\n `${transportShapes.length} Transport(s) [${transportShapes.join(\", \")}] found but returned \"unsupported\" status.`,\r\n }),\r\n [EErrId_NiceTransport.initialization_failed]: err<{\r\n actionId: string;\r\n }>({\r\n message: ({ actionId }) => `Transports found for action \"${actionId}\", but none are ready.`,\r\n }),\r\n [EErrId_NiceTransport.send_failed]: err<{\r\n actionState: string;\r\n actionId: string;\r\n httpStatusCode?: number;\r\n message?: string;\r\n }>({\r\n message: ({ actionId, httpStatusCode, message }) =>\r\n `Failed to send action \"${actionId}\" [${httpStatusCode ?? \"Unknown status\"}]: ${message ?? \"Unknown error\"}.`,\r\n httpStatusCode: ({ httpStatusCode }) => httpStatusCode ?? 500,\r\n }),\r\n [EErrId_NiceTransport.invalid_action_response]: err<{\r\n actionId: string;\r\n }>({\r\n message: ({ actionId }) => `Invalid action response JSON structure for action \"${actionId}\"`,\r\n }),\r\n },\r\n});\r\n","import { EErrId_NiceTransport, err_nice_transport } from \"./err_nice_transport\";\r\nimport {\r\n ETransportStatus,\r\n type IActionTransportReady,\r\n type ITransportRouteActionParams,\r\n type TTransportCache,\r\n} from \"./Transport.types\";\r\nimport type { TransportConnection } from \"./TransportConnection\";\r\n\r\nexport class ConnectionTransportManager {\r\n private _transports: TransportConnection[] = [];\r\n\r\n constructor(private _cache: TTransportCache) {}\r\n\r\n addTransport(transport: TransportConnection) {\r\n this._transports.push(transport);\r\n }\r\n\r\n /**\r\n * The highest-priority transport (first declared). Used to label an action's route *before* the\r\n * transport has finished connecting — so a still-connecting action shows its (expected) destination\r\n * instead of an \"unknown\" hop. {@link getReadyTransport} still decides the real winner, and the\r\n * caller corrects the hop if a lower-priority transport ends up serving the action.\r\n */\r\n getPreferredTransport(): TransportConnection | undefined {\r\n return this._transports[0];\r\n }\r\n\r\n async getReadyTransport(\r\n routeActionParams: ITransportRouteActionParams,\r\n ): Promise<IActionTransportReady> {\r\n const action = routeActionParams.action;\r\n\r\n // The transports are declared in preference order. We honour that order strictly: a\r\n // higher-priority transport that is still *initializing* (e.g. a WebSocket warming up its\r\n // connection / handshake) takes precedence over a lower-priority transport that happens to be\r\n // synchronously ready right now (e.g. plain HTTP). A lower-priority transport is only used as a\r\n // fallback once every transport ahead of it has been exhausted (unsupported or failed). This is\r\n // what lets a transport \"warm up\" on the first action instead of racing — and quietly losing — to\r\n // an always-ready fallback.\r\n const candidates: Promise<IActionTransportReady>[] = [];\r\n const unavailableTransports: TransportConnection<any>[] = [];\r\n\r\n for (const transport of this._transports) {\r\n // Availability gate — consulted *before* cache-key resolution and `getTransport`. A transport that\r\n // declares itself unavailable for this action (e.g. a socket gated behind a runtime precondition)\r\n // is skipped entirely, so its cache key is never computed and its carrier is never opened.\r\n if (!transport.isAvailable(routeActionParams)) {\r\n unavailableTransports.push(transport);\r\n continue;\r\n }\r\n\r\n const cacheKey = transport.getCacheKey(routeActionParams);\r\n\r\n if (cacheKey != null) {\r\n const cached = this._cache.get(cacheKey);\r\n if (cached != null) {\r\n if (cached instanceof Promise) {\r\n candidates.push(cached);\r\n continue;\r\n }\r\n // A live, ready cached transport: nothing lower priority can outrank it, so stop scanning.\r\n candidates.push(Promise.resolve({ ...cached, transport }));\r\n break;\r\n }\r\n }\r\n\r\n const statusInfo = transport.getTransport(routeActionParams);\r\n\r\n if (statusInfo.status === ETransportStatus.ready) {\r\n const readyData = statusInfo.readyData;\r\n if (cacheKey != null) {\r\n const entry = { methods: readyData, transport };\r\n this._cache.set(cacheKey, entry);\r\n // Only evict if this exact entry is still cached — a socket that closes after the cache was\r\n // re-populated (e.g. a teardown then reconnect under the same key) must not drop the new one.\r\n readyData.addOnDisconnectListener?.(() => {\r\n if (this._cache.get(cacheKey) === entry) this._cache.delete(cacheKey);\r\n });\r\n }\r\n // A synchronously-ready transport is a terminal fallback: anything after it is unreachable.\r\n candidates.push(Promise.resolve({ methods: readyData, transport }));\r\n break;\r\n }\r\n\r\n if (statusInfo.status === ETransportStatus.unsupported) {\r\n unavailableTransports.push(transport);\r\n continue;\r\n }\r\n\r\n if (statusInfo.status === ETransportStatus.initializing) {\r\n const promise = statusInfo.initializationPromise\r\n .then((info): IActionTransportReady => {\r\n if (info.status === ETransportStatus.failed) {\r\n throw info.error;\r\n }\r\n\r\n if (info.status === ETransportStatus.unsupported) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.unsupported, {\r\n transportShapes: [transport.type],\r\n });\r\n }\r\n\r\n const readyData = info.readyData;\r\n const entry = { methods: readyData, transport };\r\n if (cacheKey != null) {\r\n // Adopt the cache slot only if our placeholder promise is still there. A teardown\r\n // (clearTransportCache) or a newer connection on the same key may have replaced it while\r\n // we were connecting — in that case this socket is orphaned, so close it instead of\r\n // clobbering the live entry. The awaiting dispatch then aborts cleanly on the closed socket.\r\n if (this._cache.get(cacheKey) === promise) {\r\n this._cache.set(cacheKey, entry);\r\n readyData.addOnDisconnectListener?.(() => {\r\n if (this._cache.get(cacheKey) === entry) this._cache.delete(cacheKey);\r\n });\r\n } else {\r\n readyData.disconnect?.();\r\n }\r\n }\r\n\r\n return entry;\r\n })\r\n .catch((e) => {\r\n // Only clear our own slot — a newer connection may already own the key.\r\n if (cacheKey != null && this._cache.get(cacheKey) === promise) {\r\n this._cache.delete(cacheKey);\r\n }\r\n throw e;\r\n });\r\n\r\n if (cacheKey != null) {\r\n this._cache.set(cacheKey, promise);\r\n }\r\n\r\n candidates.push(promise);\r\n }\r\n }\r\n\r\n if (candidates.length === 0) {\r\n if (unavailableTransports.length > 0) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.unsupported, {\r\n transportShapes: unavailableTransports.map((t) => t.type),\r\n });\r\n }\r\n\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.not_found, {\r\n actionId: action.id,\r\n });\r\n }\r\n\r\n // Resolve candidates in priority order, falling through to the next only when the preferred\r\n // transport actually fails. Initialization for every candidate was already kicked off above, so\r\n // they all warm up in parallel — we simply *select* the winner by declared preference.\r\n let lastError: unknown;\r\n for (const candidate of candidates) {\r\n try {\r\n return await candidate;\r\n } catch (e) {\r\n lastError = e;\r\n }\r\n }\r\n\r\n throw err_nice_transport\r\n .fromId(EErrId_NiceTransport.initialization_failed, {\r\n actionId: action.id,\r\n })\r\n .withOriginError(lastError);\r\n }\r\n}\r\n","import type {\n TAction_Any_JsonObject,\n TNarrowActionJsonTypeToActionInstanceType,\n} from \"../ActionDefinition/Action/Action.combined.types\";\nimport type { INiceActionIdAndDomain } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { ActionDomain } from \"../ActionDefinition/Domain/ActionDomain\";\nimport type { IActionDomain } from \"../ActionDefinition/Domain/ActionDomain.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../errors/err_nice_action\";\n\nexport class ActionDomainManager {\n private _domains: Map<string, ActionDomain<any>> = new Map();\n\n addDomain(domain: ActionDomain<any>): void {\n this._domains.set(domain.domain, domain);\n }\n\n getDomains(): ActionDomain<any>[] {\n return [...this._domains.values()];\n }\n\n verifyIsActionJson(action: INiceActionIdAndDomain<any>): void {\n if (typeof action.domain !== \"string\" || typeof action.id !== \"string\") {\n throw err_nice_action.fromId(EErrId_NiceAction.wire_not_action_data);\n }\n }\n\n getActionDomain<DOM extends IActionDomain, ACT extends INiceActionIdAndDomain<DOM>>(\n action: ACT,\n ): ActionDomain<DOM> | undefined {\n this.verifyIsActionJson(action);\n const domain = this._domains.get(action.domain) as ActionDomain<DOM>;\n\n if (!domain) {\n return undefined;\n }\n\n return domain;\n }\n\n getActionDomainOrThrow<DOM extends IActionDomain, ACT extends INiceActionIdAndDomain<DOM>>(\n action: ACT,\n ): ActionDomain<DOM> {\n this.verifyIsActionJson(action);\n const domain = this._domains.get(action.domain) as ActionDomain<DOM>;\n\n if (!domain) {\n throw err_nice_action.fromId(EErrId_NiceAction.domain_no_handler, {\n domain: action.domain,\n });\n }\n\n return domain;\n }\n\n hydrateActionPayload<\n D extends IActionDomain,\n ID extends keyof D[\"actionSchema\"] & string,\n A extends TAction_Any_JsonObject<D, ID>,\n >(actionJson: A): TNarrowActionJsonTypeToActionInstanceType<D, A, ID> {\n const domain = this.getActionDomainOrThrow(actionJson) as ActionDomain<D>;\n return domain.hydrateAnyAction(actionJson);\n }\n}\n","import type { INiceActionIdAndDomain } from \"../../ActionDefinition/Action/ActionBase.types\";\nimport type { ActionCore } from \"../../ActionDefinition/Action/Core/ActionCore\";\nimport type { ActionDomain } from \"../../ActionDefinition/Domain/ActionDomain\";\nimport type { IActionDomain } from \"../../ActionDefinition/Domain/ActionDomain.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../../errors/err_nice_action\";\nimport { ActionDomainManager } from \"../ActionDomainManager\";\nimport type { IHandleActionOptions } from \"../Handler/ActionHandler.types\";\nimport {\n EActionRouterContextType,\n type IActionRouterContext,\n type TMatchHandlerKey,\n} from \"./ActionRouter.types\";\n\nexport class ActionRouter<DATA> {\n readonly domainManager = new ActionDomainManager();\n private actionRouteData = new Map<TMatchHandlerKey, DATA[]>();\n private _context: IActionRouterContext;\n\n constructor(context: IActionRouterContext) {\n this._context = context;\n }\n\n // ---------------------------------------------------------------------------\n // Merge / copy\n // ---------------------------------------------------------------------------\n\n /** Copy all routes from another router into this one, replacing any overlapping keys. */\n mergeRouter(actionRouter: ActionRouter<DATA>): void {\n for (const domain of actionRouter.getDomains()) {\n this.domainManager.addDomain(domain);\n }\n for (const [matchKey, routeDataEntries] of actionRouter.actionRouteData.entries()) {\n this.actionRouteData.set(matchKey, [...routeDataEntries]);\n }\n }\n\n addDomainsFromOther(actionRouter: ActionRouter<DATA>): void {\n for (const domain of actionRouter.getDomains()) {\n this.domainManager.addDomain(domain);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Lookup\n // ---------------------------------------------------------------------------\n\n /** All FNs registered for an action, ID-specific entries first then domain wildcard. */\n getRouteDataEntriesForAction(action: { domain: string; id: string }): DATA[] {\n const idKey: TMatchHandlerKey = `dom[${action.domain}]id[${action.id}]`;\n const domKey: TMatchHandlerKey = `dom[${action.domain}]id[_]`;\n return [\n ...(this.actionRouteData.get(idKey) ?? []),\n ...(this.actionRouteData.get(domKey) ?? []),\n ];\n }\n\n /** First FN registered for an action (ID-specific beats domain wildcard). */\n getRouteDataForAction(action: INiceActionIdAndDomain): DATA | undefined {\n return this.getRouteDataEntriesForAction(action)[0];\n }\n\n private throwNoHandlerForAction(\n action: INiceActionIdAndDomain,\n context: IHandleActionOptions,\n ): never {\n if (this._context.contextType === EActionRouterContextType.handler_route) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n specifiedClient: context.targetLocalRuntime?.coordinate,\n });\n }\n\n if (this._context.contextType === EActionRouterContextType.runtime_to_handler) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n specifiedClient: this._context.runtime.coordinate,\n });\n }\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n });\n }\n\n getRouteDataEntriesForActionOrThrow(\n action: INiceActionIdAndDomain,\n context: IHandleActionOptions,\n ): DATA[] {\n const entries = this.getRouteDataEntriesForAction(action);\n\n if (entries.length === 0) {\n this.throwNoHandlerForAction(action, context);\n }\n\n return entries;\n }\n\n getRouteDataForActionOrThrow(\n action: INiceActionIdAndDomain,\n context: IHandleActionOptions,\n ): DATA {\n const routeData = this.getRouteDataForAction(action);\n\n if (!routeData) {\n this.throwNoHandlerForAction(action, context);\n }\n\n return routeData;\n }\n\n /** All FNs stored under an exact match key. */\n getForKey(key: TMatchHandlerKey): readonly DATA[] {\n return this.actionRouteData.get(key) ?? [];\n }\n\n /** Every match key that has at least one registered FN. */\n getRegisteredKeys(): TMatchHandlerKey[] {\n return [...this.actionRouteData.keys()];\n }\n\n getDomains(): ActionDomain[] {\n return this.domainManager.getDomains();\n }\n\n // ---------------------------------------------------------------------------\n // Registration — for* (replace) and add* (accumulate)\n // ---------------------------------------------------------------------------\n\n /** Register a handler for all actions in a domain, replacing any existing one. */\n forDomain<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>, routeData: DATA): this {\n this.domainManager.addDomain(domain);\n this.actionRouteData.set(`dom[${domain.domain}]id[_]`, [routeData]);\n return this;\n }\n\n forAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\n action: ActionCore<ACT_DOM, ID>,\n routeData: DATA,\n ): this {\n return this.forActionId(action._domain, action.id, routeData);\n }\n\n /** Register a handler for a specific action, replacing any existing one. */\n forActionId<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\n domain: ActionDomain<ACT_DOM>,\n id: ID,\n routeData: DATA,\n ): this {\n this.domainManager.addDomain(domain);\n this.actionRouteData.set(`dom[${domain.domain}]id[${id}]`, [routeData]);\n return this;\n }\n\n /** Register one handler for several action IDs, replacing any existing ones. */\n forActionIds<\n ACT_DOM extends IActionDomain,\n IDS extends ReadonlyArray<keyof ACT_DOM[\"actionSchema\"] & string>,\n >(domain: ActionDomain<ACT_DOM>, ids: IDS, routeData: DATA): this {\n this.domainManager.addDomain(domain);\n for (const id of ids) {\n this.forActionId(domain, id, routeData);\n }\n return this;\n }\n\n /** Register per-action handlers from a cases map, replacing any existing ones. */\n forDomainActionCases<FOR_DOM extends IActionDomain>(\n domain: ActionDomain<FOR_DOM>,\n cases: { [ID in keyof FOR_DOM[\"actionSchema\"] & string]?: DATA },\n ): this {\n this.domainManager.addDomain(domain);\n for (const id of Object.keys(cases) as Array<keyof FOR_DOM[\"actionSchema\"] & string>) {\n const routeData = cases[id];\n if (routeData != null) {\n this.actionRouteData.set(`dom[${domain.domain}]id[${id}]`, [routeData]);\n }\n }\n return this;\n }\n\n /** Append a handler for all actions in a domain (accumulates alongside existing). */\n addForDomain<FOR_DOM extends IActionDomain>(\n domain: ActionDomain<FOR_DOM>,\n routeData: DATA,\n ): this {\n this.domainManager.addDomain(domain);\n this._push(`dom[${domain.domain}]id[_]`, routeData);\n return this;\n }\n\n /** Append a handler for a specific action (accumulates alongside existing). */\n addForAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\n domain: ActionDomain<ACT_DOM>,\n id: ID,\n routeData: DATA,\n ): this {\n this.domainManager.addDomain(domain);\n this._push(`dom[${domain.domain}]id[${id}]`, routeData);\n return this;\n }\n\n /** Append one handler for several action IDs (accumulates alongside existing). */\n addForActionIds<\n ACT_DOM extends IActionDomain,\n IDS extends ReadonlyArray<keyof ACT_DOM[\"actionSchema\"] & string>,\n >(domain: ActionDomain<ACT_DOM>, ids: IDS, routeData: DATA): this {\n this.domainManager.addDomain(domain);\n for (const id of ids) {\n this.addForAction(domain, id, routeData);\n }\n return this;\n }\n\n /** Append per-action handlers from a cases map (accumulates alongside existing). */\n addForDomainActionCases<FOR_DOM extends IActionDomain>(\n domain: ActionDomain<FOR_DOM>,\n cases: { [ID in keyof FOR_DOM[\"actionSchema\"] & string]?: DATA },\n ): this {\n this.domainManager.addDomain(domain);\n for (const id of Object.keys(cases) as Array<keyof FOR_DOM[\"actionSchema\"] & string>) {\n const routeData = cases[id];\n if (routeData != null) {\n this._push(`dom[${domain.domain}]id[${id}]`, routeData);\n }\n }\n return this;\n }\n\n /** Append a handler directly by its raw match key (used when the key is known ahead of time). */\n addForKey(key: TMatchHandlerKey, routeData: DATA): this {\n this._push(key, routeData);\n return this;\n }\n\n private _push(key: TMatchHandlerKey, routeData: DATA): void {\n const existing = this.actionRouteData.get(key);\n if (existing != null) {\n existing.push(routeData);\n } else {\n this.actionRouteData.set(key, [routeData]);\n }\n }\n}\n","import { nanoid } from \"nanoid\";\nimport type { IActionRouteItemHandler } from \"../../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport type { ActionPayload_Request } from \"../../ActionDefinition/Action/Payload/ActionPayload_Request\";\nimport type { RunningAction } from \"../../ActionDefinition/Action/RunningAction\";\nimport type { IActionDomain } from \"../../ActionDefinition/Domain/ActionDomain.types\";\nimport { ActionRouter } from \"../Routing/ActionRouter\";\nimport type {\n EActionHandlerType,\n IActionHandler_Base,\n IHandleActionOptions,\n TActionHandler_Json,\n} from \"./ActionHandler.types\";\n\nexport abstract class ActionHandler<T extends EActionHandlerType>\n implements IActionHandler_Base<T>\n{\n abstract readonly handlerType: T;\n readonly cuid: string;\n abstract readonly actionRouter: ActionRouter<any>;\n\n constructor() {\n this.cuid = nanoid();\n }\n\n getActionRouter() {\n return this.actionRouter;\n }\n\n abstract handleActionRequest<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string,\n >(\n action: ActionPayload_Request<DOM, ID>,\n config?: IHandleActionOptions,\n ): Promise<RunningAction<DOM, ID>>;\n\n abstract toJsonObject(): TActionHandler_Json;\n\n abstract toHandlerRouteItem(...args: any[]): IActionRouteItemHandler;\n}\n","import type { ActionCore } from \"../../../ActionDefinition/Action/Core/ActionCore\";\r\nimport type {\r\n TActionPayload_Any_Instance,\r\n TActionPayload_Any_JsonObject,\r\n} from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { IActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport type { ActionRuntime } from \"../../ActionRuntime\";\r\nimport { ActionRouter } from \"../../Routing/ActionRouter\";\r\nimport { EActionRouterContextType } from \"../../Routing/ActionRouter.types\";\r\nimport type { RuntimeCoordinate } from \"../../RuntimeCoordinate\";\r\nimport { ActionHandler } from \"../ActionHandler\";\r\nimport { EActionHandlerType, type IActionHandler_Peer } from \"../ActionHandler.types\";\r\n\r\n/**\r\n * Shared base for every handler that routes a domain set to/from *another runtime* (a \"peer\") — the\r\n * unified peer-link concept. Both specializations extend this as siblings, differing only in *who\r\n * establishes the connection*, which is a transport trait, not a routing one:\r\n *\r\n * - {@link ConnectorHandler} — **dial-out**: this runtime opens connection(s) to one peer\r\n * over a transport stack (with caching + fallback). The classic \"client → backend\" link.\r\n * - {@link AcceptorHandler} — **accept-in**: connections are accepted from many peers and fed in\r\n * via `receive()`; it keeps a per-connection registry and can push to any of them.\r\n *\r\n * To the runtime there is no \"client\" vs \"server\" — both are peer-link handlers (`handlerType =\r\n * external`) keyed to a peer coordinate, chosen by the return-path dispatch via {@link sendReturnPayload}.\r\n */\r\nexport abstract class PeerLinkHandler\r\n extends ActionHandler<EActionHandlerType.peer>\r\n implements IActionHandler_Peer\r\n{\r\n /** The peer runtime this handler links to (an env-only coordinate for an accept-in handler). */\r\n readonly peerClient: RuntimeCoordinate;\r\n readonly handlerType = EActionHandlerType.peer;\r\n\r\n /**\r\n * Whether this link can deliver an *unsolicited* frame to the peer (a result/progress pushed back on\r\n * the return path, or a `broadcast`). A duplex carrier (WebSocket/WebRTC/…) can; an exchange-only\r\n * carrier (HTTP) cannot — its reply must ride the response to its own request. The runtime's\r\n * return-path dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) skips handlers that can't\r\n * push, so an exchange-only handler is never asked to deliver one.\r\n */\r\n abstract readonly canPush: boolean;\r\n\r\n readonly actionRouter: ActionRouter<true> = new ActionRouter({\r\n contextType: EActionRouterContextType.handler_route,\r\n handler: this,\r\n });\r\n\r\n /** Listeners installed by the runtime (`resolveIncomingActionPayload`) for inbound peer frames. */\r\n private readonly _incomingActionDataListeners: ((\r\n json: TActionPayload_Any_JsonObject<any, any>,\r\n ) => void)[] = [];\r\n\r\n constructor(peerCoordinate: RuntimeCoordinate) {\r\n super();\r\n this.peerClient = peerCoordinate;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Routing — which domains/actions travel to this peer (shared by both specializations)\r\n // ---------------------------------------------------------------------------\r\n\r\n forDomain<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>): this {\r\n this.actionRouter.forDomain(domain, true);\r\n return this;\r\n }\r\n\r\n forAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\r\n action: ActionCore<ACT_DOM, ID>,\r\n ): this {\r\n this.actionRouter.forAction(action, true);\r\n return this;\r\n }\r\n\r\n forActionIds<\r\n ACT_DOM extends IActionDomain,\r\n IDS extends ReadonlyArray<keyof ACT_DOM[\"actionSchema\"] & string>,\r\n >(domain: ActionDomain<ACT_DOM>, ids: IDS): this {\r\n this.actionRouter.forActionIds(domain, ids, true);\r\n return this;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Runtime binding — inbound peer frames\r\n // ---------------------------------------------------------------------------\r\n\r\n _setIncomingActionDataListener(\r\n listener: (json: TActionPayload_Any_JsonObject<any, any>) => void,\r\n ): void {\r\n this._incomingActionDataListeners.push(listener);\r\n }\r\n\r\n /** Hand a decoded inbound frame to the runtime (called by each specialization's receive path). */\r\n protected _emitIncoming(json: TActionPayload_Any_JsonObject<any, any>): void {\r\n for (const listener of this._incomingActionDataListeners) listener(json);\r\n }\r\n\r\n /**\r\n * Dispatch a result/progress payload back to the action's origin peer over this link. The runtime's\r\n * return-path dispatch calls it on whichever peer-link handler best reaches `originClient`. Returns\r\n * `true` if it was sent, `false` if no channel was available.\r\n */\r\n abstract sendReturnPayload(\r\n payload: TActionPayload_Any_Instance<any, any>,\r\n config: { targetLocalRuntime: ActionRuntime },\r\n ): Promise<boolean>;\r\n\r\n /**\r\n * Whether this handler currently holds a *live* connection bound to `origin`. The runtime's return-path\r\n * dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) prefers a handler that owns the origin's\r\n * connection over a mere coordinate match, so with several duplex acceptors a result/push routes back\r\n * over the carrier the client connected on. Defaults to `false`; an acceptor overrides it from its\r\n * connection registry.\r\n */\r\n ownsLiveConnectionFor(_origin: RuntimeCoordinate): boolean {\r\n return false;\r\n }\r\n\r\n /** Release any long-lived connections this handler owns (a teardown). No-op by default. */\r\n clearTransportCache(): void {}\r\n}\r\n","import type { IActionRouteItem } from \"../../../../ActionDefinition/Action/Context/ActionContext.types\";\r\nimport type {\r\n IActionRouteItemHandler,\r\n TActionPayload_Any_Instance,\r\n} from \"../../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport { EActionPayloadType } from \"../../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionPayload_Request } from \"../../../../ActionDefinition/Action/Payload/ActionPayload_Request\";\r\nimport { RunningAction } from \"../../../../ActionDefinition/Action/RunningAction\";\r\nimport type { IActionDomain } from \"../../../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport { EActionResponseMode } from \"../../../../ActionDefinition/Schema/ActionSchema\";\r\nimport { DEFAULT_TRANSPORT_TIMEOUT } from \"../../../../nice_action.static\";\r\nimport { ActionRuntime } from \"../../../ActionRuntime\";\r\nimport { peekHandlerCuid } from \"../../../HandlerCallStack\";\r\nimport { ConnectionTransportManager } from \"../../../Transport/ConnectionTransportManager\";\r\nimport {\r\n ETransportShape,\r\n type ITransportMethod_SendActionData_Input,\r\n type ITransportRouteActionParams,\r\n type TTransportCache,\r\n} from \"../../../Transport/Transport.types\";\r\nimport type { TransportConnection } from \"../../../Transport/TransportConnection\";\r\nimport type { IActionHandler_Peer_Json, IHandleActionOptions } from \"../../ActionHandler.types\";\r\nimport { PeerLinkHandler } from \"../../PeerLink/PeerLinkHandler\";\r\nimport type { IConnectorHandlerConfig } from \"./ConnectorHandler.types\";\r\n\r\n/**\r\n * Dial-out peer link: this runtime opens connection(s) to one peer over a transport stack (cached, with\r\n * preference-ordered fallback). The classic \"client → backend\" handler — but to the runtime it's just a\r\n * {@link PeerLinkHandler} like the accept-in server one.\r\n */\r\nexport class ConnectorHandler extends PeerLinkHandler {\r\n /**\r\n * Dial-out can receive (and so return) an unsolicited push only over a duplex transport. With every\r\n * transport exchange-only (HTTP), the peer can never push to us — so this link can't deliver one back.\r\n */\r\n readonly canPush: boolean;\r\n\r\n private _defaultTimeout: number;\r\n private _transportCache: TTransportCache = new Map();\r\n private transportManager = new ConnectionTransportManager(this._transportCache);\r\n\r\n constructor({\r\n runtimeCoordinate: peerSpecifier,\r\n transports,\r\n defaultTimeout,\r\n }: IConnectorHandlerConfig) {\r\n super(peerSpecifier);\r\n\r\n this._defaultTimeout = defaultTimeout ?? DEFAULT_TRANSPORT_TIMEOUT;\r\n this.canPush = transports.some((transport) => transport.type === ETransportShape.duplex);\r\n\r\n for (const transport of transports) {\r\n const connection = transport._createConnection({\r\n resolvers: {\r\n onIncomingActionDataJson: (json) => this._emitIncoming(json),\r\n },\r\n });\r\n connection.definition = transport;\r\n this.transportManager.addTransport(connection);\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Action handling\r\n // ---------------------------------------------------------------------------\r\n\r\n async handleActionRequest<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n >(\r\n action: ActionPayload_Request<DOM, ID>,\r\n config?: IHandleActionOptions,\r\n ): Promise<RunningAction<DOM, ID>> {\r\n const localRuntime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();\r\n const localClient = localRuntime.coordinate;\r\n\r\n const incomingTimeout = config?.timeout ?? this._defaultTimeout;\r\n\r\n // Capture parent + call site synchronously — once we await the transport the call stack is gone.\r\n const parentCuid = peekHandlerCuid();\r\n const callSite = action._callSite ?? new Error().stack;\r\n\r\n const routeParams: ITransportRouteActionParams = {\r\n action,\r\n localClient,\r\n externalClient: this.peerClient,\r\n };\r\n\r\n // Record the route hop up-front, labelled with the highest-priority transport, so the action shows\r\n // its (expected) destination — the runtime + e.g. \"ws → backend\" — the moment it appears, instead\r\n // of an \"unknown\" hop while the transport is still connecting. `_dispatchWhenTransportReady`\r\n // corrects it once `getReadyTransport` picks the real winner (which can differ if the preferred\r\n // transport is unavailable and a fallback serves the action).\r\n const preferredTransport = this.transportManager.getPreferredTransport();\r\n const routeItem: IActionRouteItem | undefined =\r\n preferredTransport != null\r\n ? {\r\n runtime: localClient,\r\n handler: this.toHandlerRouteItem(preferredTransport, routeParams),\r\n time: Date.now(),\r\n }\r\n : undefined;\r\n if (routeItem != null) action.context.addRouteItem(routeItem);\r\n\r\n // Create + register the RunningAction up-front, before acquiring the transport. Acquiring it can\r\n // take real time (opening a WebSocket + running its handshake on the first action), and that wait\r\n // is part of the action's running lifecycle — not a precondition for the action to exist. Creating\r\n // it now means observers (devtools, the dispatching domain's listeners) see the action the moment\r\n // it's initiated and watch it move through \"connecting → sent → finished\", instead of it only\r\n // popping into existence — already mid-flight or done — once the socket is ready.\r\n const runningAction = new RunningAction<DOM, ID>({\r\n context: action.context,\r\n request: action,\r\n parentCuid,\r\n callSite,\r\n });\r\n localRuntime.registerRunningAction(runningAction);\r\n\r\n // Resolve the transport and dispatch in the background so the RunningAction can be returned (and\r\n // observed) immediately. Any failure along the way aborts the action, surfacing through its result\r\n // and in the devtools just as a synchronous send failure would.\r\n void this._dispatchWhenTransportReady(runningAction, routeParams, routeItem, incomingTimeout);\r\n\r\n return runningAction;\r\n }\r\n\r\n private async _dispatchWhenTransportReady<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n >(\r\n runningAction: RunningAction<DOM, ID>,\r\n routeParams: ITransportRouteActionParams,\r\n routeItem: IActionRouteItem | undefined,\r\n incomingTimeout: number,\r\n ): Promise<void> {\r\n const action = routeParams.action;\r\n try {\r\n const { methods, transport } = await this.transportManager.getReadyTransport(routeParams);\r\n\r\n // Correct the hop to the transport that actually serves the action (the preferred one may have\r\n // been unavailable). Mutated in place so the action wire and the devtools \"finished\" view reflect\r\n // the real route.\r\n const handlerRouteItem = this.toHandlerRouteItem(transport, routeParams);\r\n if (routeItem != null) {\r\n routeItem.handler = handlerRouteItem;\r\n routeItem.time = Date.now();\r\n } else {\r\n action.context.addRouteItem({\r\n runtime: routeParams.localClient,\r\n handler: handlerRouteItem,\r\n time: Date.now(),\r\n });\r\n }\r\n\r\n const sendInput: ITransportMethod_SendActionData_Input = {\r\n ...routeParams,\r\n runningAction,\r\n timeout: incomingTimeout,\r\n };\r\n\r\n if (action.type === EActionPayloadType.request && methods.updateRunConfig != null) {\r\n const runConfig = methods.updateRunConfig(sendInput);\r\n sendInput.timeout = runConfig?.timeout ?? incomingTimeout;\r\n }\r\n\r\n methods.sendActionData(sendInput);\r\n\r\n // Fire-and-forget: no reply correlates back, so resolve the running action on send instead of\r\n // leaving it pending until it times out.\r\n if (\r\n action.type === EActionPayloadType.request &&\r\n action.schema.responseMode === EActionResponseMode.none\r\n ) {\r\n runningAction._completeWithResult(\r\n (action as ActionPayload_Request<any, any>).successResult(undefined),\r\n );\r\n }\r\n } catch (err) {\r\n runningAction._abort(err);\r\n }\r\n }\r\n\r\n /**\r\n * Dispatch a result or progress payload directly back to the external client via the best\r\n * available bidirectional transport (WebSocket / Custom). Used for return-path routing when the\r\n * local runtime recognises that it has a direct channel to the action's originClient.\r\n *\r\n * Returns `true` if the payload was sent, `false` if no suitable transport was available.\r\n */\r\n async sendReturnPayload(\r\n payload: TActionPayload_Any_Instance<any, any>,\r\n config: { targetLocalRuntime: ActionRuntime },\r\n ): Promise<boolean> {\r\n const localClient = config.targetLocalRuntime.coordinate;\r\n try {\r\n const { methods } = await this.transportManager.getReadyTransport({\r\n action: payload,\r\n localClient,\r\n externalClient: this.peerClient,\r\n });\r\n if (methods.sendReturnData == null) return false;\r\n methods.sendReturnData(payload, { localClient, externalClient: this.peerClient });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n toJsonObject(): IActionHandler_Peer_Json {\r\n return {\r\n type: this.handlerType,\r\n client: this.peerClient,\r\n };\r\n }\r\n\r\n toHandlerRouteItem(\r\n transport: TransportConnection,\r\n input: ITransportRouteActionParams,\r\n ): IActionRouteItemHandler {\r\n return {\r\n type: this.handlerType,\r\n client: this.peerClient,\r\n transOrd: transport.transOrd,\r\n transShape: transport.type,\r\n transInfo: transport.getRouteInfo(input),\r\n };\r\n }\r\n\r\n clearTransportCache() {\r\n // Close any live long-lived connection (e.g. a WebSocket) before dropping it, so a teardown\r\n // actually releases the socket instead of leaving it open until GC. HTTP/stateless transports\r\n // don't implement `disconnect`, so they're simply forgotten.\r\n for (const entry of this._transportCache.values()) {\r\n if (entry instanceof Promise) {\r\n entry.then((ready) => ready.methods.disconnect?.()).catch(() => {});\r\n } else {\r\n entry.methods.disconnect?.();\r\n }\r\n }\r\n this._transportCache.clear();\r\n }\r\n}\r\n\r\nexport const createConnectorHandler = (config: IConnectorHandlerConfig) => {\r\n return new ConnectorHandler(config);\r\n};\r\n","import { castNiceError } from \"@nice-code/error\";\r\nimport { nanoid } from \"nanoid\";\r\nimport type { ActionCore } from \"../ActionDefinition/Action/Core/ActionCore\";\r\nimport type { TActionPayload_Any_Instance } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport {\r\n EActionPayloadType,\r\n type TActionPayload_Any_JsonObject,\r\n} from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport { RunningAction } from \"../ActionDefinition/Action/RunningAction\";\r\nimport {\r\n ERunningActionFinishedType,\r\n ERunningActionUpdateType,\r\n} from \"../ActionDefinition/Action/RunningAction.types\";\r\nimport type { ActionDomain } from \"../ActionDefinition/Domain/ActionDomain\";\r\nimport type { IActionDomain } from \"../ActionDefinition/Domain/ActionDomain.types\";\r\nimport { EActionResponseMode } from \"../ActionDefinition/Schema/ActionSchema\";\r\nimport { EErrId_NiceAction, err_nice_action } from \"../errors/err_nice_action\";\r\nimport { UNSET_RUNTIME_ENV_ID } from \"../nice_action.static\";\r\nimport { getAssumedRuntimeInfo } from \"../utils/getAssumedRuntimeEnvironment\";\r\nimport { isActionPayload_Any_JsonObject } from \"../utils/isActionPayload_Any_JsonObject\";\r\nimport type { IRuntimeMeta, TActionRuntimeHandler } from \"./ActionRuntime.types\";\r\nimport {\r\n EActionHandlerType,\r\n type IHandleActionOptions,\r\n type TActionHandler,\r\n} from \"./Handler/ActionHandler.types\";\r\nimport { ConnectorHandler } from \"./Handler/PeerLink/Connector/ConnectorHandler\";\r\nimport type { PeerLinkHandler } from \"./Handler/PeerLink/PeerLinkHandler\";\r\nimport { ActionRouter } from \"./Routing/ActionRouter\";\r\nimport { EActionRouterContextType } from \"./Routing/ActionRouter.types\";\r\nimport { type IRuntimeCoordinateSpecifics, RuntimeCoordinate } from \"./RuntimeCoordinate\";\r\nimport type { Transport } from \"./Transport/Transport\";\r\n\r\nexport class ActionRuntime {\r\n private _coordinate: RuntimeCoordinate;\r\n readonly timeCreated: number;\r\n readonly runtimeInfo: IRuntimeMeta = getAssumedRuntimeInfo();\r\n private readonly actionRouter: ActionRouter<TActionRuntimeHandler>;\r\n private readonly _pendingRunningActions: Map<string, RunningAction<any, any>> = new Map();\r\n private readonly _registeredPeerHandlers: PeerLinkHandler[] = [];\r\n private _applied = false;\r\n\r\n static getDefault(): ActionRuntime {\r\n return getDefaultActionRuntime();\r\n }\r\n\r\n constructor(coordinate: RuntimeCoordinate) {\r\n this._coordinate = coordinate.specifyIfUnset({\r\n insId: nanoid(14),\r\n });\r\n this.timeCreated = Date.now();\r\n\r\n this.actionRouter = new ActionRouter({\r\n contextType: EActionRouterContextType.runtime_to_handler,\r\n runtime: this,\r\n });\r\n }\r\n\r\n get coordinate(): RuntimeCoordinate {\r\n return this._coordinate;\r\n }\r\n\r\n specifyRuntimeCoordinate(specifics: IRuntimeCoordinateSpecifics & { envId?: string }): void {\r\n if (specifics.envId != null && this._coordinate.envId !== specifics.envId) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.not_implemented, {\r\n label: `updating RuntimeCoordinate with a different \"envId\" (\"${this._coordinate.envId}\" → \"${specifics.envId}\")`,\r\n });\r\n }\r\n\r\n this._coordinate = this._coordinate.specify(specifics);\r\n this.apply();\r\n }\r\n\r\n registerRunningAction(ra: RunningAction<any, any>): void {\r\n this._pendingRunningActions.set(ra.cuid, ra);\r\n ra.addUpdateListeners([\r\n (update) => {\r\n if (update.type === ERunningActionUpdateType.finished) {\r\n this._pendingRunningActions.delete(ra.cuid);\r\n }\r\n },\r\n ]);\r\n }\r\n\r\n resolveIncomingActionPayload(json: TActionPayload_Any_JsonObject<any, any>): void {\r\n if (json.type === EActionPayloadType.request) {\r\n this.handleActionPayloadWire(json).catch((err) => {\r\n console.error(\r\n `[ActionRuntime] Incoming action [${json.domain}:${json.id}:${json.form}:${json.type}] unhandled:`,\r\n err,\r\n );\r\n });\r\n return;\r\n }\r\n this._pendingRunningActions.get(json.context.cuid)?._resolveFromJson(json as any);\r\n }\r\n\r\n /**\r\n * Handle an incoming action wire (e.g. from a transport layer), route it to\r\n * the correct handler, and return the response. The most specific handler\r\n * match is chosen (action-ID-specific beats domain-wildcard).\r\n */\r\n async handleActionPayloadWire<\r\n D extends IActionDomain,\r\n ID extends keyof D[\"actionSchema\"] & string,\r\n >(wire: TActionPayload_Any_JsonObject<D, ID>): Promise<RunningAction<D, ID>>;\r\n async handleActionPayloadWire(wire: unknown): Promise<RunningAction<any, any>>;\r\n async handleActionPayloadWire(wire: unknown): Promise<RunningAction<any, any>> {\r\n let action: TActionPayload_Any_Instance<any, any> | undefined;\r\n\r\n if (isActionPayload_Any_JsonObject(wire)) {\r\n const domain = this.actionRouter.domainManager.getActionDomainOrThrow(wire);\r\n action = domain.hydrateAnyAction(wire) as TActionPayload_Any_Instance<any, any>;\r\n }\r\n\r\n if (action == null) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.wire_not_action_data);\r\n }\r\n\r\n return this.handleActionPayload(action);\r\n }\r\n\r\n async handleActionPayload<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n >(\r\n action: TActionPayload_Any_Instance<DOM, ID>,\r\n options?: Omit<IHandleActionOptions, \"targetLocalRuntime\">,\r\n ): Promise<RunningAction<DOM, ID>> {\r\n if (action.type === EActionPayloadType.request) {\r\n // This is the inbound entrypoint (server receiving a wire, or a bidirectional\r\n // transport pushing an action to this client). Unlike the local-dispatch path\r\n // (`runAction`), the handler doesn't attach the domain's action observers, so\r\n // wire them on here — otherwise inbound actions never surface in devtools.\r\n const observers = action.context._domain._collectActionObservers();\r\n\r\n let handlerForAction: TActionHandler;\r\n try {\r\n handlerForAction = this.getHandlerForActionOrThrow(action, options);\r\n } catch (err) {\r\n const runningAction = new RunningAction<DOM, ID>({\r\n context: action.context,\r\n request: action,\r\n });\r\n runningAction.addUpdateListeners(observers);\r\n runningAction._completeWithResult(action.errorResult(castNiceError(err) as any));\r\n return runningAction;\r\n }\r\n\r\n const runningAction = await handlerForAction.handleActionRequest(action, {\r\n ...options,\r\n targetLocalRuntime: this,\r\n });\r\n runningAction.addUpdateListeners(observers);\r\n this._trySetupReturnDispatch(runningAction);\r\n return runningAction;\r\n }\r\n\r\n throw err_nice_action.fromId(EErrId_NiceAction.not_implemented, {\r\n label: `Handling incoming action payloads of type \"${action.type}\"`,\r\n });\r\n }\r\n\r\n /**\r\n * @internal\r\n *\r\n * Return the first handler registered for the given action, or `undefined`\r\n * if none has been registered (action-ID-specific beats domain-wildcard).\r\n */\r\n _getHandlerForAction<ACT extends TActionPayload_Any_Instance<any, any>>(\r\n action: ACT,\r\n options?: Omit<IHandleActionOptions, \"targetLocalRuntime\">,\r\n ): TActionHandler | undefined {\r\n const handlers = this.actionRouter.getRouteDataEntriesForAction(action);\r\n const targetPeer = options?.targetPeer;\r\n\r\n const possibleHandlers = handlers.filter((handler) => {\r\n if (handler.handlerType === EActionHandlerType.peer) {\r\n if (targetPeer && !targetPeer.isSameFor(handler.peerClient).id) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n if (targetPeer != null) {\r\n return false;\r\n }\r\n\r\n if (action.type === EActionPayloadType.request) {\r\n return true;\r\n }\r\n\r\n return false;\r\n });\r\n\r\n if (possibleHandlers.length === 0) {\r\n return undefined;\r\n }\r\n\r\n const scoringPeer = targetPeer ?? RuntimeCoordinate.unknown;\r\n\r\n let handlerScore = -1;\r\n let handler: TActionHandler | undefined;\r\n\r\n for (const possibleHandler of possibleHandlers) {\r\n // A local handler always wins over any external one: registering a local handler for an action\r\n // means \"execute it here\" (the \"handle locally if you can, else forward\" pattern, and the path\r\n // by which an inbound push on a bidirectional domain is handled rather than re-forwarded). This\r\n // is independent of registration order — otherwise an external `forDomain` registered first could\r\n // shadow a local handler for the same action.\r\n if (possibleHandler.handlerType === EActionHandlerType.local) {\r\n return possibleHandler;\r\n }\r\n\r\n if (possibleHandler.handlerType === EActionHandlerType.peer) {\r\n const score = scoringPeer.similarityLevel(possibleHandler.peerClient);\r\n if (score > handlerScore) {\r\n handlerScore = score;\r\n handler = possibleHandler;\r\n }\r\n }\r\n }\r\n\r\n return handler;\r\n }\r\n\r\n getHandlerForActionOrThrow<ACT extends TActionPayload_Any_Instance<any, any>>(\r\n action: ACT,\r\n options?: Omit<IHandleActionOptions, \"localRuntime\">,\r\n ): TActionHandler {\r\n const handler = this._getHandlerForAction(action, options);\r\n\r\n if (handler == null) {\r\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\r\n actionId: action.id,\r\n domain: action.domain,\r\n specifiedClient: options?.targetPeer,\r\n });\r\n }\r\n\r\n return handler;\r\n }\r\n\r\n /**\r\n * Register one or more handlers. Each handler's own `actionRouter` defines\r\n * which domains/actions it handles — those routing keys are mirrored into\r\n * this runtime's router so the same action can be served by multiple handlers.\r\n * Duplicate registrations (same handler cuid for the same key) are skipped.\r\n */\r\n addHandlers(handlers: TActionRuntimeHandler[]): this {\r\n for (const handler of handlers) {\r\n if (handler.handlerType === EActionHandlerType.peer) {\r\n handler._setIncomingActionDataListener((json) => this.resolveIncomingActionPayload(json));\r\n this._registeredPeerHandlers.push(handler);\r\n }\r\n\r\n const handlerRouter = handler.getActionRouter();\r\n this.actionRouter.addDomainsFromOther(handlerRouter);\r\n\r\n if (this._applied) {\r\n this.apply();\r\n }\r\n\r\n for (const key of handlerRouter.getRegisteredKeys()) {\r\n const alreadyRegistered = this.actionRouter\r\n .getForKey(key)\r\n .some((h) => h.cuid === handler.cuid);\r\n if (!alreadyRegistered) {\r\n this.actionRouter.addForKey(key, handler);\r\n }\r\n }\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Declare an external \"backend client\" in one call: build an\r\n * {@link ConnectorHandler} for `externalCoordinate` carrying the given\r\n * `transports`, route the listed `domains`/`actions` to it, register it (plus any\r\n * `localHandlers` — e.g. server→client push handlers that share the same channel)\r\n * on this runtime, and `apply()`. Returns the external handler so the caller can\r\n * later `clearTransportCache()` it.\r\n *\r\n * Sugar over `new ConnectorHandler(...).forDomain(...)` + `addHandlers([...])`,\r\n * so a single runtime can host one handler per backend target with its transports\r\n * declared once and reused across every action routed to that backend.\r\n */\r\n connectTo(\r\n externalCoordinate: RuntimeCoordinate,\r\n options: {\r\n transports: Transport[];\r\n domains?: ActionDomain<any>[];\r\n actions?: ActionCore<any, any>[];\r\n localHandlers?: TActionRuntimeHandler[];\r\n defaultTimeout?: number;\r\n },\r\n ): ConnectorHandler {\r\n const handler = new ConnectorHandler({\r\n runtimeCoordinate: externalCoordinate,\r\n transports: options.transports,\r\n defaultTimeout: options.defaultTimeout,\r\n });\r\n\r\n for (const domain of options.domains ?? []) {\r\n handler.forDomain(domain);\r\n }\r\n for (const action of options.actions ?? []) {\r\n handler.forAction(action);\r\n }\r\n\r\n this.addHandlers([handler, ...(options.localHandlers ?? [])]);\r\n this.apply();\r\n\r\n return handler;\r\n }\r\n\r\n private applyRuntimeForDomain(domain: ActionDomain<any>): void {\r\n const rootDomain = domain.rootDomain;\r\n if (!rootDomain._hasRuntime(this)) {\r\n rootDomain._registerRuntime(this);\r\n }\r\n }\r\n\r\n /**\r\n * Register this runtime with all root domains covered by its currently-added handlers,\r\n * making it eligible to execute actions dispatched from those domains.\r\n * After apply() is called, any subsequent addHandlers() calls also auto-register.\r\n */\r\n apply(): this {\r\n this._applied = true;\r\n for (const domain of this.actionRouter.getDomains()) {\r\n this.applyRuntimeForDomain(domain);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Find the best registered external handler that can reach `originClient` directly.\r\n * Used to locate the return-path channel for dispatching results back to the action origin.\r\n * Returns `undefined` if no handler matches (score > 0 required, i.e. at least id must match).\r\n *\r\n * A handler that currently holds the origin's *live* connection always wins over a mere coordinate\r\n * match — so with several duplex acceptors (e.g. WS + WebRTC) a result/push routes back over the carrier\r\n * the client actually connected on, never a same-coordinate sibling that lacks the socket. Only when no\r\n * handler owns a live connection do we fall back to the plain best-coordinate-score pick (the\r\n * single-acceptor and connector-only cases, unchanged).\r\n */\r\n getReturnHandlerForOrigin(originClient: RuntimeCoordinate): PeerLinkHandler | undefined {\r\n if (originClient.envId === UNSET_RUNTIME_ENV_ID) return undefined;\r\n\r\n let bestScore = -1;\r\n let bestHandler: PeerLinkHandler | undefined;\r\n let bestOwnedScore = -1;\r\n let bestOwnedHandler: PeerLinkHandler | undefined;\r\n\r\n for (const handler of this._registeredPeerHandlers) {\r\n // Only a push-capable (duplex) link can deliver an unsolicited result back; an exchange-only\r\n // (HTTP) handler returns its reply inline on the request, so skip it as a return-path candidate.\r\n if (!handler.canPush) continue;\r\n const score = originClient.similarityLevel(handler.peerClient);\r\n if (score > bestScore) {\r\n bestScore = score;\r\n bestHandler = handler;\r\n }\r\n if (score > bestOwnedScore && handler.ownsLiveConnectionFor(originClient)) {\r\n bestOwnedScore = score;\r\n bestOwnedHandler = handler;\r\n }\r\n }\r\n\r\n if (bestOwnedHandler != null && bestOwnedScore > 0) return bestOwnedHandler;\r\n return bestScore > 0 ? bestHandler : undefined;\r\n }\r\n\r\n resetRuntime(): void {\r\n for (const ra of this._pendingRunningActions.values()) {\r\n ra._abort(err_nice_action.fromId(EErrId_NiceAction.runtime_reset));\r\n }\r\n\r\n for (const handler of this._registeredPeerHandlers) {\r\n handler.clearTransportCache();\r\n }\r\n }\r\n\r\n private _trySetupReturnDispatch(runningAction: RunningAction<any, any>): void {\r\n // Fire-and-forget actions get no reply — the sender never waits for one. Skip the return path\r\n // entirely (the inbound push was handled locally; that's the whole contract).\r\n if (runningAction.context.schema.responseMode === EActionResponseMode.none) {\r\n return;\r\n }\r\n\r\n const originClient = runningAction.context.originClient;\r\n\r\n if (\r\n originClient.envId === UNSET_RUNTIME_ENV_ID ||\r\n originClient.isSameFor(this._coordinate).id\r\n ) {\r\n return;\r\n }\r\n\r\n runningAction.addUpdateListeners([\r\n (update) => {\r\n if (\r\n update.type === ERunningActionUpdateType.finished &&\r\n update.finishType === ERunningActionFinishedType.success\r\n ) {\r\n const returnHandler = this.getReturnHandlerForOrigin(originClient);\r\n returnHandler\r\n ?.sendReturnPayload(update.response, { targetLocalRuntime: this })\r\n .catch(() => {});\r\n }\r\n },\r\n ]);\r\n }\r\n}\r\n\r\nconst runtimeState: {\r\n defaultLocalRuntime?: ActionRuntime;\r\n assumedRuntimeInfo?: IRuntimeMeta;\r\n} = {\r\n defaultLocalRuntime: undefined,\r\n assumedRuntimeInfo: undefined,\r\n};\r\n\r\nfunction getDefaultActionRuntime(): ActionRuntime {\r\n if (runtimeState.assumedRuntimeInfo == null) {\r\n runtimeState.assumedRuntimeInfo = getAssumedRuntimeInfo();\r\n }\r\n\r\n if (runtimeState.defaultLocalRuntime == null) {\r\n runtimeState.defaultLocalRuntime = new ActionRuntime(\r\n RuntimeCoordinate.unknown.specify({\r\n perId: `${runtimeState.assumedRuntimeInfo?.runtimeName ?? \"unknown\"}-runtime`,\r\n }),\r\n );\r\n }\r\n\r\n return runtimeState.defaultLocalRuntime;\r\n}\r\n","import { castNiceError, isNiceErrorObject, NiceError } from \"@nice-code/error\";\nimport type { ActionCore } from \"../../../ActionDefinition/Action/Core/ActionCore\";\nimport type { IActionRouteItemHandler } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { ActionPayload_Request } from \"../../../ActionDefinition/Action/Payload/ActionPayload_Request\";\nimport { ActionPayload_Result } from \"../../../ActionDefinition/Action/Payload/ActionPayload_Result\";\nimport { RunningAction } from \"../../../ActionDefinition/Action/RunningAction\";\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\nimport type { IActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../../../errors/err_nice_action\";\nimport { isActionPayload_Result_JsonObject } from \"../../../utils/isActionPayload_Result_JsonObject\";\nimport { ActionRuntime } from \"../../ActionRuntime\";\nimport { peekHandlerCuid, popHandlerCuid, pushHandlerCuid } from \"../../HandlerCallStack\";\nimport { ActionRouter } from \"../../Routing/ActionRouter\";\nimport { EActionRouterContextType } from \"../../Routing/ActionRouter.types\";\nimport { ActionHandler } from \"../ActionHandler\";\nimport {\n EActionHandlerType,\n type IActionHandler_Local,\n type IActionHandler_Local_Json,\n type IHandleActionOptions,\n} from \"../ActionHandler.types\";\nimport type { THandleActionExecutionFn } from \"./ActionLocalHandler.types\";\n\nexport class ActionLocalHandler\n extends ActionHandler<EActionHandlerType.local>\n implements IActionHandler_Local\n{\n readonly handlerType = EActionHandlerType.local;\n readonly actionRouter: ActionRouter<THandleActionExecutionFn<any, any>> = new ActionRouter({\n contextType: EActionRouterContextType.handler_route,\n handler: this,\n });\n\n constructor() {\n super();\n }\n\n /**\n * Register a handler for all actions in a domain.\n * Receives the full primed action — use `matchAction()` to narrow to a specific action id.\n * Useful for forwarding all domain actions to a remote endpoint.\n * Lower priority than `forAction`.\n */\n forDomain<FOR_DOM extends IActionDomain>(\n domain: ActionDomain<FOR_DOM>,\n handler: THandleActionExecutionFn<FOR_DOM>,\n ): this {\n this.actionRouter.forDomain(domain, handler);\n return this;\n }\n\n /**\n * Register a handler for a base action instance. Takes priority over domain-wide handlers.\n * Receives the full primed action with narrowed input type.\n * Useful for handling specific actions locally while forwarding the rest of the domain. For example, a local \"ping\" action that checks connectivity without needing a round trip.\n */\n forAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\n action: ActionCore<ACT_DOM, ID>,\n handler: THandleActionExecutionFn<ACT_DOM, ID>,\n ): this {\n this.actionRouter.forAction(action, handler);\n return this;\n }\n\n /**\n * Register a handler for multiple action IDs (first-match-wins among cases).\n * Receives the full primed action narrowed to the union of those IDs.\n * Use `act.coreAction.id` to branch on which action was dispatched.\n */\n forActionIds<\n ACT_DOM extends IActionDomain,\n IDS extends ReadonlyArray<keyof ACT_DOM[\"actionSchema\"] & string>,\n >(\n domain: ActionDomain<ACT_DOM>,\n ids: IDS,\n handler: THandleActionExecutionFn<ACT_DOM, IDS[number]>,\n ): this {\n this.actionRouter.forActionIds(domain, ids, handler);\n return this;\n }\n\n /**\n * Register per-action handlers for a domain using a single map, without needing\n * separate `forAction` calls. Unregistered action IDs are unaffected.\n *\n * @example\n * ```ts\n * handler.forDomainActionCases(userDomain, {\n * getUser: (primed) => db.getUser(primed.input.userId),\n * deleteUser: (primed) => db.deleteUser(primed.input.userId),\n * });\n * ```\n */\n forDomainActionCases<FOR_DOM extends IActionDomain>(\n domain: ActionDomain<FOR_DOM>,\n cases: {\n [ID in keyof FOR_DOM[\"actionSchema\"] & string]?: THandleActionExecutionFn<FOR_DOM, ID>;\n },\n ): this {\n this.actionRouter.forDomainActionCases(domain, cases);\n return this;\n }\n\n async handleActionRequest<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string,\n >(\n action: ActionPayload_Request<DOM, ID>,\n config?: IHandleActionOptions,\n ): Promise<RunningAction<DOM, ID>> {\n const targetLocalRuntime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();\n\n const handler = this.actionRouter.getRouteDataForActionOrThrow(action, {\n targetLocalRuntime,\n });\n\n action.context.addRouteItem({\n runtime: targetLocalRuntime.coordinate,\n handler: this.toHandlerRouteItem(),\n time: Date.now(),\n });\n\n const runningAction = new RunningAction<DOM, ID>({\n context: action.context,\n request: action,\n parentCuid: peekHandlerCuid(),\n callSite: action._callSite ?? new Error().stack,\n });\n this._handleRunningAction(handler, runningAction).catch((err) => {\n if (err instanceof NiceError) {\n runningAction._completeWithResult(action.errorResult(err as any));\n } else if (isNiceErrorObject(err)) {\n runningAction._completeWithResult(action.errorResult(castNiceError(err) as any));\n } else {\n runningAction._abort(err);\n }\n });\n return runningAction;\n }\n\n private async _handleRunningAction(\n handler: THandleActionExecutionFn<any, any>,\n runningAction: RunningAction<any, any>,\n ) {\n const state = runningAction.state;\n\n if (state.result != null) {\n return;\n }\n\n // Yield before pushing so that sibling actions dispatched in the same synchronous\n // frame have already read their parentCuid (which they do synchronously in\n // handleActionRequest) before we mutate the stack. Without this, a concurrent\n // sibling's peek would see our cuid and incorrectly treat us as its parent.\n // Truly nested child actions (dispatched from inside the handler body below) still\n // see our cuid correctly because the push happens before we call handler().\n await Promise.resolve();\n\n pushHandlerCuid(runningAction.cuid);\n try {\n const rawResult = await handler(state.request);\n let result: ActionPayload_Result<any, any>;\n\n if (rawResult instanceof ActionPayload_Result) {\n result = rawResult;\n } else if (rawResult != null && isActionPayload_Result_JsonObject(rawResult)) {\n const domain = this.actionRouter.domainManager.getActionDomainOrThrow(state.request);\n result = domain.hydrateResultPayload(rawResult);\n } else {\n result = state.request.successResult(rawResult);\n }\n\n runningAction._completeWithResult(result);\n } finally {\n popHandlerCuid();\n }\n }\n\n async handlePayloadWireOrThrow(\n wire: unknown,\n config?: IHandleActionOptions,\n ): Promise<RunningAction<any, any>> {\n const hydratedAction = this.actionRouter.domainManager.hydrateActionPayload(wire as any);\n\n if (!(hydratedAction instanceof ActionPayload_Request)) {\n throw err_nice_action.fromId(EErrId_NiceAction.wire_action_not_payload, {\n domain: hydratedAction.domain,\n actionId: hydratedAction.id,\n actionState: (hydratedAction as any).type ?? (hydratedAction as any).form,\n });\n }\n\n return await this.handleActionRequest(hydratedAction, config);\n }\n\n toJsonObject(): IActionHandler_Local_Json {\n return {\n type: this.handlerType,\n };\n }\n\n toHandlerRouteItem(): IActionRouteItemHandler {\n return {\n type: this.handlerType,\n };\n }\n}\n\nexport const createLocalHandler = () => {\n return new ActionLocalHandler();\n};\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionContext_JsonObject } from \"../ActionDefinition/Action/Context/ActionContext.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isAction_Context_JsonObject = (obj: unknown): obj is IActionContext_JsonObject => {\n return isAction_Base_JsonObject(obj) && obj.form === EActionForm.context;\n};\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionCore_JsonObject } from \"../ActionDefinition/Action/Core/ActionCore.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isAction_Core_JsonObject = (obj: unknown): obj is IActionCore_JsonObject => {\n return isAction_Base_JsonObject(obj) && obj.form === EActionForm.core;\n};\n","import type { TAction_Any_JsonObject } from \"../ActionDefinition/Action/Action.combined.types\";\nimport { isAction_Context_JsonObject } from \"./isAction_Context_JsonObject\";\nimport { isAction_Core_JsonObject } from \"./isAction_Core_JsonObject\";\nimport { isActionPayload_Any_JsonObject } from \"./isActionPayload_Any_JsonObject\";\n\nexport function isAction_Any_JsonObject(obj: unknown): obj is TAction_Any_JsonObject {\n return (\n isActionPayload_Any_JsonObject(obj) ||\n isAction_Context_JsonObject(obj) ||\n isAction_Core_JsonObject(obj)\n );\n}\n","import type { IActionBase_JsonObject } from \"../ActionDefinition/Action/ActionBase.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../errors/err_nice_action\";\nimport { isAction_Any_JsonObject } from \"./isAction_Any_JsonObject\";\n\nexport function assertIsActionJson(obj: unknown): asserts obj is IActionBase_JsonObject {\n if (!isAction_Any_JsonObject(obj)) {\n throw err_nice_action.fromId(EErrId_NiceAction.wire_not_action_data);\n }\n}\n","import type { TAction_Any_Instance } from \"../ActionDefinition/Action/Action.combined.types\";\nimport type { IActionBase } from \"../ActionDefinition/Action/ActionBase.types\";\nimport { ActionContext } from \"../ActionDefinition/Action/Context/ActionContext\";\nimport { ActionCore } from \"../ActionDefinition/Action/Core/ActionCore\";\nimport { ActionPayload } from \"../ActionDefinition/Action/Payload/ActionPayload\";\n\nexport function isAction_Any_Instance<ACT extends IActionBase<any, any>>(\n value: unknown | ACT,\n): value is TAction_Any_Instance<any, any> {\n return (\n value instanceof ActionCore || value instanceof ActionPayload || value instanceof ActionContext\n );\n}\n","import type {\n TDistributeRunningActionUpdateListener,\n TRunningActionUpdateListener,\n} from \"../Action/RunningAction.types\";\nimport type { IActionDomain } from \"./ActionDomain.types\";\n\nexport abstract class ActionDomainBase<ACT_DOM extends IActionDomain = IActionDomain>\n implements IActionDomain<ACT_DOM[\"allDomains\"], ACT_DOM[\"actionSchema\"]>\n{\n readonly domain: ACT_DOM[\"domain\"];\n readonly allDomains: ACT_DOM[\"allDomains\"];\n readonly actionSchema: ACT_DOM[\"actionSchema\"];\n\n protected _listeners: TRunningActionUpdateListener<any, any>[] = [];\n\n constructor(definition: ACT_DOM) {\n this.domain = definition.domain;\n this.allDomains = definition.allDomains;\n this.actionSchema = definition.actionSchema;\n }\n\n /**\n * Add an observer that is called after every action dispatched through this domain.\n * Returns an unsubscribe function — call it to remove the listener.\n */\n addActionListener(\n listener: TDistributeRunningActionUpdateListener<\n ACT_DOM,\n keyof ACT_DOM[\"actionSchema\"] & string\n >,\n ): () => void {\n this._listeners.push(listener as TRunningActionUpdateListener<any, any>);\n return () => {\n this._listeners = this._listeners.filter((l) => l !== listener);\n };\n }\n\n /**\n * @internal\n * Observers registered directly on this domain via {@link addActionListener}.\n * Used to wire observers (e.g. devtools) onto RunningActions that aren't created\n * through the local-dispatch path — notably inbound actions pushed from a backend\n * or another client over a bidirectional transport.\n */\n _getActionObservers(): TRunningActionUpdateListener<any, any>[] {\n return this._listeners;\n }\n}\n","import type { TActionPayload_Any_Instance } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../errors/err_nice_action\";\nimport type { ActionRuntime } from \"./ActionRuntime\";\nimport type { IActionHandlerAndRuntime, IActionRuntimeManagerContext } from \"./ActionRuntime.types\";\nimport type { IHandleActionOptions } from \"./Handler/ActionHandler.types\";\nimport {\n type IRuntimeCoordinate,\n RuntimeCoordinate,\n type TRuntimeCoordinateStringId,\n} from \"./RuntimeCoordinate\";\nimport { runtimeCoordinateToStringIds } from \"./utils/runtimeCoordinateToStringIds\";\n\nexport class ActionRuntimeManager {\n private _runtimes: Map<TRuntimeCoordinateStringId, ActionRuntime> = new Map();\n private _preferredRuntimeClientId: TRuntimeCoordinateStringId | null = null;\n private _context: IActionRuntimeManagerContext;\n\n constructor(context?: IActionRuntimeManagerContext) {\n this._context = context ?? {};\n }\n\n registerRuntime(runtime: ActionRuntime): void {\n const runtimeId = runtime.coordinate.stringId;\n if (this._runtimes.has(runtimeId)) {\n throw err_nice_action.fromId(EErrId_NiceAction.client_runtime_already_registered, {\n context: this._context,\n client: runtime.coordinate,\n });\n }\n\n for (const id of runtime.coordinate.toStringIds()) {\n if (this._runtimes.has(id)) {\n continue;\n }\n\n this._runtimes.set(id, runtime);\n }\n }\n\n getRuntimeAndHandlerForAction(\n action: TActionPayload_Any_Instance<any, any>,\n options?: IHandleActionOptions,\n throwOnIssue?: boolean,\n ): IActionHandlerAndRuntime | undefined {\n const localRuntime = options?.targetLocalRuntime;\n\n if (localRuntime != null) {\n const runtime = throwOnIssue\n ? this.getBestRuntimeOrThrow(options?.targetLocalRuntime?.coordinate)\n : this.getBestRuntime(options?.targetLocalRuntime?.coordinate);\n\n if (runtime == null) {\n return;\n }\n\n const handler = runtime._getHandlerForAction(action, options);\n\n if (handler != null) {\n return { handler, runtime };\n }\n\n if (throwOnIssue) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n specifiedClient: localRuntime.coordinate,\n });\n }\n }\n\n // If no client specified, try to find a runtime that can handle the action\n for (const runtime of this._runtimes.values()) {\n const handler = runtime._getHandlerForAction(action);\n if (handler) {\n return { handler, runtime };\n }\n }\n\n if (throwOnIssue) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n specifiedClient: options?.targetLocalRuntime?.coordinate,\n });\n }\n }\n\n getRuntimeAndHandlerForActionOrThrow(\n action: TActionPayload_Any_Instance<any, any>,\n options?: IHandleActionOptions,\n ): IActionHandlerAndRuntime {\n return this.getRuntimeAndHandlerForAction(action, options, true)!;\n }\n\n setPreferredRuntime(runtime: ActionRuntime): void {\n const runtimeId = runtime.coordinate.stringId;\n this._preferredRuntimeClientId = runtimeId;\n }\n\n getPreferredRuntime(): ActionRuntime | undefined {\n if (this._preferredRuntimeClientId) {\n const runtime = this._runtimes.get(this._preferredRuntimeClientId);\n if (runtime) {\n return runtime;\n }\n }\n return this._runtimes.values().next().value;\n }\n\n getBestRuntimeForSpecifier(clientSpecifier: IRuntimeCoordinate): ActionRuntime | undefined {\n const actionClient = new RuntimeCoordinate(clientSpecifier);\n const ids = actionClient.toStringIds();\n\n for (const id of ids) {\n const runtime = this._runtimes.get(id);\n if (runtime) {\n return runtime;\n }\n }\n }\n\n getBestRuntime(clientSpecifier?: IRuntimeCoordinate): ActionRuntime | undefined {\n return clientSpecifier != null\n ? this.getBestRuntimeForSpecifier(clientSpecifier)\n : this.getPreferredRuntime();\n }\n\n hasRuntime(runtime: ActionRuntime): boolean {\n return this._runtimes.has(runtime.coordinate.stringId);\n }\n\n getBestRuntimeOrThrow(specifier?: IRuntimeCoordinate): ActionRuntime {\n const runtime = this.getBestRuntime(specifier);\n\n if (!runtime) {\n if (specifier == null) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_client_runtimes_registered, {\n context: this._context,\n });\n }\n\n throw err_nice_action.fromId(EErrId_NiceAction.client_runtime_not_registered, {\n context: this._context,\n clientStringId: runtimeCoordinateToStringIds(specifier)[0],\n });\n }\n\n return runtime;\n }\n}\n","import type { ActionRuntime } from \"../../ActionRuntime/ActionRuntime\";\nimport type { IActionHandlerAndRuntime } from \"../../ActionRuntime/ActionRuntime.types\";\nimport { ActionRuntimeManager } from \"../../ActionRuntime/ActionRuntimeManager\";\nimport type { IExecuteActionOptions } from \"../../ActionRuntime/Handler/ActionHandler.types\";\nimport type { IRuntimeCoordinate } from \"../../ActionRuntime/RuntimeCoordinate\";\nimport { EErrId_NiceAction, err_nice_action } from \"../../errors/err_nice_action\";\nimport type { ActionPayload_Request } from \"../Action/Payload/ActionPayload_Request\";\nimport { RunningAction } from \"../Action/RunningAction\";\nimport { ActionDomain } from \"./ActionDomain\";\nimport type {\n IActionDomain,\n IActionDomainChildOptions,\n IActionRootDomain,\n TActionDomainChildDef,\n} from \"./ActionDomain.types\";\nimport { ActionDomainBase } from \"./ActionDomainBase\";\n\nexport class ActionRootDomain<\n ROOT_DOM extends IActionRootDomain = IActionRootDomain,\n> extends ActionDomainBase<ROOT_DOM> {\n private _actionRuntimeManager: ActionRuntimeManager;\n\n constructor(\n readonly domainDefinition: {\n domain: ROOT_DOM[\"domain\"];\n },\n ) {\n const domainId = domainDefinition.domain;\n\n super({\n domain: domainId,\n allDomains: [domainId],\n actionSchema: {},\n } as ROOT_DOM);\n\n this._actionRuntimeManager = new ActionRuntimeManager({ domain: domainId });\n }\n\n createChildDomain<SUB_DOM extends IActionDomainChildOptions>(\n subDomainDef: SUB_DOM & {\n [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never;\n },\n ): ActionDomain<TActionDomainChildDef<ROOT_DOM, SUB_DOM>> {\n if (this.allDomains.includes(subDomainDef.domain)) {\n throw err_nice_action.fromId(EErrId_NiceAction.domain_already_exists_in_hierarchy, {\n domain: subDomainDef.domain,\n allParentDomains: this.allDomains,\n parentDomain: this.domain,\n });\n }\n\n return new ActionDomain<TActionDomainChildDef<ROOT_DOM, SUB_DOM>>(\n {\n allDomains: [...this.allDomains, subDomainDef.domain],\n domain: subDomainDef.domain,\n actionSchema: subDomainDef.actions,\n },\n { rootDomain: this },\n );\n }\n\n _registerRuntime(runtime: ActionRuntime): void {\n this._actionRuntimeManager.registerRuntime(runtime);\n }\n\n _hasRuntime(runtime: ActionRuntime): boolean {\n return this._actionRuntimeManager.hasRuntime(runtime);\n }\n\n getRuntime(clientSpecifier: IRuntimeCoordinate): ActionRuntime | undefined {\n return this._actionRuntimeManager.getBestRuntimeForSpecifier(clientSpecifier);\n }\n\n async _runAction<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n ACT extends ActionPayload_Request<DOM, ID> = ActionPayload_Request<DOM, ID>,\n >(actionPayload: ACT, options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>> {\n const allListeners = [...this._listeners, ...(options?.listeners ?? [])];\n\n let handlerAndRuntime: IActionHandlerAndRuntime;\n try {\n handlerAndRuntime = this._actionRuntimeManager.getRuntimeAndHandlerForActionOrThrow(\n actionPayload,\n options,\n );\n } catch (err) {\n const runningAction = new RunningAction<DOM, ID>({\n context: actionPayload.context,\n request: actionPayload,\n callSite: actionPayload._callSite,\n });\n runningAction.addUpdateListeners(allListeners);\n runningAction._failWithError(err);\n throw err;\n }\n\n const { handler, runtime } = handlerAndRuntime;\n\n actionPayload.context._setOriginClient(runtime.coordinate);\n\n const runningAction = await handler.handleActionRequest(actionPayload, {\n targetLocalRuntime: runtime,\n });\n\n runningAction.addUpdateListeners(allListeners);\n\n return runningAction;\n }\n}\n","import type { ActionRuntime } from \"../../ActionRuntime/ActionRuntime\";\nimport type { IExecuteActionOptions } from \"../../ActionRuntime/Handler/ActionHandler.types\";\nimport { ActionLocalHandler } from \"../../ActionRuntime/Handler/Local/ActionLocalHandler\";\nimport { RuntimeCoordinate } from \"../../ActionRuntime/RuntimeCoordinate\";\nimport { EErrId_NiceAction, err_nice_action } from \"../../errors/err_nice_action\";\nimport { assertIsActionJson } from \"../../utils/assertIsActionJson\";\nimport { isAction_Any_Instance } from \"../../utils/isAction_Any_Instance\";\nimport type {\n TAction_Any_JsonObject,\n TDistributeActionPayload_Request,\n TDistributeActionPayload_Result,\n TDistributedDomainActions,\n TNarrowActionJsonTypeToActionInstanceType,\n} from \"../Action/Action.combined.types\";\nimport { EActionForm, type IActionBase } from \"../Action/ActionBase.types\";\nimport { ActionContext } from \"../Action/Context/ActionContext\";\nimport type { IActionContext_Data_JsonObject } from \"../Action/Context/ActionContext.types\";\nimport { ActionCore } from \"../Action/Core/ActionCore\";\nimport {\n EActionPayloadType,\n type IActionPayload_Request_JsonObject,\n type IActionPayload_Result_JsonObject,\n} from \"../Action/Payload/ActionPayload.types\";\nimport { ActionPayload_Request } from \"../Action/Payload/ActionPayload_Request\";\nimport { ActionPayload_Result } from \"../Action/Payload/ActionPayload_Result\";\nimport type { RunningAction } from \"../Action/RunningAction\";\nimport type { TRunningActionUpdateListener } from \"../Action/RunningAction.types\";\nimport type {\n IActionDomain,\n IActionDomainChildOptions,\n TActionDomainChildDef,\n TWrappableDomainActionHandler,\n} from \"./ActionDomain.types\";\nimport { ActionDomainBase } from \"./ActionDomainBase\";\nimport { type ActionRootDomain } from \"./ActionRootDomain\";\n\ntype TActionMap<ACT_DOM extends IActionDomain> = {\n [K in keyof ACT_DOM[\"actionSchema\"] & string]: ActionCore<ACT_DOM, K>;\n};\n\nexport class ActionDomain<\n ACT_DOM extends IActionDomain = IActionDomain,\n> extends ActionDomainBase<ACT_DOM> {\n private _rootDomain: ActionRootDomain<any>;\n private readonly _actionMap: TActionMap<ACT_DOM>;\n\n constructor(\n definition: ACT_DOM,\n {\n rootDomain,\n }: {\n rootDomain: ActionRootDomain<any>;\n },\n ) {\n super(definition);\n this._rootDomain = rootDomain;\n this._actionMap = this.createActionMap();\n }\n\n get rootDomain() {\n return this._rootDomain;\n }\n\n /**\n * @internal\n * All action observers that should see actions on this domain: the root domain's\n * observers plus this subdomain's own. Mirrors the listener set the local-dispatch\n * path assembles in `runAction`/`_runAction`, so inbound actions (pushed from a\n * backend or another client) can be wired up identically and surface in devtools.\n */\n _collectActionObservers(): TRunningActionUpdateListener<any, any>[] {\n return [...this._rootDomain._getActionObservers(), ...this._getActionObservers()];\n }\n\n _registerRuntime(runtime: ActionRuntime): void {\n this._rootDomain._registerRuntime(runtime);\n }\n\n createChildDomain<SUB_DOM extends IActionDomainChildOptions>(\n subDomainDef: SUB_DOM & {\n [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never;\n },\n ): ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>> {\n if (this.allDomains.includes(subDomainDef.domain)) {\n throw err_nice_action.fromId(EErrId_NiceAction.domain_already_exists_in_hierarchy, {\n domain: subDomainDef.domain,\n allParentDomains: this.allDomains,\n parentDomain: this.domain,\n });\n }\n\n return new ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>>(\n {\n allDomains: [...this.allDomains, subDomainDef.domain],\n domain: subDomainDef.domain,\n actionSchema: subDomainDef.actions,\n },\n { rootDomain: this._rootDomain },\n );\n }\n\n get action(): TActionMap<ACT_DOM> {\n return this._actionMap;\n }\n\n actionsMap(): TActionMap<ACT_DOM> {\n return this._actionMap;\n }\n\n actionForId<ID extends keyof ACT_DOM[\"actionSchema\"] & string>(id: ID): ActionCore<ACT_DOM, ID> {\n const actionSchema = this.actionSchema[id];\n if (!actionSchema) {\n throw err_nice_action.fromId(EErrId_NiceAction.action_id_not_in_domain, {\n domain: this.domain,\n actionId: id as string,\n });\n }\n\n return new ActionCore<ACT_DOM, ID>(this, id);\n }\n\n wrapAsPartialLocalHandler(\n wrappedActionExecutor: Partial<TWrappableDomainActionHandler<ACT_DOM>>,\n ): ActionLocalHandler {\n const _handler = new ActionLocalHandler();\n const executor = wrappedActionExecutor as unknown as Record<string, (input: any) => any>;\n\n for (const actionKey in wrappedActionExecutor) {\n if (!this.actionSchema[actionKey]) {\n continue;\n }\n\n _handler.forAction(this.actionForId(actionKey), (request) =>\n executor[request.id](request.input),\n );\n }\n\n return _handler;\n }\n\n wrapAsLocalHandler(\n wrappedActionExecutor: TWrappableDomainActionHandler<ACT_DOM>,\n ): ActionLocalHandler {\n const _handler = new ActionLocalHandler();\n const executor = wrappedActionExecutor as unknown as Record<string, (input: any) => any>;\n return _handler.forDomain(this, (request) => executor[request.id](request.input));\n }\n\n hydrateContext<ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\n id: ID,\n contextData: IActionContext_Data_JsonObject,\n ): ActionContext<ACT_DOM, ID> {\n return new ActionContext(this, id, {\n timeCreated: contextData.timeCreated,\n cuid: contextData.cuid,\n routing: contextData.routing.map((item) => {\n return {\n runtime: new RuntimeCoordinate(item.runtime),\n handler: item.handler,\n time: item.time,\n };\n }),\n originClient: contextData.originClient\n ? new RuntimeCoordinate(contextData.originClient)\n : RuntimeCoordinate.unknown,\n });\n }\n\n isDomainAction<ACT extends IActionBase<any, ACT_DOM, any>>(\n action: ACT | unknown | null | undefined,\n ): action is TDistributedDomainActions<ACT_DOM, ACT> {\n return isAction_Any_Instance(action) && action.domain === this.domain;\n }\n\n hydrateRequestPayload<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n P extends IActionPayload_Request_JsonObject<ACT_DOM, ID>,\n >(serialized: P): TDistributeActionPayload_Request<ACT_DOM, ID> {\n if (serialized.type !== EActionPayloadType.request) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_state_mismatch, {\n expected: EActionPayloadType.request,\n received: serialized.type,\n });\n }\n\n if (serialized.domain !== this.domain) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_domain_mismatch, {\n expected: this.domain,\n received: serialized.domain,\n });\n }\n\n const id = serialized.id;\n if (!this.actionSchema[id]) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_id_not_found, {\n domain: this.domain,\n actionId: serialized.id,\n });\n }\n\n const contextAction = this.hydrateContext(id, serialized.context);\n\n return new ActionPayload_Request(\n { context: contextAction },\n contextAction.deserializeInput(serialized.input),\n {\n time: serialized.time,\n },\n ) as TDistributeActionPayload_Request<ACT_DOM, ID>;\n }\n\n hydrateResultPayload<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n R extends IActionPayload_Result_JsonObject<ACT_DOM, ID>,\n >(serialized: R): TDistributeActionPayload_Result<ACT_DOM, ID> {\n if (serialized.type !== EActionPayloadType.result) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_state_mismatch, {\n expected: EActionPayloadType.result,\n received: serialized.type,\n });\n }\n\n if (serialized.domain !== this.domain) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_domain_mismatch, {\n expected: this.domain,\n received: serialized.domain,\n });\n }\n\n const id = serialized.id;\n\n if (!this.actionSchema[id]) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_id_not_found, {\n domain: this.domain,\n actionId: serialized.id,\n });\n }\n\n const contextAction = this.hydrateContext(id, serialized.context);\n\n const result = serialized.result.ok\n ? {\n ok: true as const,\n output: contextAction.schema.deserializeOutput(serialized.result.output),\n }\n : serialized.result;\n\n return new ActionPayload_Result({ context: contextAction }, result, {\n time: serialized.time,\n }) as TDistributeActionPayload_Result<ACT_DOM, ID>;\n }\n\n hydrateAnyAction<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n AJ extends TAction_Any_JsonObject<ACT_DOM, ID>,\n >(actionJson: AJ): TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID> {\n assertIsActionJson(actionJson);\n\n if (actionJson.form === EActionForm.data) {\n if (actionJson.type === EActionPayloadType.request) {\n return this.hydrateRequestPayload(\n actionJson,\n ) as unknown as TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;\n }\n\n if (actionJson.type === EActionPayloadType.result) {\n return this.hydrateResultPayload(\n actionJson,\n ) as unknown as TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;\n }\n }\n\n return this.actionForId(actionJson.id) as TNarrowActionJsonTypeToActionInstanceType<\n ACT_DOM,\n AJ,\n ID\n >;\n }\n\n async runAction<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n ACT extends ActionPayload_Request<ACT_DOM, ID>,\n >(\n request: ACT,\n options?: IExecuteActionOptions<ACT_DOM, ID>,\n ): Promise<RunningAction<ACT_DOM, ID>> {\n const allListeners: TRunningActionUpdateListener<any, any>[] = [\n ...(options?.listeners ?? []),\n ...this._listeners,\n ];\n\n return this._rootDomain._runAction(request, {\n ...options,\n listeners: allListeners,\n });\n }\n\n private createActionMap(): {\n [K in keyof ACT_DOM[\"actionSchema\"] & string]: ActionCore<ACT_DOM, K>;\n } {\n const map = {} as {\n [K in keyof ACT_DOM[\"actionSchema\"] & string]: ActionCore<ACT_DOM, K>;\n };\n\n for (const id in this.actionSchema) {\n map[id] = new ActionCore(this, id);\n }\n\n return map;\n }\n}\n","import type { IActionRootDomain } from \"../ActionDomain.types\";\nimport { ActionRootDomain } from \"../ActionRootDomain\";\n\nexport const createActionRootDomain = <ID extends string>(definition: {\n domain: ID;\n}): ActionRootDomain<IActionRootDomain<ID>> => {\n return new ActionRootDomain<IActionRootDomain<ID>>(definition);\n};\n","import {\r\n type ClientCryptoKeyLink,\r\n createTypedStorage,\r\n type StorageAdapter,\r\n type TSerializedCryptoKeyData_Ed25519_Raw,\r\n type TSerializedCryptoKeyData_X25519_Raw,\r\n type TTypeAndId,\r\n} from \"@nice-code/util\";\r\nimport { nanoid } from \"nanoid\";\r\nimport * as v from \"valibot\";\r\nimport { type IRuntimeCoordinate, RuntimeCoordinate } from \"../../RuntimeCoordinate\";\r\n\r\n/**\r\n * Authenticated handshake for the WebSocket channel. Run once per connection, before any action\r\n * frames flow, it:\r\n * - exchanges each side's {@link RuntimeCoordinate} + public keys,\r\n * - checks both ends share the same wire dictionary version (closes the positional-dictionary footgun),\r\n * - has the client prove control of its verify (Ed25519) key by signing a fresh challenge that binds\r\n * both nonces, both identities, the dictionary version, the level, and every exchanged public key,\r\n * - establishes a `ClientCryptoKeyLink` link on both sides (so the server can verify the signature and,\r\n * for the `encrypted` level, both can derive a shared AES-GCM key with the verify keys folded in).\r\n *\r\n * This module is transport-agnostic: it produces/consumes message objects. The transport + server\r\n * handler drive the I/O and the connection phase (Step 4). Keep `none`-level connections from ever\r\n * reaching here — they skip the handshake entirely.\r\n */\r\n\r\nconst HANDSHAKE_PROTOCOL = \"nice-ws-hs/1\";\r\n\r\n/** How much the channel protects after the handshake — chosen by the consumer (perf vs security). */\r\nexport enum ESecurityLevel {\r\n /** No handshake; identity is self-asserted (fastest, dev / trusted networks). */\r\n none = \"none\",\r\n /** Handshake authenticates identity (sign/verify + key pin); frames stay plaintext over TLS. */\r\n authenticated = \"authenticated\",\r\n /** Authenticated handshake + every frame AES-GCM encrypted with the derived shared key. */\r\n encrypted = \"encrypted\",\r\n}\r\n\r\nexport enum EHandshakeMessageType {\r\n hello = \"hello\",\r\n welcome = \"welcome\",\r\n prove = \"prove\",\r\n accept = \"accept\",\r\n reject = \"reject\",\r\n}\r\n\r\n// --- wire message schemas (these arrive untrusted from the network) --------------------------------\r\n\r\nconst vEd25519Raw = v.custom<TSerializedCryptoKeyData_Ed25519_Raw>(\r\n (val) => typeof val === \"string\" && val.startsWith(\"ed25519::raw_base64::\"),\r\n);\r\nconst vX25519Raw = v.custom<TSerializedCryptoKeyData_X25519_Raw>(\r\n (val) => typeof val === \"string\" && val.startsWith(\"x25519::raw_base64::\"),\r\n);\r\nconst vCoordinate = v.object({\r\n envId: v.string(),\r\n perId: v.optional(v.string()),\r\n insId: v.optional(v.string()),\r\n});\r\nconst vSecurityLevel = v.picklist([\r\n ESecurityLevel.none,\r\n ESecurityLevel.authenticated,\r\n ESecurityLevel.encrypted,\r\n]);\r\n\r\nconst vHsHello = v.object({\r\n t: v.literal(EHandshakeMessageType.hello),\r\n protocol: v.string(),\r\n securityLevel: vSecurityLevel,\r\n dictionaryVersion: v.string(),\r\n client: vCoordinate,\r\n clientNonce: v.string(),\r\n verifyPublicKey: vEd25519Raw,\r\n exchangePublicKey: v.optional(vX25519Raw),\r\n});\r\n\r\nconst vHsWelcome = v.object({\r\n t: v.literal(EHandshakeMessageType.welcome),\r\n securityLevel: vSecurityLevel,\r\n dictionaryVersion: v.string(),\r\n server: vCoordinate,\r\n serverNonce: v.string(),\r\n verifyPublicKey: vEd25519Raw,\r\n exchangePublicKey: v.optional(vX25519Raw),\r\n});\r\n\r\nconst vHsProve = v.object({\r\n t: v.literal(EHandshakeMessageType.prove),\r\n signatureBase64: v.string(),\r\n});\r\n\r\nconst vHsAccept = v.object({\r\n t: v.literal(EHandshakeMessageType.accept),\r\n signatureBase64: v.optional(v.string()),\r\n});\r\n\r\nconst vHsReject = v.object({\r\n t: v.literal(EHandshakeMessageType.reject),\r\n reason: v.string(),\r\n});\r\n\r\nconst vHandshakeMessage = v.variant(\"t\", [vHsHello, vHsWelcome, vHsProve, vHsAccept, vHsReject]);\r\n\r\nexport type THsHello = v.InferOutput<typeof vHsHello>;\r\nexport type THsWelcome = v.InferOutput<typeof vHsWelcome>;\r\nexport type THsProve = v.InferOutput<typeof vHsProve>;\r\nexport type THsAccept = v.InferOutput<typeof vHsAccept>;\r\nexport type THsReject = v.InferOutput<typeof vHsReject>;\r\nexport type THandshakeMessage = v.InferOutput<typeof vHandshakeMessage>;\r\n\r\n/** Serialize a handshake message for the wire (handshake frames are JSON — they aren't the hot path). */\r\nexport function encodeHandshakeMessage(message: THandshakeMessage): string {\r\n return JSON.stringify(message);\r\n}\r\n\r\n/** Parse + structurally validate an incoming handshake frame; `undefined` if it isn't one. */\r\nexport function decodeHandshakeMessage(raw: string): THandshakeMessage | undefined {\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n return undefined;\r\n }\r\n const result = v.safeParse(vHandshakeMessage, parsed);\r\n return result.success ? result.output : undefined;\r\n}\r\n\r\n// --- helpers ---------------------------------------------------------------------------------------\r\n\r\n/** Stable link id for a runtime coordinate — the key both the crypto link and the connection use. */\r\nexport function runtimeLinkId(coordinate: IRuntimeCoordinate): TTypeAndId {\r\n return `runtime::${new RuntimeCoordinate(coordinate).stringId}`;\r\n}\r\n\r\nfunction coordId(coordinate: IRuntimeCoordinate): string {\r\n return new RuntimeCoordinate(coordinate).stringId;\r\n}\r\n\r\nfunction sessionSalt(clientNonce: string, serverNonce: string): string {\r\n return `${clientNonce}::${serverNonce}`;\r\n}\r\n\r\nfunction handshakeInfo(dictionaryVersion: string): string {\r\n return `${HANDSHAKE_PROTOCOL}::${dictionaryVersion}`;\r\n}\r\n\r\n/**\r\n * The exact string both sides sign/verify. JSON-encoded ordered array so field boundaries are\r\n * unambiguous; binds identities, nonces (freshness), version, level, and all exchanged public keys\r\n * (authenticating the keys via the signature, complementing `bindVerifyKeysIntoDerivation`).\r\n */\r\nfunction buildHandshakeChallenge(parts: {\r\n securityLevel: ESecurityLevel;\r\n dictionaryVersion: string;\r\n clientCoordId: string;\r\n serverCoordId: string;\r\n clientNonce: string;\r\n serverNonce: string;\r\n clientVerifyKey: string;\r\n serverVerifyKey: string;\r\n clientExchangeKey?: string;\r\n serverExchangeKey?: string;\r\n}): string {\r\n return JSON.stringify([\r\n HANDSHAKE_PROTOCOL,\r\n parts.securityLevel,\r\n parts.dictionaryVersion,\r\n parts.clientCoordId,\r\n parts.serverCoordId,\r\n parts.clientNonce,\r\n parts.serverNonce,\r\n parts.clientVerifyKey,\r\n parts.serverVerifyKey,\r\n parts.clientExchangeKey ?? \"_\",\r\n parts.serverExchangeKey ?? \"_\",\r\n ]);\r\n}\r\n\r\nfunction reject(reason: string): THsReject {\r\n return { t: EHandshakeMessageType.reject, reason };\r\n}\r\n\r\n/**\r\n * Everything needed to re-derive the shared AES-GCM key for an `encrypted` link after a restart —\r\n * the remote's public keys + the HKDF salt/info used at handshake time. The local (server) key pair is\r\n * recovered from its own persisted `ClientCryptoKeyLink` storage, so re-linking with this material\r\n * yields the identical shared key without a fresh handshake.\r\n */\r\nexport interface IHandshakeEncryptionKeyMaterial {\r\n verifyPublicKey: TSerializedCryptoKeyData_Ed25519_Raw;\r\n exchangePublicKey: TSerializedCryptoKeyData_X25519_Raw;\r\n saltString: string;\r\n infoString: string;\r\n bindVerifyKeysIntoDerivation: boolean;\r\n}\r\n\r\n/** Outcome of a completed handshake — what the transport/handler needs to wire the channel. */\r\nexport interface IHandshakeResult {\r\n /** The crypto-link id (and connection-registry key) for the authenticated remote. */\r\n linkedClientId: TTypeAndId;\r\n /** The remote's authenticated coordinate. */\r\n remote: IRuntimeCoordinate;\r\n securityLevel: ESecurityLevel;\r\n /** For the `encrypted` level: material to restore the shared key after eviction (persist it). */\r\n encryptionKeyMaterial?: IHandshakeEncryptionKeyMaterial;\r\n}\r\n\r\n// --- pluggable trust (TOFU now, pre-provisioned later) ---------------------------------------------\r\n\r\nexport interface IClientVerifyKeyResolveInput {\r\n client: IRuntimeCoordinate;\r\n verifyPublicKey: TSerializedCryptoKeyData_Ed25519_Raw;\r\n}\r\n\r\nexport interface IClientVerifyKeyResolver {\r\n /**\r\n * Decide whether a presented verify key is trusted for a client identity. The signature is already\r\n * verified by the time this runs, so this is purely the identity-pinning decision. Swap in a\r\n * persistent / pre-provisioned implementation without touching the protocol.\r\n */\r\n resolve(input: IClientVerifyKeyResolveInput): Promise<{ trusted: boolean; reason?: string }>;\r\n}\r\n\r\nfunction tofuPinKey(client: IRuntimeCoordinate): string {\r\n // Pin to the persistent identity (perId) so a client may reconnect with new instances (insId),\r\n // but a changed verify key for the same persistent identity is rejected.\r\n return `${client.envId}::${client.perId ?? client.insId ?? \"_\"}`;\r\n}\r\n\r\n/**\r\n * In-memory trust-on-first-use resolver: trusts (and pins) the first verify key seen for a client\r\n * identity, then rejects a different key for that identity. The default; replace with a storage-backed\r\n * resolver for cross-restart pinning (see Step 5).\r\n */\r\nexport function createInMemoryTofuVerifyKeyResolver(): IClientVerifyKeyResolver {\r\n const pinned = new Map<string, string>();\r\n return {\r\n async resolve({ client, verifyPublicKey }) {\r\n const key = tofuPinKey(client);\r\n const existing = pinned.get(key);\r\n if (existing == null) {\r\n pinned.set(key, verifyPublicKey);\r\n return { trusted: true };\r\n }\r\n if (existing === verifyPublicKey) return { trusted: true };\r\n return { trusted: false, reason: \"verify key changed for client identity (pin mismatch)\" };\r\n },\r\n };\r\n}\r\n\r\ninterface ITofuPinStorage {\r\n pins: Record<string, TSerializedCryptoKeyData_Ed25519_Raw>;\r\n}\r\n\r\n/**\r\n * Storage-backed trust-on-first-use resolver: pins survive process restarts / Durable Object eviction\r\n * (e.g. back it with `createDurableObjectStorageAdapter`). Same policy as the in-memory variant — trust\r\n * + pin the first verify key per client identity, reject a different one thereafter.\r\n */\r\nexport function createStorageTofuVerifyKeyResolver(\r\n storageAdapter: StorageAdapter,\r\n): IClientVerifyKeyResolver {\r\n const storage = createTypedStorage<ITofuPinStorage>({ storageAdapter });\r\n return {\r\n async resolve({ client, verifyPublicKey }) {\r\n const key = tofuPinKey(client);\r\n const existing = (await storage.getJson(\"pins\"))?.[key];\r\n if (existing == null) {\r\n await storage.updateJsonWithDef(\"pins\", {}, (current) => ({\r\n ...current,\r\n [key]: verifyPublicKey,\r\n }));\r\n return { trusted: true };\r\n }\r\n if (existing === verifyPublicKey) return { trusted: true };\r\n return { trusted: false, reason: \"verify key changed for client identity (pin mismatch)\" };\r\n },\r\n };\r\n}\r\n\r\n// --- client side -----------------------------------------------------------------------------------\r\n\r\nexport interface IClientHandshakeConfig {\r\n link: ClientCryptoKeyLink;\r\n localCoordinate: IRuntimeCoordinate;\r\n dictionaryVersion: string;\r\n securityLevel: ESecurityLevel;\r\n}\r\n\r\nexport function createClientHandshake(config: IClientHandshakeConfig) {\r\n const { link, localCoordinate, dictionaryVersion, securityLevel } = config;\r\n const wantsEncryption = securityLevel === ESecurityLevel.encrypted;\r\n const clientNonce = nanoid();\r\n\r\n let pending:\r\n | { linkedServerId: TTypeAndId; server: IRuntimeCoordinate; challenge: string }\r\n | undefined;\r\n\r\n return {\r\n async createHello(): Promise<THsHello> {\r\n return {\r\n t: EHandshakeMessageType.hello,\r\n protocol: HANDSHAKE_PROTOCOL,\r\n securityLevel,\r\n dictionaryVersion,\r\n client: localCoordinate,\r\n clientNonce,\r\n verifyPublicKey: await link.getLocalVerifyPublicKey(),\r\n exchangePublicKey: wantsEncryption ? await link.getLocalExchangePublicKey() : undefined,\r\n };\r\n },\r\n\r\n async onWelcome(welcome: THsWelcome): Promise<THsProve> {\r\n if (welcome.dictionaryVersion !== dictionaryVersion) {\r\n throw new Error(\"[ws-handshake] server dictionary version mismatch\");\r\n }\r\n if (welcome.securityLevel !== securityLevel) {\r\n throw new Error(\"[ws-handshake] server security level mismatch\");\r\n }\r\n if (wantsEncryption && welcome.exchangePublicKey == null) {\r\n throw new Error(\"[ws-handshake] server did not provide an exchange key for encryption\");\r\n }\r\n\r\n const linkedServerId = runtimeLinkId(welcome.server);\r\n await link.linkClient({\r\n linkedClientId: linkedServerId,\r\n verifyPublicKey: welcome.verifyPublicKey,\r\n // Salt/info/exchange only matter for the encrypted level's shared-key derivation; the\r\n // authenticated level links the verify key alone (passing salt without an exchange key throws).\r\n ...(wantsEncryption\r\n ? {\r\n exchangePublicKey: welcome.exchangePublicKey,\r\n saltString: sessionSalt(clientNonce, welcome.serverNonce),\r\n infoString: handshakeInfo(dictionaryVersion),\r\n bindVerifyKeysIntoDerivation: true,\r\n }\r\n : {}),\r\n });\r\n\r\n const challenge = buildHandshakeChallenge({\r\n securityLevel,\r\n dictionaryVersion,\r\n clientCoordId: coordId(localCoordinate),\r\n serverCoordId: coordId(welcome.server),\r\n clientNonce,\r\n serverNonce: welcome.serverNonce,\r\n clientVerifyKey: await link.getLocalVerifyPublicKey(),\r\n serverVerifyKey: welcome.verifyPublicKey,\r\n clientExchangeKey: wantsEncryption ? await link.getLocalExchangePublicKey() : undefined,\r\n serverExchangeKey: welcome.exchangePublicKey,\r\n });\r\n\r\n pending = { linkedServerId, server: welcome.server, challenge };\r\n return {\r\n t: EHandshakeMessageType.prove,\r\n signatureBase64: (await link.signChallenge([challenge])).signatureBase64,\r\n };\r\n },\r\n\r\n async onAccept(accept: THsAccept): Promise<IHandshakeResult> {\r\n if (pending == null) throw new Error(\"[ws-handshake] accept before welcome\");\r\n\r\n // Optional mutual auth: confirm the server signed the same challenge (liveness over TLS).\r\n if (accept.signatureBase64 != null) {\r\n const valid = await link.verifyChallengeFromLinkedClient({\r\n linkedClientId: pending.linkedServerId,\r\n challenge: pending.challenge,\r\n signatureBase64: accept.signatureBase64,\r\n });\r\n if (!valid) throw new Error(\"[ws-handshake] server signature invalid\");\r\n }\r\n\r\n return { linkedClientId: pending.linkedServerId, remote: pending.server, securityLevel };\r\n },\r\n };\r\n}\r\n\r\n// --- server side -----------------------------------------------------------------------------------\r\n\r\nexport interface IServerHandshakeConfig {\r\n link: ClientCryptoKeyLink;\r\n localCoordinate: IRuntimeCoordinate;\r\n dictionaryVersion: string;\r\n /**\r\n * The level(s) this server accepts. A single level is strict (the client must match). An array is a\r\n * negotiable allowed set — the server adopts whichever level the client requests, as long as it's in\r\n * the set (lets one backend serve `authenticated` and `encrypted` clients at once). `none` in the set\r\n * is handled by the transport/handler (a `none` client never reaches the handshake).\r\n */\r\n securityLevel: ESecurityLevel | readonly ESecurityLevel[];\r\n /** Trust decision for a client's verify key. Defaults to in-memory TOFU. */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n}\r\n\r\nexport function createServerHandshake(config: IServerHandshakeConfig) {\r\n const { link, localCoordinate, dictionaryVersion } = config;\r\n const allowedLevels = Array.isArray(config.securityLevel)\r\n ? config.securityLevel\r\n : [config.securityLevel];\r\n const verifyKeyResolver = config.verifyKeyResolver ?? createInMemoryTofuVerifyKeyResolver();\r\n const serverNonce = nanoid();\r\n\r\n let pending:\r\n | {\r\n client: IRuntimeCoordinate;\r\n linkedClientId: TTypeAndId;\r\n challenge: string;\r\n clientVerifyKey: TSerializedCryptoKeyData_Ed25519_Raw;\r\n negotiatedLevel: ESecurityLevel;\r\n keyMaterial?: IHandshakeEncryptionKeyMaterial;\r\n }\r\n | undefined;\r\n let result: IHandshakeResult | undefined;\r\n\r\n return {\r\n async onHello(hello: THsHello): Promise<THsWelcome | THsReject> {\r\n if (hello.protocol !== HANDSHAKE_PROTOCOL) return reject(\"unsupported handshake protocol\");\r\n if (hello.dictionaryVersion !== dictionaryVersion)\r\n return reject(\"dictionary version mismatch\");\r\n\r\n // Negotiate: adopt the client's requested level if this server allows it. `none` never\r\n // handshakes, so it's not a valid negotiated level here.\r\n const negotiatedLevel = hello.securityLevel;\r\n if (negotiatedLevel === ESecurityLevel.none || !allowedLevels.includes(negotiatedLevel)) {\r\n return reject(\"security level not allowed\");\r\n }\r\n const wantsEncryption = negotiatedLevel === ESecurityLevel.encrypted;\r\n if (wantsEncryption && hello.exchangePublicKey == null) {\r\n return reject(\"missing exchange key for encryption\");\r\n }\r\n\r\n const linkedClientId = runtimeLinkId(hello.client);\r\n await link.linkClient({\r\n linkedClientId,\r\n verifyPublicKey: hello.verifyPublicKey,\r\n // See client side: only the encrypted level needs the exchange key + HKDF salt/info.\r\n ...(wantsEncryption\r\n ? {\r\n exchangePublicKey: hello.exchangePublicKey,\r\n saltString: sessionSalt(hello.clientNonce, serverNonce),\r\n infoString: handshakeInfo(dictionaryVersion),\r\n bindVerifyKeysIntoDerivation: true,\r\n }\r\n : {}),\r\n });\r\n\r\n const serverVerifyKey = await link.getLocalVerifyPublicKey();\r\n const serverExchangeKey = wantsEncryption\r\n ? await link.getLocalExchangePublicKey()\r\n : undefined;\r\n\r\n const keyMaterial: IHandshakeEncryptionKeyMaterial | undefined =\r\n wantsEncryption && hello.exchangePublicKey != null\r\n ? {\r\n verifyPublicKey: hello.verifyPublicKey,\r\n exchangePublicKey: hello.exchangePublicKey,\r\n saltString: sessionSalt(hello.clientNonce, serverNonce),\r\n infoString: handshakeInfo(dictionaryVersion),\r\n bindVerifyKeysIntoDerivation: true,\r\n }\r\n : undefined;\r\n\r\n pending = {\r\n client: hello.client,\r\n linkedClientId,\r\n clientVerifyKey: hello.verifyPublicKey,\r\n negotiatedLevel,\r\n keyMaterial,\r\n challenge: buildHandshakeChallenge({\r\n securityLevel: negotiatedLevel,\r\n dictionaryVersion,\r\n clientCoordId: coordId(hello.client),\r\n serverCoordId: coordId(localCoordinate),\r\n clientNonce: hello.clientNonce,\r\n serverNonce,\r\n clientVerifyKey: hello.verifyPublicKey,\r\n serverVerifyKey,\r\n clientExchangeKey: hello.exchangePublicKey,\r\n serverExchangeKey,\r\n }),\r\n };\r\n\r\n return {\r\n t: EHandshakeMessageType.welcome,\r\n securityLevel: negotiatedLevel,\r\n dictionaryVersion,\r\n server: localCoordinate,\r\n serverNonce,\r\n verifyPublicKey: serverVerifyKey,\r\n exchangePublicKey: serverExchangeKey,\r\n };\r\n },\r\n\r\n async onProve(prove: THsProve): Promise<THsAccept | THsReject> {\r\n if (pending == null) return reject(\"prove before hello\");\r\n\r\n const signatureValid = await link.verifyChallengeFromLinkedClient({\r\n linkedClientId: pending.linkedClientId,\r\n challenge: pending.challenge,\r\n signatureBase64: prove.signatureBase64,\r\n });\r\n if (!signatureValid) return reject(\"invalid client signature\");\r\n\r\n const trust = await verifyKeyResolver.resolve({\r\n client: pending.client,\r\n verifyPublicKey: pending.clientVerifyKey,\r\n });\r\n if (!trust.trusted) return reject(trust.reason ?? \"client verify key not trusted\");\r\n\r\n result = {\r\n linkedClientId: pending.linkedClientId,\r\n remote: pending.client,\r\n securityLevel: pending.negotiatedLevel,\r\n encryptionKeyMaterial: pending.keyMaterial,\r\n };\r\n\r\n // Sign the same challenge back so the client can confirm server liveness (mutual auth).\r\n return {\r\n t: EHandshakeMessageType.accept,\r\n signatureBase64: (await link.signChallenge([pending.challenge])).signatureBase64,\r\n };\r\n },\r\n\r\n /** The completed handshake result once `onProve` has accepted, else `undefined`. */\r\n getResult(): IHandshakeResult | undefined {\r\n return result;\r\n },\r\n };\r\n}\r\n","import type { TActionPayload_Any_JsonObject } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport { isActionPayload_Any_JsonObject } from \"./isActionPayload_Any_JsonObject\";\r\n\r\n/**\r\n * Minimal codec shape needed to turn an incoming channel frame back into action wire JSON. Matches\r\n * the `formatMessage` object the WebSocket transport (and `createBinaryWireAdapter`) provide.\r\n */\r\nexport interface IActionFrameDecoder {\r\n incoming?: (\r\n frame: string | ArrayBuffer | Uint8Array | Blob,\r\n ) => TActionPayload_Any_JsonObject<any, any> | undefined;\r\n}\r\n\r\n/**\r\n * Decode a single inbound channel frame (text or binary) into validated action wire JSON, or\r\n * `undefined` if it isn't a recognisable action payload.\r\n *\r\n * Shared by the WebSocket transport's message listener and the server-side `AcceptorHandler` so\r\n * both decode identically: a binary `decoder.incoming` (e.g. msgpackr) takes precedence, and plain\r\n * text frames fall back to JSON — keeping binary and JSON clients interoperable on one channel.\r\n */\r\nexport function decodeActionFrame(\r\n frame: string | ArrayBuffer | Uint8Array,\r\n decoder?: IActionFrameDecoder,\r\n): TActionPayload_Any_JsonObject<any, any> | undefined {\r\n const decoded =\r\n decoder?.incoming?.(frame) ??\r\n (typeof frame === \"string\" ? parseJsonActionFrame(frame) : undefined);\r\n\r\n return decoded != null && isActionPayload_Any_JsonObject(decoded) ? decoded : undefined;\r\n}\r\n\r\nfunction parseJsonActionFrame(\r\n message: string,\r\n): TActionPayload_Any_JsonObject<any, any> | undefined {\r\n try {\r\n const json = JSON.parse(message);\r\n return isActionPayload_Any_JsonObject(json) ? json : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n","import type { ClientCryptoKeyLink, TTypeAndId } from \"@nice-code/util\";\r\nimport { pack, unpack } from \"msgpackr\";\r\n\r\n/**\r\n * Async AES-GCM transform for the `encrypted` security level. It wraps the opaque binary frame a\r\n * session codec produces (it does NOT look inside it), encrypting on the way out and decrypting on the\r\n * way in with the shared key established by the handshake.\r\n *\r\n * It is deliberately separate from the (synchronous) session `formatMessage`: WebCrypto is always\r\n * Promise-based, so encryption has to happen at the transport's async I/O boundary — the connection\r\n * encrypts after `session.outgoing()` and decrypts before `session.incoming()`. The `authenticated`\r\n * and `none` levels use no crypto transform at all (frames go out as the session produced them).\r\n *\r\n * Wire shape of an encrypted frame: `pack([nonceBytes, ciphertextBytes])` — msgpack carries the two\r\n * binary fields with a couple of bytes of overhead, no base64 inflation.\r\n */\r\nexport interface IActionFrameCrypto {\r\n /** Encrypt one session frame for sending. */\r\n encryptFrame(frame: Uint8Array): Promise<Uint8Array>;\r\n /** Decrypt one received frame back to the session frame. Throws on a non-binary / malformed /\r\n * tampered frame — the caller (transport) decides how to react (drop / close). */\r\n decryptFrame(frame: string | ArrayBuffer | Uint8Array): Promise<Uint8Array>;\r\n}\r\n\r\nexport interface IActionFrameCryptoConfig {\r\n link: ClientCryptoKeyLink;\r\n /** The handshake-established link id for the remote (key + connection-registry id). */\r\n linkedClientId: TTypeAndId;\r\n}\r\n\r\nconst ENCRYPTED_ENVELOPE_LENGTH = 2;\r\n\r\n/**\r\n * Build the encrypt/decrypt transform for a connection whose handshake settled on the `encrypted`\r\n * level. Keyed by the link + `linkedClientId`, so it reuses the cached shared AES-GCM key.\r\n */\r\nexport function createActionFrameCrypto({\r\n link,\r\n linkedClientId,\r\n}: IActionFrameCryptoConfig): IActionFrameCrypto {\r\n return {\r\n async encryptFrame(frame: Uint8Array): Promise<Uint8Array> {\r\n const { nonce, ciphertext } = await link.encryptBytesForLinkedClient({\r\n linkedClientId,\r\n dataToEncrypt: frame,\r\n });\r\n return pack([nonce, ciphertext]);\r\n },\r\n\r\n async decryptFrame(frame: string | ArrayBuffer | Uint8Array): Promise<Uint8Array> {\r\n if (typeof frame === \"string\") {\r\n throw new Error(\"[ws-crypto] expected an encrypted binary frame, received text\");\r\n }\r\n\r\n const buffer = frame instanceof ArrayBuffer ? new Uint8Array(frame) : frame;\r\n const envelope = unpack(buffer);\r\n if (!Array.isArray(envelope) || envelope.length !== ENCRYPTED_ENVELOPE_LENGTH) {\r\n throw new Error(\"[ws-crypto] malformed encrypted frame envelope\");\r\n }\r\n\r\n const [nonce, ciphertext] = envelope;\r\n if (!(nonce instanceof Uint8Array) || !(ciphertext instanceof Uint8Array)) {\r\n throw new Error(\"[ws-crypto] malformed encrypted frame fields\");\r\n }\r\n\r\n // AES-GCM verifies integrity — a tampered ciphertext throws here.\r\n return await link.decryptBytesFromLinkedClient({\r\n linkedClientId,\r\n dataToDecrypt: { nonce, ciphertext },\r\n });\r\n },\r\n };\r\n}\r\n","import type { TFrame } from \"../Carrier/Carrier.types\";\r\n\r\n/** Normalize any frame form to bytes (for the AES-GCM layer, which works on `Uint8Array`). */\r\nexport function toFrameBytes(frame: TFrame): Uint8Array {\r\n if (typeof frame === \"string\") return new TextEncoder().encode(frame);\r\n if (frame instanceof ArrayBuffer) return new Uint8Array(frame);\r\n return frame;\r\n}\r\n","import type { TFrame } from \"../Carrier/Carrier.types\";\r\nimport type { IActionFrameCrypto } from \"../crypto/actionFrameCrypto\";\r\nimport { toFrameBytes } from \"../crypto/frameBytes\";\r\n\r\n/**\r\n * Ordered frame crypto over a single channel/connection — the one place the encrypt-on-send /\r\n * decrypt-on-receive logic lives, shared by both link roles:\r\n *\r\n * - the **connector** (one carrier, one crypto) — see `establishLinkSession`;\r\n * - the **acceptor** (one per accepted connection, crypto re-derived asynchronously after a hibernation\r\n * wake) — see `AcceptorHandler`.\r\n *\r\n * Outbound frames go on an ordered chain so async AES-GCM never reorders them, and the chain gates once\r\n * on `crypto` — which, when `crypto` is a promise, also gates the first send on the post-wake key\r\n * re-derivation. With no `crypto` it's a plaintext passthrough.\r\n */\r\nexport interface IFrameCryptoPipe {\r\n /** Encrypt (if secured) and write `frame`, preserving dispatch order. Dropped if `isOpen` is false. */\r\n send(frame: TFrame): void;\r\n /** Decrypt an inbound frame; resolves `undefined` (frame dropped) if decryption fails. */\r\n decryptIncoming(frame: TFrame): Promise<TFrame | undefined>;\r\n}\r\n\r\nexport interface IFrameCryptoPipeConfig {\r\n /** Raw frame writer — the carrier's `send`, or the acceptor's per-connection send. */\r\n write: (frame: TFrame) => void;\r\n /** Optional synchronous open-guard; when it returns `false`, sends are dropped (a closed carrier). */\r\n isOpen?: () => boolean;\r\n /**\r\n * The AES-GCM transform, or a promise of it. `undefined` ⇒ plaintext passthrough. A promise lets the\r\n * acceptor gate the connection's first frame on an async key re-derivation after a hibernation wake.\r\n */\r\n crypto?: IActionFrameCrypto | Promise<IActionFrameCrypto>;\r\n /** Short label for the encrypt/decrypt failure logs (e.g. `\"link\"`, `\"ws-server\"`). */\r\n label?: string;\r\n}\r\n\r\nexport function createFrameCryptoPipe(config: IFrameCryptoPipeConfig): IFrameCryptoPipe {\r\n const { write, isOpen, crypto, label = \"link\" } = config;\r\n\r\n // Ordered send chain: async encryption must keep frames in dispatch order.\r\n let sendChain: Promise<void> = Promise.resolve();\r\n\r\n const send = (frame: TFrame): void => {\r\n if (isOpen != null && !isOpen()) return;\r\n if (crypto == null) {\r\n write(frame);\r\n return;\r\n }\r\n const bytes = toFrameBytes(frame);\r\n sendChain = sendChain\r\n .then(() => crypto)\r\n .then((c) => c.encryptFrame(bytes))\r\n .then((encrypted) => {\r\n if (isOpen == null || isOpen()) write(encrypted);\r\n })\r\n .catch((err) => console.error(`[${label}] failed to encrypt/send frame`, err));\r\n };\r\n\r\n const decryptIncoming = async (frame: TFrame): Promise<TFrame | undefined> => {\r\n if (crypto == null) return frame;\r\n try {\r\n return await (await crypto).decryptFrame(frame);\r\n } catch (err) {\r\n console.error(`[${label}] failed to decrypt incoming frame`, err);\r\n return undefined;\r\n }\r\n };\r\n\r\n return { send, decryptIncoming };\r\n}\r\n","import type { ClientCryptoKeyLink, TTypeAndId } from \"@nice-code/util\";\r\nimport { type IRuntimeCoordinate, RuntimeCoordinate } from \"../../RuntimeCoordinate\";\r\nimport type { TFrame } from \"../Carrier/Carrier.types\";\r\nimport { createActionFrameCrypto } from \"../crypto/actionFrameCrypto\";\r\nimport {\r\n createServerHandshake,\r\n decodeHandshakeMessage,\r\n EHandshakeMessageType,\r\n ESecurityLevel,\r\n encodeHandshakeMessage,\r\n type IClientVerifyKeyResolver,\r\n type IHandshakeEncryptionKeyMaterial,\r\n type IHandshakeResult,\r\n} from \"../crypto/actionHandshake\";\r\nimport { createFrameCryptoPipe, type IFrameCryptoPipe } from \"./frameCryptoPipe\";\r\n\r\n/** What the handshake authenticated — the handler binds this identity + persists it for resumption. */\r\nexport interface IAcceptorAuthResult {\r\n /** The peer's *authenticated* coordinate — the only identity inbound frames are bound to. */\r\n client: RuntimeCoordinate;\r\n securityLevel: ESecurityLevel;\r\n linkedClientId: TTypeAndId;\r\n /** Present at the `encrypted` level — persist it so an evicted connection re-derives its key. */\r\n keyMaterial?: IHandshakeEncryptionKeyMaterial;\r\n}\r\n\r\n/** The persisted secure state replayed to resume an authenticated connection after eviction. */\r\nexport interface IAcceptorSecureResumeState {\r\n securityLevel: ESecurityLevel;\r\n linkedClientId: TTypeAndId;\r\n keyMaterial?: IHandshakeEncryptionKeyMaterial;\r\n}\r\n\r\nexport interface IAcceptorSecureSessionConfig {\r\n /** This acceptor's crypto identity (verify + exchange key pairs, optionally persisted). */\r\n link: ClientCryptoKeyLink;\r\n /** This acceptor's coordinate — its identity to clients during the handshake. */\r\n localCoordinate: IRuntimeCoordinate;\r\n /** Wire dictionary version; the handshake rejects a client on a mismatch. */\r\n dictionaryVersion: string;\r\n /** Accepted level(s) — a single level is strict, an array is a negotiable allowed set. */\r\n securityLevel: ESecurityLevel | readonly ESecurityLevel[];\r\n /** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n /** Whether a plain (`none`) client may be served on this endpoint (i.e. `none` is in the set). */\r\n noneAllowed: boolean;\r\n /** Raw frame writer to this one connection. */\r\n send: (frame: TFrame) => void;\r\n /** Called once the handshake authenticates the peer — the handler binds identity + persists it. */\r\n onAuthenticated: (auth: IAcceptorAuthResult) => void;\r\n /** Route a frame from a `none`-negotiated connection through the handler's plain (self-asserted) path. */\r\n routePlain: (frame: TFrame) => void;\r\n /** Route a decrypted, ready-to-decode action frame from an authenticated connection. */\r\n routeAction: (bytes: TFrame) => void;\r\n}\r\n\r\n/**\r\n * The acceptor (accept-in) counterpart to the connector's `establishLinkSession`: one connection's\r\n * secure session — the server-side handshake driving, the ordered frame crypto, and the per-connection\r\n * phase (undecided → plain | authenticated). The crypto itself (ordered encrypt-send / decrypt) lives in\r\n * the shared {@link createFrameCryptoPipe}, the same primitive the connector uses — so the secure logic\r\n * lives once for both link roles.\r\n *\r\n * The handler owns one of these per accepted connection and feeds it inbound frames via {@link receive};\r\n * identity binding, persistence, codec, and return routing stay in the handler (driven through the\r\n * config callbacks). Inbound processing is serialized per connection because the handshake and decryption\r\n * are async — this keeps handshake ordering and frame order intact.\r\n */\r\nexport class AcceptorSecureSession {\r\n private _handshake?: ReturnType<typeof createServerHandshake>;\r\n /** The ordered encrypt-send / decrypt pipe — present only for an `encrypted` connection. */\r\n private _pipe?: IFrameCryptoPipe;\r\n private _authed = false;\r\n private _plain = false;\r\n /** Serializes inbound processing (handshake + decryption are async). */\r\n private _inboundChain: Promise<void> = Promise.resolve();\r\n\r\n constructor(private readonly config: IAcceptorSecureSessionConfig) {}\r\n\r\n /** Feed one inbound frame. Serialized per connection; routes back through the config callbacks. */\r\n receive(frame: TFrame): void {\r\n this._inboundChain = this._inboundChain\r\n .then(() => this._receive(frame))\r\n .catch((err) => console.error(\"[ws-server] failed to process inbound frame\", err));\r\n }\r\n\r\n private async _receive(frame: TFrame): Promise<void> {\r\n // A connection that already negotiated `none` is routed plainly (self-asserted identity).\r\n if (this._plain) {\r\n this.config.routePlain(frame);\r\n return;\r\n }\r\n\r\n if (!this._authed) {\r\n // Undecided first frame: a handshake control frame → drive the secure handshake; anything else,\r\n // when `none` is allowed, means a plain client → route it plainly from here on.\r\n const message = typeof frame === \"string\" ? decodeHandshakeMessage(frame) : undefined;\r\n if (message == null) {\r\n if (this.config.noneAllowed) {\r\n this._plain = true;\r\n this.config.routePlain(frame);\r\n }\r\n return;\r\n }\r\n\r\n await this.config.link.initialize();\r\n if (this._handshake == null) {\r\n this._handshake = createServerHandshake({\r\n link: this.config.link,\r\n localCoordinate: this.config.localCoordinate,\r\n dictionaryVersion: this.config.dictionaryVersion,\r\n securityLevel: this.config.securityLevel,\r\n verifyKeyResolver: this.config.verifyKeyResolver,\r\n });\r\n }\r\n\r\n if (message.t === EHandshakeMessageType.hello) {\r\n this.config.send(encodeHandshakeMessage(await this._handshake.onHello(message)));\r\n } else if (message.t === EHandshakeMessageType.prove) {\r\n const reply = await this._handshake.onProve(message);\r\n this.config.send(encodeHandshakeMessage(reply));\r\n const result = this._handshake.getResult();\r\n if (reply.t === EHandshakeMessageType.accept && result != null) this._complete(result);\r\n }\r\n return;\r\n }\r\n\r\n // Authenticated phase: decrypt (if encrypted), then hand the bytes to the handler to decode + route.\r\n const bytes = this._pipe != null ? await this._pipe.decryptIncoming(frame) : frame;\r\n if (bytes === undefined) return; // decryption failed (logged inside the pipe) — drop the frame\r\n this.config.routeAction(bytes);\r\n }\r\n\r\n private _complete(result: IHandshakeResult): void {\r\n this._authed = true;\r\n this._handshake = undefined;\r\n\r\n if (result.securityLevel === ESecurityLevel.encrypted) {\r\n this._pipe = this._buildPipe(\r\n createActionFrameCrypto({ link: this.config.link, linkedClientId: result.linkedClientId }),\r\n );\r\n }\r\n\r\n this.config.onAuthenticated({\r\n client: new RuntimeCoordinate(result.remote),\r\n securityLevel: result.securityLevel,\r\n linkedClientId: result.linkedClientId,\r\n keyMaterial: result.encryptionKeyMaterial,\r\n });\r\n }\r\n\r\n /**\r\n * Restore an already-authenticated session after eviction — no handshake. For an `encrypted`\r\n * connection the shared key is re-derived asynchronously (the acceptor re-links the client off its own\r\n * persisted identity); the pipe's crypto IS that promise, so the connection's first in/out frame\r\n * naturally waits for the key before encrypt/decrypt — no separate gate.\r\n */\r\n rehydrate(state: IAcceptorSecureResumeState): void {\r\n this._authed = true;\r\n\r\n if (state.securityLevel !== ESecurityLevel.encrypted || state.keyMaterial == null) return;\r\n\r\n const { link } = this.config;\r\n const { linkedClientId, keyMaterial } = state;\r\n const cryptoReady = link\r\n .initialize()\r\n .then(() =>\r\n link.linkClient({\r\n linkedClientId,\r\n verifyPublicKey: keyMaterial.verifyPublicKey,\r\n exchangePublicKey: keyMaterial.exchangePublicKey,\r\n saltString: keyMaterial.saltString,\r\n infoString: keyMaterial.infoString,\r\n bindVerifyKeysIntoDerivation: keyMaterial.bindVerifyKeysIntoDerivation,\r\n }),\r\n )\r\n .then(() => createActionFrameCrypto({ link, linkedClientId }));\r\n\r\n // Surface a re-link failure clearly (the pipe also logs per-frame, but this names the cause).\r\n cryptoReady.catch((err) =>\r\n console.error(\"[ws-server] failed to restore encrypted session\", err),\r\n );\r\n this._pipe = this._buildPipe(cryptoReady);\r\n }\r\n\r\n /** Send an outbound frame: through the encrypt pipe when encrypted, otherwise raw. */\r\n send(frame: TFrame): void {\r\n if (this._pipe != null) {\r\n this._pipe.send(frame);\r\n return;\r\n }\r\n this.config.send(frame);\r\n }\r\n\r\n private _buildPipe(\r\n crypto: Parameters<typeof createFrameCryptoPipe>[0][\"crypto\"],\r\n ): IFrameCryptoPipe {\r\n return createFrameCryptoPipe({ write: this.config.send, crypto, label: \"ws-server\" });\r\n }\r\n}\r\n","import type { ClientCryptoKeyLink, TTypeAndId } from \"@nice-code/util\";\r\nimport type { TDistributeActionPayload_Request } from \"../../../../ActionDefinition/Action/Action.combined.types\";\r\nimport type { IActionRouteItemHandler } from \"../../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport {\r\n EActionPayloadType,\r\n type TActionPayload_Any_Instance,\r\n type TActionPayload_Any_JsonObject,\r\n} from \"../../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionPayload_Request } from \"../../../../ActionDefinition/Action/Payload/ActionPayload_Request\";\r\nimport { RunningAction } from \"../../../../ActionDefinition/Action/RunningAction\";\r\nimport { ERunningActionUpdateType } from \"../../../../ActionDefinition/Action/RunningAction.types\";\r\nimport type { ActionDomain } from \"../../../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { IActionDomain } from \"../../../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport { EActionResponseMode } from \"../../../../ActionDefinition/Schema/ActionSchema\";\r\nimport { DEFAULT_TRANSPORT_TIMEOUT, UNSET_RUNTIME_ENV_ID } from \"../../../../nice_action.static\";\r\nimport { decodeActionFrame } from \"../../../../utils/decodeActionFrame\";\r\nimport { ActionRuntime } from \"../../../ActionRuntime\";\r\nimport { peekHandlerCuid } from \"../../../HandlerCallStack\";\r\nimport { type IRuntimeCoordinate, RuntimeCoordinate } from \"../../../RuntimeCoordinate\";\r\nimport type { IActionWireFormat } from \"../../../Transport/codec/actionWireCodec\";\r\nimport {\r\n ESecurityLevel,\r\n type IClientVerifyKeyResolver,\r\n type IHandshakeEncryptionKeyMaterial,\r\n} from \"../../../Transport/crypto/actionHandshake\";\r\nimport { EErrId_NiceTransport, err_nice_transport } from \"../../../Transport/err_nice_transport\";\r\nimport {\r\n AcceptorSecureSession,\r\n type IAcceptorAuthResult,\r\n} from \"../../../Transport/SecureSession/acceptorSecureSession\";\r\nimport { ETransportShape } from \"../../../Transport/Transport.types\";\r\nimport type { IActionHandler_Peer_Json, IHandleActionOptions } from \"../../ActionHandler.types\";\r\nimport { ActionLocalHandler } from \"../../Local/ActionLocalHandler\";\r\nimport type { THandleActionExecutionFn } from \"../../Local/ActionLocalHandler.types\";\r\nimport { PeerLinkHandler } from \"../../PeerLink/PeerLinkHandler\";\r\n\r\n/** The codec shape `AcceptorHandler` uses to pack/unpack frames — same as the Link transport's. */\r\nexport type TActionChannelFormatMessage = IActionWireFormat;\r\n\r\n/** How a connection encodes its frames, remembered so we answer each client in its own dialect. */\r\nexport type TActionConnectionEncoding = \"json\" | \"binary\";\r\n\r\n/** A connection's restorable identity — what to persist so a binding survives transport eviction. */\r\nexport interface IAcceptorConnectionBinding {\r\n /** Full client coordinate, so `originClient` can be re-injected into frames that omit it. */\r\n client: IRuntimeCoordinate;\r\n encoding: TActionConnectionEncoding;\r\n /**\r\n * Secure-session state (set once a connection's handshake completes). Persist it alongside the\r\n * binding so an authenticated/encrypted connection resumes after eviction without re-handshaking —\r\n * the `keyMaterial` lets the server re-derive the shared key from its own persisted identity.\r\n */\r\n secure?: {\r\n securityLevel: ESecurityLevel;\r\n linkedClientId: TTypeAndId;\r\n keyMaterial?: IHandshakeEncryptionKeyMaterial;\r\n };\r\n}\r\n\r\n/**\r\n * Server-side secure-channel config. When set, each connection negotiates a level from\r\n * {@link securityLevel}: an `authenticated`/`encrypted` client must complete the handshake (and is then\r\n * bound to its *authenticated* coordinate) before any action frame is accepted. A `none` client (only\r\n * when `none` is in the allowed set) is accepted as-is with a self-asserted identity. For the\r\n * `encrypted` level the codec source should be a session factory (`createFormatMessage`).\r\n */\r\nexport interface IAcceptorSecurity {\r\n /**\r\n * Accepted level(s). A single level is strict; an array is a negotiable allowed set — the server\r\n * adopts whichever level each client requests (e.g. `[none, authenticated, encrypted]` serves all\r\n * three over one endpoint).\r\n */\r\n securityLevel: ESecurityLevel | readonly ESecurityLevel[];\r\n /** This server's crypto identity (verify + exchange key pairs, optionally persisted). */\r\n link: ClientCryptoKeyLink;\r\n /** This server's coordinate — its identity to clients during the handshake. */\r\n localCoordinate: IRuntimeCoordinate;\r\n /** Wire dictionary version; the handshake rejects a client on a mismatch. */\r\n dictionaryVersion: string;\r\n /** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n}\r\n\r\ninterface IAcceptorHandlerBaseOptions<TConn> {\r\n /**\r\n * Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env(\"web_app\")`).\r\n * The runtime's return-path dispatch scores incoming actions' `originClient` against this to pick\r\n * this handler for sending results/pushes back over the right channel.\r\n */\r\n clientEnv: RuntimeCoordinate;\r\n /** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */\r\n send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;\r\n /**\r\n * The runtime this handler belongs to. When set, {@link AcceptorHandler.broadcast} can be called\r\n * without threading a runtime through each call. Optional — `pushToClient` still takes one explicitly.\r\n */\r\n runtime?: ActionRuntime;\r\n /** Timeout (ms) applied to server-initiated actions awaiting a client response. */\r\n defaultTimeout?: number;\r\n /**\r\n * Called once when a connection is first bound to a client identity. Use it to persist the binding\r\n * for transports that can resume after eviction — e.g. a Durable Object's hibernatable WebSocket:\r\n * `(ws, binding) => ws.serializeAttachment(binding)` — then replay it via {@link AcceptorHandler.rehydrateConnection}\r\n * when the channel comes back.\r\n */\r\n onConnectionBound?: (connection: TConn, binding: IAcceptorConnectionBinding) => void;\r\n /**\r\n * Enable the authenticated (optionally encrypted) handshake. When omitted, connections are trusted\r\n * as-is (identity self-asserted) — fine for dev / trusted networks.\r\n */\r\n security?: IAcceptorSecurity;\r\n}\r\n\r\n/**\r\n * Provide exactly one codec source:\r\n * - `formatMessage` — a single shared codec for every connection (stateless, e.g. `createBinaryWireAdapter`).\r\n * - `createFormatMessage` — a per-connection factory for stateful codecs (e.g.\r\n * `createBinaryWireSessionFactory`, whose sessions hold correlation + identity state). Required for the\r\n * leanest binary wire; the handler creates and caches one codec per connection.\r\n */\r\nexport type IAcceptorHandlerOptions<TConn> = IAcceptorHandlerBaseOptions<TConn> &\r\n (\r\n | { formatMessage: TActionChannelFormatMessage; createFormatMessage?: never }\r\n | { createFormatMessage: () => TActionChannelFormatMessage; formatMessage?: never }\r\n );\r\n\r\n/**\r\n * A connection-aware execution case (see {@link AcceptorHandler.forConnectionDomainCases}). It\r\n * receives the primed request plus the originating client's live connection (already resolved from the\r\n * request's `originClient`, `undefined` if the socket is gone), and may return the action's raw output,\r\n * a result payload, or nothing (auto-wrapped as an empty success) — exactly like a local handler case.\r\n */\r\nexport type TAcceptorConnectionCaseFn<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n TConn,\r\n> = (\r\n action: TDistributeActionPayload_Request<DOM, ID>,\r\n connection: TConn | undefined,\r\n) => ReturnType<THandleActionExecutionFn<DOM, ID>> | void;\r\n\r\n/**\r\n * Server-side handler for backends that accept many client connections over a single open channel\r\n * (WebSockets, Durable Objects, …). It is transport-agnostic: you feed it inbound frames with\r\n * {@link receive} and tell it how to write outbound frames via the `send` option.\r\n *\r\n * Add it alongside your local execution handler:\r\n * ```ts\r\n * const serverHandler = createAcceptorHandler({ clientEnv, formatMessage, send: (ws, f) => ws.send(f) });\r\n * runtime.addHandlers([localHandler, serverHandler]);\r\n * // per inbound message (e.g. a Durable Object's webSocketMessage):\r\n * serverHandler.receive(ws, message);\r\n * ```\r\n *\r\n * Inbound requests route to your local handler; the runtime's return dispatch then calls this\r\n * handler back (it is an external handler keyed to `clientEnv`) to send the result to the originating\r\n * connection. The handler keeps a per-connection identity registry so each result lands on the right\r\n * socket, and remembers each connection's encoding so binary and JSON clients can share the channel.\r\n *\r\n * It registers an empty action router, so it is never chosen to *execute* an inbound request — only\r\n * to ferry results/pushes back out.\r\n */\r\nexport class AcceptorHandler<TConn = unknown> extends PeerLinkHandler {\r\n /** Accept-in over a live (duplex) connection registry — it pushes results/broadcasts to bound sockets. */\r\n readonly canPush = true;\r\n\r\n private readonly _formatMessage?: TActionChannelFormatMessage;\r\n private readonly _createFormatMessage?: () => TActionChannelFormatMessage;\r\n private readonly _send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;\r\n private readonly _runtime?: ActionRuntime;\r\n private readonly _serverTimeout: number;\r\n private _onConnectionBound?: (connection: TConn, binding: IAcceptorConnectionBinding) => void;\r\n\r\n private readonly _security?: IAcceptorSecurity;\r\n /** Normalized accepted levels; whether `none` (plain) is allowed; whether any level needs a handshake. */\r\n private readonly _allowedLevels: readonly ESecurityLevel[];\r\n private readonly _noneAllowed: boolean;\r\n private readonly _handshakeMode: boolean;\r\n\r\n // Per-connection identity + encoding + codec registries.\r\n private readonly _connByClient = new Map<string, TConn>();\r\n private readonly _clientByConn = new Map<TConn, RuntimeCoordinate>();\r\n private readonly _connEncoding = new Map<TConn, TActionConnectionEncoding>();\r\n private readonly _codecByConn = new Map<TConn, TActionChannelFormatMessage>();\r\n\r\n // Per-connection secure session (only built when `security` is set): owns the handshake driving, the\r\n // ordered encrypt-send / decrypt pipe, and the connection's phase. The handler keeps only the identity\r\n // registry + encoding/codec; all crypto/handshake/chain bookkeeping lives in the session core.\r\n private readonly _sessionByConn = new Map<TConn, AcceptorSecureSession>();\r\n\r\n constructor(options: IAcceptorHandlerOptions<TConn>) {\r\n super(options.clientEnv);\r\n this._formatMessage = options.formatMessage;\r\n this._createFormatMessage = options.createFormatMessage;\r\n this._send = options.send;\r\n this._runtime = options.runtime;\r\n this._serverTimeout = options.defaultTimeout ?? DEFAULT_TRANSPORT_TIMEOUT;\r\n this._onConnectionBound = options.onConnectionBound;\r\n this._security = options.security;\r\n this._allowedLevels =\r\n options.security == null\r\n ? []\r\n : Array.isArray(options.security.securityLevel)\r\n ? options.security.securityLevel\r\n : [options.security.securityLevel];\r\n this._noneAllowed = this._allowedLevels.includes(ESecurityLevel.none);\r\n this._handshakeMode = this._allowedLevels.some((level) => level !== ESecurityLevel.none);\r\n }\r\n\r\n /**\r\n * The codec for a connection: a per-connection session (cached) when a factory was provided, else\r\n * the single shared `formatMessage`.\r\n */\r\n private _codecFor(connection: TConn): TActionChannelFormatMessage {\r\n if (this._createFormatMessage != null) {\r\n let codec = this._codecByConn.get(connection);\r\n if (codec == null) {\r\n codec = this._createFormatMessage();\r\n this._codecByConn.set(connection, codec);\r\n }\r\n return codec;\r\n }\r\n if (this._formatMessage != null) return this._formatMessage;\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.not_found, {\r\n actionId: \"server-handler-codec (provide formatMessage or createFormatMessage)\",\r\n });\r\n }\r\n\r\n /**\r\n * Register (or replace) the connection-bound persistence callback after construction. Used by\r\n * lifecycle helpers like {@link createHibernatableWsServerAdapter} so persistence and replay are\r\n * owned by one place instead of being split across the constructor options.\r\n */\r\n setOnConnectionBound(\r\n onConnectionBound: (connection: TConn, binding: IAcceptorConnectionBinding) => void,\r\n ): void {\r\n this._onConnectionBound = onConnectionBound;\r\n }\r\n\r\n /**\r\n * Feed one inbound frame from a connection into the runtime. Decodes text or binary, binds the\r\n * connection to the requesting client's identity, then routes it (requests execute locally;\r\n * results/progress resolve pending server-initiated actions).\r\n */\r\n receive(connection: TConn, frame: string | ArrayBuffer | Uint8Array): void {\r\n const security = this._security;\r\n // No security configured, or only `none` accepted → always plain (synchronous, self-asserted).\r\n if (security == null || !this._handshakeMode) {\r\n this._receivePlain(connection, frame);\r\n return;\r\n }\r\n\r\n // Secure mode: the per-connection session drives the handshake + decryption (serialized internally)\r\n // and routes back through the handler via the callbacks wired in `_sessionFor`.\r\n this._sessionFor(connection, security).receive(frame);\r\n }\r\n\r\n private _receivePlain(connection: TConn, frame: string | ArrayBuffer | Uint8Array): void {\r\n const wire = decodeActionFrame(frame, this._codecFor(connection));\r\n if (wire == null) return;\r\n\r\n const encoding: TActionConnectionEncoding = typeof frame === \"string\" ? \"json\" : \"binary\";\r\n this._connEncoding.set(connection, encoding);\r\n\r\n if (wire.type === EActionPayloadType.request) {\r\n this._resolveRequestIdentity(connection, wire, encoding);\r\n }\r\n\r\n this._emitIncoming(wire);\r\n }\r\n\r\n /**\r\n * The secure session for a connection (built lazily on its first secure-mode frame), with the\r\n * handler-owned effects — raw send, identity binding + persistence, and inbound routing — wired in as\r\n * callbacks. The session owns all crypto/handshake/chain state; the handler keeps only the registry.\r\n */\r\n private _sessionFor(connection: TConn, security: IAcceptorSecurity): AcceptorSecureSession {\r\n let session = this._sessionByConn.get(connection);\r\n if (session == null) {\r\n session = new AcceptorSecureSession({\r\n link: security.link,\r\n localCoordinate: security.localCoordinate,\r\n dictionaryVersion: security.dictionaryVersion,\r\n securityLevel: security.securityLevel,\r\n verifyKeyResolver: security.verifyKeyResolver,\r\n noneAllowed: this._noneAllowed,\r\n send: (frame) => this._send(connection, frame),\r\n onAuthenticated: (auth) => this._onConnectionAuthenticated(connection, auth),\r\n routePlain: (frame) => this._receivePlain(connection, frame),\r\n routeAction: (bytes) => this._routeAuthedActionBytes(connection, bytes),\r\n });\r\n this._sessionByConn.set(connection, session);\r\n }\r\n return session;\r\n }\r\n\r\n /** Bind + persist a connection's authenticated identity once its handshake completes. */\r\n private _onConnectionAuthenticated(connection: TConn, auth: IAcceptorAuthResult): void {\r\n this._bindConnection(connection, auth.client);\r\n this._connEncoding.set(connection, \"binary\");\r\n\r\n // Persist the secure session so an evicted connection can resume without re-handshaking.\r\n this._onConnectionBound?.(connection, {\r\n client: auth.client.toJsonObject(),\r\n encoding: \"binary\",\r\n secure: {\r\n securityLevel: auth.securityLevel,\r\n linkedClientId: auth.linkedClientId,\r\n keyMaterial: auth.keyMaterial,\r\n },\r\n });\r\n }\r\n\r\n /** Decode a decrypted authenticated frame, inject the *authenticated* identity, and route it. */\r\n private _routeAuthedActionBytes(\r\n connection: TConn,\r\n bytes: string | ArrayBuffer | Uint8Array,\r\n ): void {\r\n const wire = decodeActionFrame(bytes, this._codecFor(connection));\r\n if (wire == null) return;\r\n\r\n // The connection is bound to an *authenticated* coordinate — always use it, never the wire's\r\n // self-asserted originClient.\r\n if (wire.type === EActionPayloadType.request) {\r\n const bound = this._clientByConn.get(connection);\r\n if (bound != null) wire.context.originClient = bound.toJsonObject();\r\n }\r\n\r\n this._emitIncoming(wire);\r\n }\r\n\r\n /**\r\n * Ensure an inbound request carries the client's identity and that this connection is bound to it,\r\n * so its result can be routed back. A session codec omits `originClient` after the first request, so\r\n * when it's missing we restore it from the (possibly rehydrated) binding instead. (Plain mode only;\r\n * secure mode binds the authenticated coordinate at handshake time.)\r\n */\r\n private _resolveRequestIdentity(\r\n connection: TConn,\r\n wire: TActionPayload_Any_JsonObject<any>,\r\n encoding: TActionConnectionEncoding,\r\n ): void {\r\n const wireOrigin = wire.context.originClient;\r\n\r\n if (wireOrigin != null && wireOrigin.envId !== UNSET_RUNTIME_ENV_ID) {\r\n const clientCoord = new RuntimeCoordinate(wireOrigin);\r\n const isNewBinding = this._clientByConn.get(connection)?.stringId !== clientCoord.stringId;\r\n this._bindConnection(connection, clientCoord);\r\n if (isNewBinding) {\r\n this._onConnectionBound?.(connection, { client: clientCoord.toJsonObject(), encoding });\r\n }\r\n return;\r\n }\r\n\r\n // Identity dropped by the session — restore it from the binding so return routing still works.\r\n const bound = this._clientByConn.get(connection);\r\n if (bound != null) wire.context.originClient = bound.toJsonObject();\r\n }\r\n\r\n /**\r\n * Restore a connection→client binding without an inbound frame — for transports that resume after\r\n * eviction. Pair it with the {@link IAcceptorHandlerOptions.onConnectionBound} hook: persist\r\n * the binding there, then replay each live connection here when the channel comes back (e.g. a\r\n * Durable Object iterating `ctx.getWebSockets()` as it wakes from hibernation).\r\n */\r\n rehydrateConnection(connection: TConn, binding: IAcceptorConnectionBinding): void {\r\n this._bindConnection(connection, new RuntimeCoordinate(binding.client));\r\n this._connEncoding.set(connection, binding.encoding);\r\n\r\n const secure = binding.secure;\r\n const security = this._security;\r\n if (secure == null || security == null) return;\r\n\r\n // The connection had already authenticated before eviction — resume its secure session (no\r\n // handshake; an encrypted session re-derives its shared key off the acceptor's persisted identity).\r\n this._sessionFor(connection, security).rehydrate(secure);\r\n }\r\n\r\n toJsonObject(): IActionHandler_Peer_Json {\r\n return {\r\n type: this.handlerType,\r\n client: this.peerClient,\r\n };\r\n }\r\n\r\n override toHandlerRouteItem(): IActionRouteItemHandler {\r\n return {\r\n type: this.handlerType,\r\n client: this.peerClient,\r\n transShape: ETransportShape.duplex,\r\n transOrd: 0,\r\n };\r\n }\r\n\r\n /** Forget a connection (call on socket close) so stale entries don't misroute later results. */\r\n dropConnection(connection: TConn): void {\r\n const coord = this._clientByConn.get(connection);\r\n if (coord != null && this._connByClient.get(coord.stringId) === connection) {\r\n this._connByClient.delete(coord.stringId);\r\n }\r\n this._clientByConn.delete(connection);\r\n this._connEncoding.delete(connection);\r\n this._codecByConn.delete(connection);\r\n this._sessionByConn.delete(connection);\r\n }\r\n\r\n /** Live connection for a client coordinate, if currently registered. */\r\n getConnectionForClient(client: RuntimeCoordinate): TConn | undefined {\r\n return this._connByClient.get(client.stringId);\r\n }\r\n\r\n /** This acceptor owns the origin's return path when it currently holds a live connection bound to it. */\r\n override ownsLiveConnectionFor(origin: RuntimeCoordinate): boolean {\r\n return this._connByClient.has(origin.stringId);\r\n }\r\n\r\n /** Whether this acceptor currently tracks `connection` — used to pick the owning handler among several. */\r\n hasConnection(connection: TConn): boolean {\r\n return this._clientByConn.has(connection);\r\n }\r\n\r\n /**\r\n * Send (and optionally await) a server-initiated action to a specific connected client. Pass the\r\n * connection token directly (e.g. the `ws`) or a client `RuntimeCoordinate` to look one up.\r\n */\r\n pushToClient<DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n runtime: ActionRuntime,\r\n target: TConn | RuntimeCoordinate,\r\n request: ActionPayload_Request<DOM, ID>,\r\n options?: { timeout?: number },\r\n ): RunningAction<DOM, ID> {\r\n const connection = this._resolveConnection(target);\r\n return this._dispatch(runtime, connection, request, options?.timeout);\r\n }\r\n\r\n /**\r\n * Build a local handler whose cases are connection-aware: each case receives the primed request and\r\n * the originating client's live connection (resolved from `originClient`), so handlers don't repeat\r\n * the `getConnectionForClient(action.context.originClient)` lookup. Cases may return raw output or\r\n * nothing, just like {@link ActionLocalHandler.forDomainActionCases}. Add the returned handler to the\r\n * runtime alongside this server handler:\r\n * ```ts\r\n * runtime.addHandlers([serverHandler.forConnectionDomainCases(domain, { … }), serverHandler]);\r\n * ```\r\n */\r\n forConnectionDomainCases<FOR_DOM extends IActionDomain>(\r\n domain: ActionDomain<FOR_DOM>,\r\n cases: {\r\n [ID in keyof FOR_DOM[\"actionSchema\"] & string]?: TAcceptorConnectionCaseFn<\r\n FOR_DOM,\r\n ID,\r\n TConn\r\n >;\r\n },\r\n ): ActionLocalHandler {\r\n return this.forConnectionDomainCasesMulti([domain], cases);\r\n }\r\n\r\n /**\r\n * Like {@link forConnectionDomainCases} but spanning several domains with one merged case map — used\r\n * by channel-derived wiring (`acceptChannelConnections`) where the channel's `toAcceptor` domains are\r\n * served together. Each domain takes only the cases whose ids it owns, so a single map can cover\r\n * several domains and unrelated ids are ignored.\r\n */\r\n forConnectionDomainCasesMulti(\r\n domains: readonly ActionDomain<any>[],\r\n cases: Record<string, TAcceptorConnectionCaseFn<any, any, TConn> | undefined>,\r\n ): ActionLocalHandler {\r\n const handler = new ActionLocalHandler();\r\n\r\n for (const domain of domains) {\r\n const ownedIds = new Set(Object.keys(domain.actionsMap()));\r\n const wrapped: Record<string, THandleActionExecutionFn<any, any>> = {};\r\n\r\n for (const id in cases) {\r\n if (!ownedIds.has(id)) continue;\r\n const caseFn = cases[id];\r\n if (caseFn == null) continue;\r\n wrapped[id] = (request) =>\r\n caseFn(request, this.getConnectionForClient(request.context.originClient));\r\n }\r\n\r\n handler.forDomainActionCases(domain, wrapped);\r\n }\r\n\r\n return handler;\r\n }\r\n\r\n /**\r\n * Fan a server-initiated request out to every currently-bound connection. A fresh request is built\r\n * per connection (each push mutates its own action context) and dispatched fire-and-forget. Pass\r\n * `except` to skip the originating socket and `where` to filter by connection (e.g. read its\r\n * attachment for a role). Iterating bound connections (rather than every accepted socket) skips\r\n * sockets that are still mid-handshake and so can't yet receive a frame.\r\n */\r\n broadcast<DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n makeRequest: () => ActionPayload_Request<DOM, ID>,\r\n options?: {\r\n runtime?: ActionRuntime;\r\n except?: TConn | null;\r\n where?: (connection: TConn) => boolean;\r\n timeout?: number;\r\n onError?: (error: unknown, connection: TConn) => void;\r\n },\r\n ): void {\r\n const runtime = options?.runtime ?? this._runtime;\r\n if (runtime == null) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.not_found, {\r\n actionId: \"server-handler-runtime (construct with `runtime` or pass `options.runtime`)\",\r\n });\r\n }\r\n\r\n for (const connection of this._clientByConn.keys()) {\r\n if (options?.except != null && connection === options.except) continue;\r\n if (options?.where != null && !options.where(connection)) continue;\r\n try {\r\n this.pushToClient(runtime, connection, makeRequest(), { timeout: options?.timeout });\r\n } catch (error) {\r\n if (options?.onError != null) options.onError(error, connection);\r\n else console.error(\"[ws-server] broadcast push failed\", error);\r\n }\r\n }\r\n }\r\n\r\n override async sendReturnPayload(\r\n payload: TActionPayload_Any_Instance<any, any>,\r\n config: { targetLocalRuntime: ActionRuntime },\r\n ): Promise<boolean> {\r\n const connection = this._connByClient.get(payload.context.originClient.stringId);\r\n if (connection == null) return false;\r\n this._sendPayload(connection, payload, config.targetLocalRuntime.coordinate);\r\n return true;\r\n }\r\n\r\n override async handleActionRequest<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n >(\r\n action: ActionPayload_Request<DOM, ID>,\r\n config?: IHandleActionOptions,\r\n ): Promise<RunningAction<DOM, ID>> {\r\n const runtime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();\r\n const connection = this._resolveSingleConnection();\r\n return this._dispatch(runtime, connection, action, config?.timeout);\r\n }\r\n\r\n private _dispatch<DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n runtime: ActionRuntime,\r\n connection: TConn,\r\n action: ActionPayload_Request<DOM, ID>,\r\n timeout?: number,\r\n ): RunningAction<DOM, ID> {\r\n const timeoutMs = timeout ?? this._serverTimeout;\r\n\r\n // The client must be able to route its result back to *us*, so the origin is this backend.\r\n action.context._setOriginClient(runtime.coordinate);\r\n action.context.addRouteItem({\r\n runtime: runtime.coordinate,\r\n handler: this.toHandlerRouteItem(),\r\n time: Date.now(),\r\n });\r\n\r\n const runningAction = new RunningAction<DOM, ID>({\r\n context: action.context,\r\n request: action,\r\n parentCuid: peekHandlerCuid(),\r\n callSite: action._callSite,\r\n });\r\n runtime.registerRunningAction(runningAction);\r\n\r\n // Fire-and-forget: no reply will come, so don't park a pending action behind a timeout. Send the\r\n // frame and complete immediately as success — the running action still surfaces in devtools, it just\r\n // resolves on send rather than on a (never-arriving) reply.\r\n if (action.schema.responseMode === EActionResponseMode.none) {\r\n try {\r\n this._sendPayload(connection, action, runtime.coordinate);\r\n runningAction._completeWithResult(\r\n (action as ActionPayload_Request<any, any>).successResult(undefined),\r\n );\r\n } catch (err) {\r\n runningAction._abort(err);\r\n }\r\n return runningAction;\r\n }\r\n\r\n const timeoutId = setTimeout(() => {\r\n runningAction._abort(\r\n err_nice_transport.fromId(EErrId_NiceTransport.timeout, { timeout: timeoutMs }),\r\n );\r\n }, timeoutMs);\r\n runningAction.addUpdateListeners([\r\n (update) => {\r\n if (update.type === ERunningActionUpdateType.finished) clearTimeout(timeoutId);\r\n },\r\n ]);\r\n\r\n try {\r\n this._sendPayload(connection, action, runtime.coordinate);\r\n } catch (err) {\r\n runningAction._abort(err);\r\n }\r\n\r\n return runningAction;\r\n }\r\n\r\n private _sendPayload(\r\n connection: TConn,\r\n payload: TActionPayload_Any_Instance<any, any>,\r\n localClient: RuntimeCoordinate,\r\n ): void {\r\n const encoding = this._connEncoding.get(connection) ?? \"binary\";\r\n const frame =\r\n encoding === \"json\"\r\n ? JSON.stringify(payload.toJsonObject())\r\n : this._codecFor(connection).outgoing({\r\n action: payload,\r\n localClient,\r\n externalClient: this.peerClient,\r\n });\r\n\r\n // A secure connection's session encrypts (and orders) the frame; plain/authenticated connections (and\r\n // connections with no secure session at all) send as-is.\r\n const session = this._sessionByConn.get(connection);\r\n if (session == null) {\r\n this._send(connection, frame);\r\n return;\r\n }\r\n session.send(frame);\r\n }\r\n\r\n private _bindConnection(connection: TConn, client: RuntimeCoordinate): void {\r\n this._connByClient.set(client.stringId, connection);\r\n this._clientByConn.set(connection, client);\r\n }\r\n\r\n private _resolveConnection(target: TConn | RuntimeCoordinate): TConn {\r\n if (target instanceof RuntimeCoordinate) {\r\n const connection = this._connByClient.get(target.stringId);\r\n if (connection == null) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.not_found, {\r\n actionId: target.stringId,\r\n });\r\n }\r\n return connection;\r\n }\r\n return target;\r\n }\r\n\r\n private _resolveSingleConnection(): TConn {\r\n if (this._clientByConn.size !== 1) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.not_found, {\r\n actionId:\r\n \"server-handler-target (use pushToClient with an explicit connection or client coordinate)\",\r\n });\r\n }\r\n return this._clientByConn.keys().next().value as TConn;\r\n }\r\n}\r\n\r\nexport const createAcceptorHandler = <TConn = unknown>(\r\n options: IAcceptorHandlerOptions<TConn>,\r\n): AcceptorHandler<TConn> => {\r\n return new AcceptorHandler<TConn>(options);\r\n};\r\n","import { ClientCryptoKeyLink, type StorageAdapter } from \"@nice-code/util\";\r\nimport type { ActionRuntime } from \"../../../ActionRuntime\";\r\nimport type { RuntimeCoordinate } from \"../../../RuntimeCoordinate\";\r\nimport {\r\n createStorageTofuVerifyKeyResolver,\r\n ESecurityLevel,\r\n type IClientVerifyKeyResolver,\r\n} from \"../../../Transport/crypto/actionHandshake\";\r\nimport type { ISecureChannel } from \"../../../Channel/secureChannel\";\r\nimport { AcceptorHandler } from \"./AcceptorHandler\";\r\n\r\n/** Default accepted set: negotiate per connection to whatever the client picks. */\r\nconst DEFAULT_SERVER_SECURITY_LEVELS = [\r\n ESecurityLevel.none,\r\n ESecurityLevel.authenticated,\r\n ESecurityLevel.encrypted,\r\n] as const;\r\n\r\nexport interface ISecureAcceptorHandlerOptions<TConn> {\r\n /** The shared channel identity (codec + dictionary version) — same one the clients use. */\r\n channel: ISecureChannel;\r\n /**\r\n * Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env(\"web_app\")`),\r\n * used to route results/pushes back over this handler.\r\n */\r\n clientEnv: RuntimeCoordinate;\r\n /** This server's runtime — its coordinate is the server identity presented in the handshake. */\r\n runtime: ActionRuntime;\r\n /**\r\n * One backing store for the server's crypto identity *and* its trust-on-first-use verify-key pins.\r\n * Their keys don't collide, so a single adapter is enough; back it with persistent storage (e.g. a\r\n * Durable Object's storage) so identity and pins survive eviction.\r\n */\r\n storageAdapter: StorageAdapter;\r\n /** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */\r\n send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;\r\n /**\r\n * The server's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storageAdapter`.\r\n * Pass an existing link to share one identity across several acceptors on the same server (e.g. a\r\n * WebSocket acceptor and a secure-HTTP {@link createActionFetchHandler}), so they present the same\r\n * verify/exchange keys — avoiding a divergent-key race when two fresh links initialize concurrently.\r\n */\r\n link?: ClientCryptoKeyLink;\r\n /** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */\r\n securityLevel?: ESecurityLevel | readonly ESecurityLevel[];\r\n /** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storageAdapter`. */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n /** Timeout (ms) applied to server-initiated actions awaiting a client response. */\r\n defaultTimeout?: number;\r\n}\r\n\r\n/**\r\n * Build an {@link AcceptorHandler} for the secure binary channel with the boilerplate folded in:\r\n * it creates the {@link ClientCryptoKeyLink} and the storage-backed TOFU resolver from a single\r\n * `storageAdapter`, installs the channel's per-connection codec, and assembles the `security` block\r\n * from the runtime coordinate + channel version (accepting all three levels by default).\r\n *\r\n * For a hibernatable transport (e.g. a Durable Object), pair it with\r\n * {@link createHibernatableWsServerAdapter} to wire persistence + replay.\r\n */\r\nexport function createSecureAcceptorHandler<TConn = unknown>(\r\n options: ISecureAcceptorHandlerOptions<TConn>,\r\n): AcceptorHandler<TConn> {\r\n const link = options.link ?? new ClientCryptoKeyLink({ storageAdapter: options.storageAdapter });\r\n\r\n return new AcceptorHandler<TConn>({\r\n clientEnv: options.clientEnv,\r\n createFormatMessage: options.channel.createCodec,\r\n send: options.send,\r\n runtime: options.runtime,\r\n defaultTimeout: options.defaultTimeout,\r\n security: {\r\n securityLevel: options.securityLevel ?? DEFAULT_SERVER_SECURITY_LEVELS,\r\n link,\r\n localCoordinate: options.runtime.coordinate.toJsonObject(),\r\n dictionaryVersion: options.channel.dictionaryVersion,\r\n verifyKeyResolver:\r\n options.verifyKeyResolver ?? createStorageTofuVerifyKeyResolver(options.storageAdapter),\r\n },\r\n });\r\n}\r\n","import type { ClientCryptoKeyLink, StorageAdapter } from \"@nice-code/util\";\r\nimport type { ActionDomain } from \"../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { TWrappableDomainActionHandler } from \"../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport type { ActionRuntime } from \"../ActionRuntime\";\r\nimport type { ActionLocalHandler } from \"../Handler/Local/ActionLocalHandler\";\r\nimport type {\r\n AcceptorHandler,\r\n TAcceptorConnectionCaseFn,\r\n} from \"../Handler/PeerLink/Acceptor/AcceptorHandler\";\r\nimport { createSecureAcceptorHandler } from \"../Handler/PeerLink/Acceptor/createSecureActionServer\";\r\nimport type { ConnectorHandler } from \"../Handler/PeerLink/Connector/ConnectorHandler\";\r\nimport type { RuntimeCoordinate } from \"../RuntimeCoordinate\";\r\nimport type { ESecurityLevel, IClientVerifyKeyResolver } from \"../Transport/crypto/actionHandshake\";\r\nimport type { Transport } from \"../Transport/Transport\";\r\nimport type { ISecureChannel } from \"./secureChannel\";\r\n\r\n/**\r\n * A transport-agnostic routing contract between two runtimes, declared *by role* rather than by\r\n * \"client\"/\"server\". The two ends are named for the only asymmetry that survives every carrier (WS,\r\n * WebRTC, BLE, raw TCP): which side dials and which side accepts.\r\n *\r\n * - The **connector** dials out and opens the link ({@link connectChannel}).\r\n * - The **acceptor** accepts incoming links and can push back ({@link acceptChannelConnections}).\r\n *\r\n * `toAcceptor` domains flow connector→acceptor (the classic \"request\"); `toConnector` domains flow\r\n * acceptor→connector (the classic \"push\"). Both ends derive their routing from the same channel instead\r\n * of restating domain lists — and because the contract is independent of how bytes move, the very same\r\n * channel can be carried over HTTP, secure WebSockets, or a mix (WS preferred, HTTP fallback).\r\n *\r\n * Build a plain one with {@link defineChannel}; layer wire-specific identity on top with\r\n * `defineSecureChannel` (which returns an `ISecureChannel` — still an `IActionChannel`, so it works\r\n * everywhere a channel is expected).\r\n */\r\nexport interface IActionChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n> {\r\n /**\r\n * Domains the connector *sends to the acceptor* (connector→acceptor requests). The connector forwards\r\n * them over its transport(s); the acceptor executes them.\r\n */\r\n toAcceptorDomains: TO_ACCEPTOR;\r\n /**\r\n * Domains the acceptor *pushes to the connector* (acceptor→connector). The connector registers local\r\n * handlers for them ({@link connectChannel}'s `onPush`); the acceptor broadcasts them. Pushes need a\r\n * bidirectional transport (e.g. a WebSocket) — over a request-only transport like HTTP they simply\r\n * never flow.\r\n */\r\n toConnectorDomains: TO_CONNECTOR;\r\n}\r\n\r\n/**\r\n * Declare a transport-agnostic channel by role. Use it for HTTP, custom transports, or as the routing\r\n * half of a richer channel. The order of each list is part of the contract for wire formats that pack\r\n * positionally (see `defineSecureChannel`) — add new domains to the end of their list. (`domains` is\r\n * accepted as a legacy alias for `toAcceptor`.)\r\n */\r\nexport function defineChannel<\r\n const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [],\r\n const TO_CONNECTOR extends readonly ActionDomain<any>[] = [],\r\n>(options: {\r\n toAcceptor: TO_ACCEPTOR;\r\n toConnector: TO_CONNECTOR;\r\n}): IActionChannel<TO_ACCEPTOR, TO_CONNECTOR> {\r\n return {\r\n toAcceptorDomains: options.toAcceptor as TO_ACCEPTOR,\r\n toConnectorDomains: options.toConnector as TO_CONNECTOR,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Channel-derived wiring (connector + acceptor)\r\n// ---------------------------------------------------------------------------\r\n\r\ntype TUnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void\r\n ? I\r\n : never;\r\n\r\ntype TDomainPushHandlers<D> =\r\n D extends ActionDomain<infer DEF> ? Partial<TWrappableDomainActionHandler<DEF>> : never;\r\n\r\n/**\r\n * The `onPush` map for a channel: the merged set of every acceptor→connector (`toConnector`) action\r\n * handler, each receiving the pushed action's input. Derived from the channel's `toConnectorDomains`, so\r\n * the keys and input types follow the channel definition.\r\n */\r\nexport type TChannelPushHandlers<TO_CONNECTOR extends readonly ActionDomain<any>[]> =\r\n TUnionToIntersection<TDomainPushHandlers<TO_CONNECTOR[number]>>;\r\n\r\nexport interface IConnectChannelOptions<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[],\r\n> {\r\n /** The shared channel — its `toAcceptorDomains`/`toConnectorDomains` drive all routing. */\r\n channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>;\r\n /**\r\n * Transports to the acceptor, in preference order (e.g. `[wsTransport, httpFallback]`). They all carry\r\n * the same `toAcceptor` domains; the manager prefers the first that's ready and falls through on\r\n * failure — so connector→acceptor works over whatever transport is available, WS or HTTP.\r\n */\r\n transports: Transport[];\r\n /** Handlers for the channel's acceptor→connector pushes. Optional — omit for a send-only connection. */\r\n onPush?: TChannelPushHandlers<TO_CONNECTOR>;\r\n /** Default per-action timeout for this connection. */\r\n defaultTimeout?: number;\r\n}\r\n\r\n/**\r\n * Wire a connection to the acceptor straight from a channel: route the channel's `toAcceptor` domains to\r\n * the acceptor over `transports`, and register local handlers for its `toConnector` pushes from\r\n * `onPush`. The channel is the single source of truth for *what* is routed in each direction — the\r\n * caller only supplies the transport(s) and the push handlers, never restated domain lists. Pass several\r\n * transports to make the connector→acceptor path transport-agnostic (e.g. secure WS preferred, HTTP\r\n * fallback).\r\n *\r\n * Sugar over {@link ActionRuntime.connectTo}. Returns the acceptor handler so the caller can later\r\n * `clearTransportCache()` it.\r\n */\r\nexport function connectChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[],\r\n>(\r\n runtime: ActionRuntime,\r\n acceptorCoordinate: RuntimeCoordinate,\r\n options: IConnectChannelOptions<TO_ACCEPTOR, TO_CONNECTOR>,\r\n): ConnectorHandler {\r\n // Each push domain self-filters `onPush` to its own action ids, so a channel with several push\r\n // domains splits one merged map across the right handlers.\r\n const pushHandlers =\r\n options.onPush != null\r\n ? options.channel.toConnectorDomains.map((domain) =>\r\n domain.wrapAsPartialLocalHandler(\r\n options.onPush as Parameters<typeof domain.wrapAsPartialLocalHandler>[0],\r\n ),\r\n )\r\n : [];\r\n\r\n return runtime.connectTo(acceptorCoordinate, {\r\n transports: options.transports,\r\n domains: [...options.channel.toAcceptorDomains],\r\n localHandlers: pushHandlers,\r\n defaultTimeout: options.defaultTimeout,\r\n });\r\n}\r\n\r\ntype TDomainAcceptorCases<D, TConn> =\r\n D extends ActionDomain<infer DEF>\r\n ? { [ID in keyof DEF[\"actionSchema\"] & string]?: TAcceptorConnectionCaseFn<DEF, ID, TConn> }\r\n : never;\r\n\r\n/**\r\n * The connection-aware case map for a channel's acceptor side: the merged set of every\r\n * connector→acceptor (`toAcceptor`) action handler, each receiving the primed request plus the\r\n * originating connection. Derived from the channel's `toAcceptorDomains`, so the keys and input/output\r\n * types follow the channel.\r\n */\r\nexport type TChannelAcceptorCases<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[],\r\n TConn,\r\n> = TUnionToIntersection<TDomainAcceptorCases<TO_ACCEPTOR[number], TConn>>;\r\n\r\n/**\r\n * Register an acceptor handler's execution for a channel straight from its definition: the channel's\r\n * `toAcceptor` domains are served together with one merged, connection-aware case map (each case gets\r\n * the primed request + the originating connection, as with\r\n * {@link AcceptorHandler.forConnectionDomainCases}). The domain list is taken from the channel,\r\n * never restated. Add the returned handler to the runtime alongside the acceptor handler:\r\n * ```ts\r\n * runtime.addHandlers([acceptChannelConnections(serverHandler, channel, { … }), serverHandler]);\r\n * ```\r\n */\r\nexport function acceptChannelConnections<TO_ACCEPTOR extends readonly ActionDomain<any>[], TConn>(\r\n serverHandler: AcceptorHandler<TConn>,\r\n channel: IActionChannel<TO_ACCEPTOR, any>,\r\n cases: TChannelAcceptorCases<TO_ACCEPTOR, TConn>,\r\n): ActionLocalHandler {\r\n return serverHandler.forConnectionDomainCasesMulti(\r\n channel.toAcceptorDomains,\r\n cases as Record<string, TAcceptorConnectionCaseFn<any, any, TConn> | undefined>,\r\n );\r\n}\r\n\r\nexport interface IAcceptChannelOptions<TConn> {\r\n /**\r\n * Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env(\"web_app\")`),\r\n * used to score return-path dispatch back to the right connection.\r\n */\r\n clientEnv: RuntimeCoordinate;\r\n /**\r\n * One backing store for the acceptor's crypto identity *and* its trust-on-first-use verify-key pins\r\n * (their keys don't collide). Back it with persistent storage so identity + pins survive eviction.\r\n */\r\n storageAdapter: StorageAdapter;\r\n /** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */\r\n send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;\r\n /**\r\n * The acceptor's crypto identity. Defaults to a fresh `ClientCryptoKeyLink` over `storageAdapter`.\r\n * Pass an existing link to share one identity across several acceptors on the same server (e.g. this\r\n * WebSocket acceptor and a secure-HTTP `createActionFetchHandler`), so they present the same keys.\r\n */\r\n link?: ClientCryptoKeyLink;\r\n /** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */\r\n securityLevel?: ESecurityLevel | readonly ESecurityLevel[];\r\n /** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storageAdapter`. */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n /** Timeout (ms) applied to acceptor-initiated actions awaiting a client response. */\r\n defaultTimeout?: number;\r\n}\r\n\r\n/**\r\n * Build the secure {@link AcceptorHandler} for a channel — the accept-in counterpart to\r\n * {@link connectChannel}. It folds in the same boilerplate as {@link createSecureAcceptorHandler} (the\r\n * `ClientCryptoKeyLink` + storage-backed TOFU resolver from one `storageAdapter`, the channel's codec +\r\n * dictionary version, the `security` block from the runtime coordinate) but takes the `(runtime, channel,\r\n * options)` shape of the channel family. Pair it with {@link acceptChannelConnections} for execution:\r\n * ```ts\r\n * const acceptor = acceptChannel(runtime, gameChannel, { clientEnv, storageAdapter, send });\r\n * runtime.addHandlers([acceptChannelConnections(acceptor, gameChannel, { … }), acceptor]);\r\n * ```\r\n */\r\nexport function acceptChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[],\r\n TConn = unknown,\r\n>(\r\n runtime: ActionRuntime,\r\n channel: ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR>,\r\n options: IAcceptChannelOptions<TConn>,\r\n): AcceptorHandler<TConn> {\r\n return createSecureAcceptorHandler<TConn>({\r\n channel,\r\n runtime,\r\n clientEnv: options.clientEnv,\r\n storageAdapter: options.storageAdapter,\r\n link: options.link,\r\n send: options.send,\r\n securityLevel: options.securityLevel,\r\n verifyKeyResolver: options.verifyKeyResolver,\r\n defaultTimeout: options.defaultTimeout,\r\n });\r\n}\r\n","import { EActionForm } from \"../../../ActionDefinition/Action/ActionBase.types\";\r\nimport type { IActionContext_Data_JsonObject } from \"../../../ActionDefinition/Action/Context/ActionContext.types\";\r\nimport {\r\n EActionPayloadType,\r\n type IActionPayload_Base_JsonObject,\r\n type TActionPayload_Any_JsonObject,\r\n} from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { TPossibleDomainIdList } from \"../../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport type { ITransportRouteActionParams } from \"../Transport.types\";\r\n\r\n/**\r\n * Shared building blocks for the binary action codecs (the stateless {@link createBinaryWireAdapter} and\r\n * the per-connection `createBinaryWireSessionFactory`). Both map a `domain:id` route to a tiny integer\r\n * and reduce the verbose JSON wire to a positional tuple — they only differ in how much context they\r\n * carry per frame, so the dictionary + payload (de)assembly live here.\r\n */\r\n\r\n/**\r\n * The carrier-neutral codec a Link connection uses to (de)serialize action payloads on the wire — the\r\n * same shape every duplex carrier (WS/WebRTC/in-memory) shares.\r\n */\r\nexport interface IActionWireFormat {\r\n /**\r\n * Pack an outgoing action payload. Return a `string` for text frames (JSON) or a binary\r\n * `Uint8Array`/`ArrayBuffer` for optimized binary frames (e.g. msgpackr).\r\n */\r\n outgoing: (input: ITransportRouteActionParams) => string | Uint8Array | ArrayBuffer;\r\n /**\r\n * Unpack an incoming frame back into the wire JSON object the runtime hydrates + validates. Return\r\n * `undefined` to defer to the connection's built-in JSON parser — this is how binary adapters stay\r\n * backward compatible with plain-JSON clients on the same socket.\r\n */\r\n incoming?: (\r\n input: string | ArrayBuffer | Uint8Array | Blob,\r\n ) => TActionPayload_Any_JsonObject<any, any> | undefined;\r\n}\r\n\r\n/**\r\n * Tiny integer codes for the payload type, so the verbose `\"request\"`/`\"result\"`/`\"progress\"`\r\n * strings never hit the wire. The index in {@link ReversePayloadType} must line up with the value.\r\n */\r\nexport const PayloadTypeToInt: Record<\r\n EActionPayloadType.request | EActionPayloadType.result | EActionPayloadType.progress,\r\n number\r\n> = {\r\n [EActionPayloadType.request]: 0,\r\n [EActionPayloadType.result]: 1,\r\n [EActionPayloadType.progress]: 2,\r\n};\r\nexport const ReversePayloadType = [\r\n EActionPayloadType.request,\r\n EActionPayloadType.result,\r\n EActionPayloadType.progress,\r\n] as const;\r\n\r\nexport interface IActionRouteMeta {\r\n domain: string;\r\n id: string;\r\n allDomains: TPossibleDomainIdList;\r\n}\r\n\r\nexport interface IActionRouteDictionary {\r\n /** `domain:id` → wire integer. */\r\n routeToInt: Map<string, number>;\r\n /** wire integer → route metadata for reconstruction. */\r\n intToRoute: IActionRouteMeta[];\r\n}\r\n\r\n/**\r\n * Build the positional `domain:id` ↔ integer dictionary. Both ends of a channel MUST build it from\r\n * the same domains in the same order — the mapping is positional, so a mismatch routes to the wrong\r\n * action. Add new transported domains to the end of the list.\r\n */\r\nexport function buildActionRouteDictionary(domains: ActionDomain<any>[]): IActionRouteDictionary {\r\n const routeToInt = new Map<string, number>();\r\n const intToRoute: IActionRouteMeta[] = [];\r\n\r\n for (const dom of domains) {\r\n for (const actionId of Object.keys(dom.actionSchema)) {\r\n const routeKey = `${dom.domain}:${actionId}`;\r\n if (routeToInt.has(routeKey)) continue;\r\n routeToInt.set(routeKey, intToRoute.length);\r\n intToRoute.push({ domain: dom.domain, id: actionId, allDomains: dom.allDomains });\r\n }\r\n }\r\n\r\n return { routeToInt, intToRoute };\r\n}\r\n\r\n/** Pull the type-specific payload (`input` / `result` / `progress`) out of a wire JSON object. */\r\nexport function extractWirePayload(json: TActionPayload_Any_JsonObject<any, any>): unknown {\r\n if (json.type === EActionPayloadType.request) return json.input;\r\n if (json.type === EActionPayloadType.result) return json.result;\r\n if (json.type === EActionPayloadType.progress) return json.progress;\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Reassemble a full wire JSON object from its decoded parts. `inputHash`/`outputHash` are emitted\r\n * empty — the hydration constructors recompute them — and the result still satisfies\r\n * `isActionPayload_Any_JsonObject` so it flows through validation like a JSON frame.\r\n */\r\nexport function assembleWireJson(\r\n routeMeta: IActionRouteMeta,\r\n payloadType: (typeof ReversePayloadType)[number],\r\n time: number,\r\n context: IActionContext_Data_JsonObject,\r\n // Runtime-dynamic payload straight off the wire (msgpack/JSON) — Valibot validates it on hydrate.\r\n payloadData: any,\r\n): TActionPayload_Any_JsonObject<any, any> {\r\n const base: Omit<IActionPayload_Base_JsonObject<EActionPayloadType>, \"type\"> = {\r\n form: EActionForm.data,\r\n domain: routeMeta.domain,\r\n id: routeMeta.id,\r\n allDomains: routeMeta.allDomains,\r\n time,\r\n context,\r\n };\r\n\r\n if (payloadType === EActionPayloadType.request) {\r\n return { ...base, type: EActionPayloadType.request, input: payloadData, inputHash: \"\" };\r\n }\r\n if (payloadType === EActionPayloadType.result) {\r\n return { ...base, type: EActionPayloadType.result, result: payloadData, outputHash: \"\" };\r\n }\r\n return { ...base, type: EActionPayloadType.progress, progress: payloadData };\r\n}\r\n","import { pack, unpack } from \"msgpackr\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { EActionPayloadType } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport { UNSET_RUNTIME_ENV_ID } from \"../../../nice_action.static\";\r\nimport { type IRuntimeCoordinate, RuntimeCoordinate } from \"../../RuntimeCoordinate\";\r\nimport type { ITransportRouteActionParams } from \"../Transport.types\";\r\nimport {\r\n assembleWireJson,\r\n buildActionRouteDictionary,\r\n extractWirePayload,\r\n type IActionWireFormat,\r\n PayloadTypeToInt,\r\n ReversePayloadType,\r\n} from \"./actionWireCodec\";\r\n\r\n/**\r\n * Positional layout of the *session* binary envelope — the leanest frame. Compared to the stateless\r\n * adapter it replaces the 21-char `cuid` with a small per-connection integer and only carries\r\n * `originClient` on the very first request of each direction (the peer remembers it afterwards).\r\n *\r\n * [ routeInt, typeInt, corrId, time, originClient?, payloadData ]\r\n */\r\nconst ENVELOPE = {\r\n route: 0,\r\n type: 1,\r\n corr: 2,\r\n time: 3,\r\n originClient: 4,\r\n payload: 5,\r\n} as const;\r\nconst ENVELOPE_LENGTH = 6;\r\n\r\n/**\r\n * How long a pending correlation entry is kept before it's swept. A correlation only matters until its\r\n * action resolves or times out, so anything older than the longest realistic action timeout can be\r\n * dropped — this bounds memory when requests time out or a connection dies mid-flight (their replies\r\n * would never arrive, leaving the entry orphaned). Generous default so live correlations are never\r\n * pruned (the default transport timeout is 10s).\r\n */\r\nconst DEFAULT_CORRELATION_TTL_MS = 5 * 60_000;\r\n\r\ntype TFormatMessage = IActionWireFormat;\r\n\r\ninterface IPendingCorrelation<V> {\r\n value: V;\r\n /** Insertion time (ms), used to expire orphaned entries. */\r\n time: number;\r\n}\r\n\r\nexport interface IBinaryWireSessionOptions {\r\n /** Override how long an unresolved correlation is retained before being swept (ms). */\r\n correlationTtlMs?: number;\r\n}\r\n\r\nfunction isKnownIdentity(\r\n coordinate: IRuntimeCoordinate | null | undefined,\r\n): coordinate is IRuntimeCoordinate {\r\n return coordinate != null && coordinate.envId !== UNSET_RUNTIME_ENV_ID;\r\n}\r\n\r\n/**\r\n * Drop entries older than `ttlMs`. Maps keep insertion order and entries are inserted in time order,\r\n * so the oldest are first — stop sweeping at the first live entry.\r\n */\r\nfunction pruneExpired<K, V>(map: Map<K, IPendingCorrelation<V>>, now: number, ttlMs: number): void {\r\n for (const [key, entry] of map) {\r\n if (now - entry.time <= ttlMs) break;\r\n map.delete(key);\r\n }\r\n}\r\n\r\n/**\r\n * Builds a factory of *stateful, per-connection* codecs for {@link LinkTransport} /\r\n * `AcceptorHandler` — the maximally compact binary wire. Call the returned factory once per live\r\n * connection (each socket on the client, each accepted connection on the server) so every channel\r\n * gets its own correlation + identity state.\r\n *\r\n * On top of everything {@link createBinaryWireAdapter} drops, a session also drops:\r\n * - **`cuid`** — replaced by a per-connection integer correlation id. The initiator maps it to its\r\n * real cuid; the responder echoes it; each side reconstructs the cuid from its own map. Correlation\r\n * only needs to be unique per socket, so a counter suffices.\r\n * - **`originClient` after the first request** — the first request each side sends carries its\r\n * identity; the peer remembers it and injects it into later frames. Replies omit it entirely (a\r\n * reply carries the initiator's own origin, which the initiator already knows).\r\n *\r\n * Both ends MUST build the factory from the same domains in the same order (positional dictionary).\r\n * Text frames still return `undefined` from `incoming`, so JSON clients remain interoperable.\r\n *\r\n * Hibernation note: after a server connection is evicted its session resets, so a still-connected\r\n * client (whose session persists) will keep omitting `originClient`. The server must therefore restore\r\n * the connection→client binding from its own store (see `AcceptorHandler.rehydrateConnection`) and\r\n * inject `originClient` from there — the session alone can't recover it.\r\n */\r\nexport function createBinaryWireSessionFactory(\r\n domains: ActionDomain<any>[],\r\n options?: IBinaryWireSessionOptions,\r\n): () => TFormatMessage {\r\n const { routeToInt, intToRoute } = buildActionRouteDictionary(domains);\r\n const unknownIdentity = RuntimeCoordinate.unknown.toJsonObject();\r\n const ttlMs = options?.correlationTtlMs ?? DEFAULT_CORRELATION_TTL_MS;\r\n\r\n return (): TFormatMessage => {\r\n let outCounter = 0;\r\n // Requests this side initiated: correlation id → our cuid (to resolve the eventual reply).\r\n const corrToCuid = new Map<number, IPendingCorrelation<string>>();\r\n // Requests this side is responding to: our (synthesized) cuid → the correlation id to echo back.\r\n const cuidToCorr = new Map<string, IPendingCorrelation<number>>();\r\n let selfIdentity: IRuntimeCoordinate | undefined;\r\n let peerIdentity: IRuntimeCoordinate | undefined;\r\n\r\n return {\r\n outgoing: (input: ITransportRouteActionParams): Uint8Array => {\r\n const json = input.action.toJsonObject();\r\n const routeKey = `${json.domain}:${json.id}`;\r\n const routeInt = routeToInt.get(routeKey);\r\n if (routeInt == null) {\r\n throw new Error(`[binary-wire] Cannot pack unregistered action route: ${routeKey}`);\r\n }\r\n\r\n const now = Date.now();\r\n pruneExpired(corrToCuid, now, ttlMs);\r\n pruneExpired(cuidToCorr, now, ttlMs);\r\n\r\n let corr: number;\r\n let wireIdentity: IRuntimeCoordinate | undefined;\r\n\r\n if (json.type === EActionPayloadType.request) {\r\n // Initiator: assign a fresh per-connection correlation id, remember our cuid for the reply.\r\n corr = outCounter++;\r\n corrToCuid.set(corr, { value: json.context.cuid, time: now });\r\n\r\n // Send our identity only on the first request — the peer remembers it from then on.\r\n if (selfIdentity == null && isKnownIdentity(json.context.originClient)) {\r\n selfIdentity = json.context.originClient;\r\n wireIdentity = json.context.originClient;\r\n }\r\n } else {\r\n // Responder: echo the correlation id the request arrived with.\r\n corr = cuidToCorr.get(json.context.cuid)?.value ?? -1;\r\n if (json.type === EActionPayloadType.result) cuidToCorr.delete(json.context.cuid);\r\n }\r\n\r\n const envelope = new Array(ENVELOPE_LENGTH);\r\n envelope[ENVELOPE.route] = routeInt;\r\n envelope[ENVELOPE.type] = PayloadTypeToInt[json.type];\r\n envelope[ENVELOPE.corr] = corr;\r\n envelope[ENVELOPE.time] = json.time;\r\n envelope[ENVELOPE.originClient] = wireIdentity; // undefined except the first request\r\n envelope[ENVELOPE.payload] = extractWirePayload(json);\r\n\r\n return pack(envelope);\r\n },\r\n\r\n incoming: (frame: string | ArrayBuffer | Uint8Array | Blob) => {\r\n let buffer: Uint8Array;\r\n if (frame instanceof ArrayBuffer) {\r\n buffer = new Uint8Array(frame);\r\n } else if (frame instanceof Uint8Array) {\r\n buffer = frame;\r\n } else {\r\n return undefined;\r\n }\r\n\r\n try {\r\n const envelope = unpack(buffer);\r\n if (!Array.isArray(envelope) || envelope.length !== ENVELOPE_LENGTH) return undefined;\r\n\r\n const routeMeta = intToRoute[envelope[ENVELOPE.route]];\r\n const payloadType = ReversePayloadType[envelope[ENVELOPE.type]];\r\n if (routeMeta == null || payloadType == null) return undefined;\r\n\r\n const now = Date.now();\r\n pruneExpired(corrToCuid, now, ttlMs);\r\n pruneExpired(cuidToCorr, now, ttlMs);\r\n\r\n const corr: number = envelope[ENVELOPE.corr];\r\n const time: number = envelope[ENVELOPE.time];\r\n const wireIdentity: IRuntimeCoordinate | undefined = envelope[ENVELOPE.originClient];\r\n\r\n let cuid: string;\r\n let originClient: IRuntimeCoordinate;\r\n\r\n if (payloadType === EActionPayloadType.request) {\r\n // Incoming request: synthesize a local cuid, remember the correlation for our reply.\r\n cuid = nanoid();\r\n cuidToCorr.set(cuid, { value: corr, time: now });\r\n\r\n if (isKnownIdentity(wireIdentity)) peerIdentity = wireIdentity;\r\n originClient = peerIdentity ?? unknownIdentity;\r\n } else {\r\n // Incoming reply: map the correlation id back to the cuid of the request we initiated.\r\n cuid = corrToCuid.get(corr)?.value ?? nanoid();\r\n if (payloadType === EActionPayloadType.result) corrToCuid.delete(corr);\r\n // A reply carries our own origin (the request originated on this side).\r\n originClient = selfIdentity ?? unknownIdentity;\r\n }\r\n\r\n const context = { cuid, timeCreated: time, routing: [], originClient };\r\n return assembleWireJson(\r\n routeMeta,\r\n payloadType,\r\n time,\r\n context,\r\n envelope[ENVELOPE.payload],\r\n );\r\n } catch (e) {\r\n console.error(\"[binary-wire] Failed to unpack binary action session frame\", e);\r\n return undefined;\r\n }\r\n },\r\n };\r\n };\r\n}\r\n","import type { ActionDomain } from \"../../ActionDefinition/Domain/ActionDomain\";\r\nimport {\r\n buildActionRouteDictionary,\r\n type IActionWireFormat,\r\n} from \"../Transport/codec/actionWireCodec\";\r\nimport {\r\n createBinaryWireSessionFactory,\r\n type IBinaryWireSessionOptions,\r\n} from \"../Transport/codec/createBinaryWireSessionFactory\";\r\nimport { defineChannel, type IActionChannel } from \"./ActionChannel\";\r\n\r\n/** The per-connection binary session codec — built once per socket from the channel's domains. */\r\ntype TChannelCodec = IActionWireFormat;\r\n\r\n/**\r\n * The shared identity of a secure channel (carrier-agnostic — WS, WebRTC, HTTP, …): the wire\r\n * dictionary version both ends check during the handshake, plus the per-connection codec factory both\r\n * ends build from the *same* domain list. Define it once (typically in code shared by both peers) and\r\n * hand it to `secureTransport` on the connector and `serveChannel` (or the lower-level `acceptChannel` /\r\n * `createSecureAcceptorHandler`) on the acceptor, so the codec and version can never drift apart.\r\n */\r\nexport interface ISecureChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n> extends IActionChannel<TO_ACCEPTOR, TO_CONNECTOR> {\r\n /** Wire dictionary version — derived from the domains by default; the handshake rejects a mismatch. */\r\n dictionaryVersion: string;\r\n /** Per-connection session codec factory (call once per live connection). */\r\n createCodec: () => TChannelCodec;\r\n}\r\n\r\n/**\r\n * Derive a stable wire-dictionary version from the ordered route list (FNV-1a over `domain:id,…`), so\r\n * the version moves automatically whenever the transported domains change — a stale peer is then\r\n * rejected by the handshake instead of silently misrouting a positionally-packed frame.\r\n */\r\nfunction deriveDictionaryVersion(domains: ActionDomain<any>[]): string {\r\n const { intToRoute } = buildActionRouteDictionary(domains);\r\n const signature = intToRoute.map((route) => `${route.domain}:${route.id}`).join(\",\");\r\n\r\n let hash = 0x811c9dc5;\r\n for (let i = 0; i < signature.length; i++) {\r\n hash ^= signature.charCodeAt(i);\r\n hash = Math.imul(hash, 0x01000193);\r\n }\r\n return `auto:${(hash >>> 0).toString(16).padStart(8, \"0\")}`;\r\n}\r\n\r\n/**\r\n * Bundle a secure channel's shared identity from its transported domains. Both ends MUST call this\r\n * with the same domains in the same order (the binary wire dictionary is positional). The\r\n * `dictionaryVersion` is derived from those domains unless you pin an explicit one.\r\n *\r\n * Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`\r\n * (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see\r\n * {@link connectChannel} and `acceptChannelConnections`) instead of being restated at each end. The\r\n * wire dictionary spans `[...toAcceptor, ...toConnector]` in that order; add new domains to the end of\r\n * their list to keep older peers compatible. (`domains` is still accepted as a legacy alias for\r\n * `toAcceptor`.)\r\n */\r\nexport function defineSecureChannel<\r\n const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [],\r\n const TO_CONNECTOR extends readonly ActionDomain<any>[] = [],\r\n>(options: {\r\n /** Domains the connector sends to the acceptor (connector→acceptor requests), in a stable order. */\r\n toAcceptor: TO_ACCEPTOR;\r\n /** Domains the acceptor pushes to the connector (acceptor→connector), in a stable order. */\r\n toConnector: TO_CONNECTOR;\r\n /** Pin a human-readable version instead of the derived hash (must match on both ends). */\r\n dictionaryVersion?: string;\r\n /** Tuning for the per-connection binary session (e.g. correlation TTL). */\r\n sessionOptions?: IBinaryWireSessionOptions;\r\n}): ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR> {\r\n // The routing half (role) is just a plain channel; this adds the WS binary wire identity on top.\r\n const base = defineChannel<TO_ACCEPTOR, TO_CONNECTOR>({\r\n toAcceptor: options.toAcceptor,\r\n toConnector: options.toConnector,\r\n });\r\n // Dictionary order is positional and must match on both ends: connector→acceptor routes first, then\r\n // acceptor→connector pushes. (`domains` already covers the legacy single-list case via toAcceptorDomains.)\r\n const allDomains: ActionDomain<any>[] = [...base.toAcceptorDomains, ...base.toConnectorDomains];\r\n\r\n return {\r\n ...base,\r\n dictionaryVersion: options.dictionaryVersion ?? deriveDictionaryVersion(allDomains),\r\n createCodec: createBinaryWireSessionFactory(allDomains, options.sessionOptions),\r\n };\r\n}\r\n\r\n// The secure WS transport is now built via `secureTransport({ carrier: wsCarrier(url) })` — this file\r\n// only defines the carrier-neutral channel identity (`defineSecureChannel` / `ISecureChannel`).\r\n","import type { TActionPayload_Any_JsonObject } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\n\r\n/**\r\n * The application-level envelope for secure action traffic over an {@link IExchangeCarrier} (HTTP). An\r\n * exchange carrier only moves one request frame → one reply frame with no unsolicited push, so the\r\n * handshake and the per-action token + crypto all ride in this envelope (a JSON string body) rather than\r\n * on a persistent channel. The three security levels share it:\r\n *\r\n * - `none` — no handshake, no token: an `act` envelope carries the plaintext wire both ways.\r\n * - `authenticated` — a one-time handshake yields a session `token`; each later `act` carries it +\r\n * the plaintext wire.\r\n * - `encrypted` — same, but the wire is AES-GCM ciphertext, base64 in the `c` field.\r\n *\r\n * The handshake runs as two `hs` exchanges (hello→welcome, prove→accept) correlated by a client-chosen\r\n * `hsid`, since stateless requests can't rely on channel ordering. The `accept` reply carries the token.\r\n */\r\n\r\ntype TWireJson = TActionPayload_Any_JsonObject<any, any>;\r\n\r\n/** Connector → acceptor request envelope. */\r\nexport type TExchangeRequest =\r\n | { k: \"hs\"; hsid: string; m: string }\r\n | { k: \"act\"; t?: string; w: TWireJson }\r\n | { k: \"act\"; t?: string; c: string };\r\n\r\n/** Acceptor → connector reply envelope. */\r\nexport type TExchangeReply =\r\n | { k: \"hs\"; m: string; t?: string }\r\n | { k: \"act\"; w: TWireJson }\r\n | { k: \"act\"; c: string }\r\n | { k: \"err\"; message: string };\r\n\r\nexport function encodeExchange(envelope: TExchangeRequest | TExchangeReply): string {\r\n return JSON.stringify(envelope);\r\n}\r\n\r\nexport function decodeExchangeRequest(raw: string): TExchangeRequest | undefined {\r\n return parse<TExchangeRequest>(raw);\r\n}\r\n\r\nexport function decodeExchangeReply(raw: string): TExchangeReply | undefined {\r\n return parse<TExchangeReply>(raw);\r\n}\r\n\r\nfunction parse<T>(raw: string): T | undefined {\r\n try {\r\n return JSON.parse(raw) as T;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n// --- base64 for the encrypted ciphertext bytes (carried in a JSON string field) -----------------\r\n// `btoa`/`atob` over a binary string — available in browsers, web/Cloudflare Workers, and Node 16+.\r\n\r\nexport function bytesToBase64(bytes: Uint8Array): string {\r\n let binary = \"\";\r\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\r\n return btoa(binary);\r\n}\r\n\r\nexport function base64ToBytes(base64: string): Uint8Array {\r\n const binary = atob(base64);\r\n const bytes = new Uint8Array(binary.length);\r\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\r\n return bytes;\r\n}\r\n","import type { ClientCryptoKeyLink } from \"@nice-code/util\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { EActionPayloadType } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport { isActionPayload_Any_JsonObject } from \"../../../utils/isActionPayload_Any_JsonObject\";\r\nimport type { ActionRuntime } from \"../../ActionRuntime\";\r\nimport { type IRuntimeCoordinate, RuntimeCoordinate } from \"../../RuntimeCoordinate\";\r\nimport { createActionFrameCrypto, type IActionFrameCrypto } from \"../crypto/actionFrameCrypto\";\r\nimport {\r\n createServerHandshake,\r\n decodeHandshakeMessage,\r\n EHandshakeMessageType,\r\n ESecurityLevel,\r\n encodeHandshakeMessage,\r\n type IClientVerifyKeyResolver,\r\n} from \"../crypto/actionHandshake\";\r\nimport {\r\n base64ToBytes,\r\n bytesToBase64,\r\n decodeExchangeRequest,\r\n encodeExchange,\r\n type TExchangeReply,\r\n} from \"./exchangeProtocol\";\r\n\r\n/** Acceptor secure config for the exchange (HTTP) endpoint — same identity an `AcceptorHandler` uses. */\r\nexport interface IExchangeAcceptorSecurity {\r\n /** This acceptor's crypto identity (verify + exchange key pairs, optionally persisted). */\r\n link: ClientCryptoKeyLink;\r\n /** This acceptor's coordinate — its identity to clients during the handshake. */\r\n localCoordinate: IRuntimeCoordinate;\r\n /** Wire dictionary version; the handshake rejects a client on a mismatch. */\r\n dictionaryVersion: string;\r\n /** Accepted level(s) — a single level is strict, an array is a negotiable allowed set. */\r\n securityLevel: ESecurityLevel | readonly ESecurityLevel[];\r\n /** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n}\r\n\r\nexport interface IExchangeAcceptorConfig {\r\n security: IExchangeAcceptorSecurity;\r\n /** The runtime that executes an inbound action wire and produces its result. */\r\n runtime: ActionRuntime;\r\n}\r\n\r\n/** A live secure session, keyed by the token the connector replays on every action POST. */\r\ninterface IExchangeSession {\r\n client: RuntimeCoordinate;\r\n securityLevel: ESecurityLevel;\r\n crypto?: IActionFrameCrypto;\r\n}\r\n\r\nconst textEncoder = new TextEncoder();\r\nconst textDecoder = new TextDecoder();\r\n\r\n/**\r\n * Acceptor (accept-in) side of the secure exchange protocol — the HTTP counterpart to\r\n * {@link AcceptorSecureSession}. Each POST body is one {@link decodeExchangeRequest} envelope; the\r\n * acceptor drives the server handshake over the two `hs` POSTs (correlated by `hsid`, since stateless\r\n * requests can't rely on channel ordering), mints a session **token** on accept, and on every later `act`\r\n * POST resolves the session by token, decrypts the body (at `encrypted`), routes it through the runtime,\r\n * and returns the (encrypted) result inline as the reply.\r\n *\r\n * Sessions and in-flight handshakes are held in memory — fine for a single-instance server. (Surviving a\r\n * Durable-Object eviction would persist each token's `keyMaterial` and re-derive the key on a miss, the\r\n * same primitive `AcceptorSecureSession.rehydrate` uses; left as a follow-up.)\r\n */\r\nexport class ExchangeAcceptor {\r\n private readonly _security: IExchangeAcceptorSecurity;\r\n private readonly _runtime: ActionRuntime;\r\n private readonly _allowedLevels: readonly ESecurityLevel[];\r\n private readonly _noneAllowed: boolean;\r\n\r\n private readonly _pendingHandshakes = new Map<string, ReturnType<typeof createServerHandshake>>();\r\n private readonly _sessions = new Map<string, IExchangeSession>();\r\n\r\n constructor(config: IExchangeAcceptorConfig) {\r\n this._security = config.security;\r\n this._runtime = config.runtime;\r\n this._allowedLevels = Array.isArray(config.security.securityLevel)\r\n ? config.security.securityLevel\r\n : [config.security.securityLevel];\r\n this._noneAllowed = this._allowedLevels.includes(ESecurityLevel.none);\r\n }\r\n\r\n /** Process one POST body (an exchange envelope), returning the reply body to send back. */\r\n async handlePost(body: string): Promise<string> {\r\n const request = decodeExchangeRequest(body);\r\n if (request == null) return this._err(\"malformed exchange request\");\r\n\r\n if (request.k === \"hs\") return encodeExchange(await this._handleHandshake(request));\r\n return encodeExchange(await this._handleAction(request));\r\n }\r\n\r\n private async _handleHandshake(request: { hsid: string; m: string }): Promise<TExchangeReply> {\r\n const message = decodeHandshakeMessage(request.m);\r\n if (message == null) return { k: \"err\", message: \"malformed handshake message\" };\r\n\r\n const security = this._security;\r\n await security.link.initialize();\r\n\r\n let handshake = this._pendingHandshakes.get(request.hsid);\r\n if (handshake == null) {\r\n handshake = createServerHandshake({\r\n link: security.link,\r\n localCoordinate: security.localCoordinate,\r\n dictionaryVersion: security.dictionaryVersion,\r\n securityLevel: security.securityLevel,\r\n verifyKeyResolver: security.verifyKeyResolver,\r\n });\r\n this._pendingHandshakes.set(request.hsid, handshake);\r\n }\r\n\r\n if (message.t === EHandshakeMessageType.hello) {\r\n return { k: \"hs\", m: encodeHandshakeMessage(await handshake.onHello(message)) };\r\n }\r\n if (message.t === EHandshakeMessageType.prove) {\r\n const reply = await handshake.onProve(message);\r\n this._pendingHandshakes.delete(request.hsid);\r\n const result = handshake.getResult();\r\n if (reply.t === EHandshakeMessageType.accept && result != null) {\r\n const token = nanoid();\r\n this._sessions.set(token, {\r\n client: new RuntimeCoordinate(result.remote),\r\n securityLevel: result.securityLevel,\r\n crypto:\r\n result.securityLevel === ESecurityLevel.encrypted\r\n ? createActionFrameCrypto({\r\n link: security.link,\r\n linkedClientId: result.linkedClientId,\r\n })\r\n : undefined,\r\n });\r\n return { k: \"hs\", m: encodeHandshakeMessage(reply), t: token };\r\n }\r\n return { k: \"hs\", m: encodeHandshakeMessage(reply) };\r\n }\r\n\r\n return { k: \"err\", message: `unexpected handshake message ${message.t}` };\r\n }\r\n\r\n private async _handleAction(\r\n request: { t?: string } & ({ w: unknown } | { c: string }),\r\n ): Promise<TExchangeReply> {\r\n let session: IExchangeSession | undefined;\r\n let candidate: unknown;\r\n\r\n if (request.t != null) {\r\n session = this._sessions.get(request.t);\r\n if (session == null) return { k: \"err\", message: \"unknown or expired session token\" };\r\n\r\n if (\"c\" in request) {\r\n if (session.crypto == null) return { k: \"err\", message: \"session is not encrypted\" };\r\n const plain = await session.crypto.decryptFrame(base64ToBytes(request.c));\r\n candidate = JSON.parse(textDecoder.decode(plain));\r\n } else {\r\n candidate = request.w;\r\n }\r\n } else {\r\n // No token → a plain (`none`) client; only honoured when `none` is in the allowed set.\r\n if (!this._noneAllowed || \"c\" in request) {\r\n return { k: \"err\", message: \"missing session token\" };\r\n }\r\n candidate = request.w;\r\n }\r\n\r\n if (!isActionPayload_Any_JsonObject(candidate)) {\r\n return { k: \"err\", message: \"malformed action wire\" };\r\n }\r\n const wire = candidate;\r\n\r\n // Bind the *authenticated* identity (never the wire's self-asserted one) so the action runs as the\r\n // handshake-verified client.\r\n if (session != null && wire.type === EActionPayloadType.request) {\r\n wire.context.originClient = session.client.toJsonObject();\r\n }\r\n\r\n const running = await this._runtime.handleActionPayloadWire(wire);\r\n const result = await running.waitForResultPayload();\r\n const resultWire = result.toJsonObject();\r\n\r\n if (session?.crypto != null) {\r\n const ciphertext = await session.crypto.encryptFrame(\r\n textEncoder.encode(JSON.stringify(resultWire)),\r\n );\r\n return { k: \"act\", c: bytesToBase64(ciphertext) };\r\n }\r\n return { k: \"act\", w: resultWire };\r\n }\r\n\r\n private _err(message: string): string {\r\n return encodeExchange({ k: \"err\", message });\r\n }\r\n}\r\n","import type { ActionRuntime } from \"../../../ActionRuntime\";\r\nimport {\r\n ExchangeAcceptor,\r\n type IExchangeAcceptorSecurity,\r\n} from \"../../../Transport/SecureSession/exchangeAcceptor\";\r\n\r\n/** Permissive defaults — fine for a public action endpoint; override (or disable) via `cors`. */\r\nconst DEFAULT_CORS_HEADERS: Record<string, string> = {\r\n \"Access-Control-Allow-Origin\": \"*\",\r\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\r\n \"Access-Control-Allow-Headers\": \"Content-Type\",\r\n \"Access-Control-Max-Age\": \"86400\",\r\n};\r\n\r\nexport interface IActionFetchHandlerOptions {\r\n /**\r\n * CORS headers merged onto every response (a preflight `OPTIONS` is answered `204` with them).\r\n * Defaults to permissive `*`; pass `false` to attach no CORS headers at all.\r\n */\r\n cors?: Record<string, string> | false;\r\n /** Which requests carry an action wire on `POST`. Default: pathname ends with `/action`. */\r\n isActionPath?: (url: URL) => boolean;\r\n /** Which requests are WebSocket upgrades. Default: pathname ends with `/ws`. */\r\n isWebSocketPath?: (url: URL) => boolean;\r\n /**\r\n * Whether a request is a WebSocket upgrade for this endpoint, given the whole request (not just the\r\n * URL). When set it *replaces* the default gate (an `Upgrade: websocket` header on an\r\n * {@link isWebSocketPath} match) — use it when the discriminant needs a header or method, not only the\r\n * path. Only consulted when {@link onWebSocketUpgrade} is present.\r\n */\r\n isWebSocketUpgrade?: (request: Request, url: URL) => boolean;\r\n /**\r\n * Perform the transport-specific WebSocket upgrade (e.g. a Durable Object's\r\n * `new WebSocketPair()` + `ctx.acceptWebSocket()` returning a `101`). Omit for HTTP-only endpoints.\r\n * Its response is returned as-is — a `101` upgrade carries no CORS headers.\r\n */\r\n onWebSocketUpgrade?: (request: Request, url: URL) => Response | Promise<Response>;\r\n /** Forwarded to `ActionPayload_Result.toHttpResponse` — use the error's HTTP status (default true). */\r\n useErrorStatus?: boolean;\r\n /**\r\n * Enable the secure exchange protocol (handshake + token sessions + body encryption) on the `/action`\r\n * endpoint, mirroring an `AcceptorHandler`'s `security`. The matching connector is\r\n * `secureTransport({ carrier: httpCarrier(...), securityLevel })`. When omitted, the endpoint speaks\r\n * today's plain protocol (the raw action wire is POSTed and the result is the response body).\r\n */\r\n security?: IExchangeAcceptorSecurity;\r\n}\r\n\r\n/**\r\n * Build the `fetch` handler a server/Durable-Object exposes for action traffic, folding in the\r\n * boilerplate every endpoint repeats: CORS (incl. the `OPTIONS` preflight), routing the `/action`\r\n * `POST` body through the runtime (`handleActionPayloadWire` → `waitForResultPayload` →\r\n * `toHttpResponse`), an optional WebSocket-upgrade hook, and a `404` fallback.\r\n *\r\n * It only touches web-standard `Request`/`Response`, so it stays transport-agnostic — the one\r\n * environment-specific bit (the WS upgrade) is injected via {@link IActionFetchHandlerOptions.onWebSocketUpgrade}:\r\n * ```ts\r\n * this.fetchHandler = createActionFetchHandler(this.runtime, {\r\n * onWebSocketUpgrade: () => {\r\n * const pair = new WebSocketPair();\r\n * this.ctx.acceptWebSocket(pair[1]);\r\n * return new Response(null, { status: 101, webSocket: pair[0] });\r\n * },\r\n * });\r\n * // async fetch(request) { return this.fetchHandler(request); }\r\n * ```\r\n */\r\nexport function createActionFetchHandler(\r\n runtime: ActionRuntime,\r\n options: IActionFetchHandlerOptions = {},\r\n): (request: Request) => Promise<Response> {\r\n const corsHeaders = options.cors === false ? {} : (options.cors ?? DEFAULT_CORS_HEADERS);\r\n const isActionPath = options.isActionPath ?? ((url) => url.pathname.endsWith(\"/action\"));\r\n const isWebSocketPath = options.isWebSocketPath ?? ((url) => url.pathname.endsWith(\"/ws\"));\r\n const exchangeAcceptor =\r\n options.security != null\r\n ? new ExchangeAcceptor({ runtime, security: options.security })\r\n : undefined;\r\n\r\n const withCors = (response: Response): Response => {\r\n if (options.cors === false) return response;\r\n const headers = new Headers(response.headers);\r\n for (const [key, value] of Object.entries(corsHeaders)) headers.set(key, value);\r\n return new Response(response.body, { status: response.status, headers });\r\n };\r\n\r\n return async (request: Request): Promise<Response> => {\r\n if (request.method === \"OPTIONS\") {\r\n return withCors(new Response(null, { status: 204 }));\r\n }\r\n\r\n const url = new URL(request.url);\r\n\r\n const isWebSocketUpgrade =\r\n options.isWebSocketUpgrade ??\r\n ((req: Request, u: URL) => req.headers.get(\"Upgrade\") === \"websocket\" && isWebSocketPath(u));\r\n\r\n if (options.onWebSocketUpgrade != null && isWebSocketUpgrade(request, url)) {\r\n return options.onWebSocketUpgrade(request, url);\r\n }\r\n\r\n if (request.method === \"POST\" && isActionPath(url)) {\r\n // Secure exchange: the body is a protocol envelope (handshake or tokened/encrypted action); the\r\n // acceptor drives the handshake + token session and returns the reply envelope inline.\r\n if (exchangeAcceptor != null) {\r\n const reply = await exchangeAcceptor.handlePost(await request.text());\r\n return withCors(\r\n new Response(reply, { status: 200, headers: { \"Content-Type\": \"application/json\" } }),\r\n );\r\n }\r\n\r\n const running = await runtime.handleActionPayloadWire(await request.json());\r\n const result = await running.waitForResultPayload();\r\n return withCors(result.toHttpResponse({ useErrorStatus: options.useErrorStatus }));\r\n }\r\n\r\n return withCors(new Response(\"Not found\", { status: 404 }));\r\n };\r\n}\r\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\r\nimport type { AcceptorHandler, IAcceptorConnectionBinding } from \"../AcceptorHandler\";\r\n\r\n/**\r\n * The composite value persisted to a connection's attachment: the consumer's own app state plus the\r\n * {@link AcceptorHandler} routing binding. Co-storing them in one slot means a transport whose\r\n * sockets outlive process eviction (e.g. a Durable Object's hibernatable WebSocket) recovers both the\r\n * application identity *and* the action routing from a single attachment after a wake — no storage reads.\r\n */\r\nexport interface IConnectionAttachment<TApp> {\r\n app?: TApp;\r\n binding?: IAcceptorConnectionBinding;\r\n}\r\n\r\nexport interface IConnectionStateStoreOptions<TConn, TApp> {\r\n /** Read a connection's raw attachment (e.g. `(ws) => ws.deserializeAttachment()`). */\r\n read: (connection: TConn) => unknown;\r\n /** Persist a connection's attachment (e.g. `(ws, value) => ws.serializeAttachment(value)`). */\r\n write: (connection: TConn, value: IConnectionAttachment<TApp>) => void;\r\n /**\r\n * All currently-live connections (e.g. `() => ctx.getWebSockets()`). Used to replay routing bindings\r\n * after a wake (via {@link createConnectionStateStore}) and to enumerate app state in\r\n * {@link ConnectionStateStore.entries}.\r\n */\r\n getConnections: () => TConn[];\r\n /**\r\n * Optional Standard Schema (valibot, zod, …) validating the *app* portion on read. A value that\r\n * fails validation reads back as `null` — the same lenient behavior as a hand-written safeParse\r\n * helper. The binding is the library's own shape and is never validated.\r\n */\r\n schema?: StandardSchemaV1<unknown, TApp>;\r\n}\r\n\r\n/**\r\n * A typed per-connection state store that co-owns the app state and the acceptor handler's routing\r\n * binding in one attachment, so neither the consumer nor the handler has to hand-merge the two. Create\r\n * it through {@link createConnectionStateStore} (which also wires binding persistence and replays\r\n * surviving connections after a wake), then `get`/`set`/`clearApp` the app state directly.\r\n *\r\n * The mechanism is carrier-neutral — it only needs read/write/enumerate callbacks for the connection's\r\n * attachment — but it pays off on transports whose connections outlive process eviction (e.g. a\r\n * Durable Object's hibernatable WebSockets), which is why it lives beside the hibernation adapter.\r\n *\r\n * ```ts\r\n * const players = createConnectionStateStore(serverHandler, {\r\n * schema: vs_player,\r\n * read: (ws) => ws.deserializeAttachment(),\r\n * write: (ws, v) => ws.serializeAttachment(v),\r\n * getConnections: () => ctx.getWebSockets(),\r\n * });\r\n * players.set(ws, player); // binding is preserved automatically\r\n * const player = players.get(ws);\r\n * ```\r\n */\r\nexport class ConnectionStateStore<TConn, TApp> {\r\n constructor(private readonly options: IConnectionStateStoreOptions<TConn, TApp>) {}\r\n\r\n /** The validated app state for a connection, or `null` if unset / invalid. */\r\n get(connection: TConn): TApp | null {\r\n return this._readAttachment(connection).app ?? null;\r\n }\r\n\r\n /** Set the app state, preserving the runtime binding already pinned to the connection. */\r\n set(connection: TConn, app: TApp): void {\r\n const existing = this._readAttachment(connection);\r\n this.options.write(connection, { app, binding: existing.binding });\r\n }\r\n\r\n /** Clear the app state but keep the binding (e.g. a spectator that stopped watching). */\r\n clearApp(connection: TConn): void {\r\n const existing = this._readAttachment(connection);\r\n this.options.write(connection, { binding: existing.binding });\r\n }\r\n\r\n /** Every live connection paired with its (validated) app state — for rebuilding in-memory state after a wake. */\r\n entries(): [TConn, TApp | null][] {\r\n return this.options\r\n .getConnections()\r\n .map((connection) => [connection, this._readAttachment(connection).app ?? null]);\r\n }\r\n\r\n /** @internal Persist a freshly-bound connection's binding, preserving any app state already stored. */\r\n _persistBinding(connection: TConn, binding: IAcceptorConnectionBinding): void {\r\n const existing = this._readAttachment(connection);\r\n this.options.write(connection, { app: existing.app, binding });\r\n }\r\n\r\n /** @internal The persisted binding for a connection, if any (used to replay routing after a wake). */\r\n _readBinding(connection: TConn): IAcceptorConnectionBinding | undefined {\r\n return this._readAttachment(connection).binding;\r\n }\r\n\r\n private _readAttachment(connection: TConn): IConnectionAttachment<TApp> {\r\n try {\r\n const raw = this.options.read(connection);\r\n if (typeof raw !== \"object\" || raw === null) return {};\r\n\r\n const attachment = raw as IConnectionAttachment<TApp>;\r\n const result: IConnectionAttachment<TApp> = {};\r\n // The binding is our own serialized shape — trust it as written.\r\n if (attachment.binding != null) result.binding = attachment.binding;\r\n if (attachment.app !== undefined) {\r\n const app = this._validateApp(attachment.app);\r\n if (app !== undefined) result.app = app;\r\n }\r\n return result;\r\n } catch {\r\n return {};\r\n }\r\n }\r\n\r\n private _validateApp(value: unknown): TApp | undefined {\r\n const schema = this.options.schema;\r\n if (schema == null) return value as TApp;\r\n const result = schema[\"~standard\"].validate(value);\r\n // App state is validated on a synchronous read path; an async schema can't be honored here.\r\n if (result instanceof Promise) return undefined;\r\n if (result.issues != null) return undefined;\r\n return result.value;\r\n }\r\n}\r\n\r\n/**\r\n * Build a per-connection {@link ConnectionStateStore} bound to an {@link AcceptorHandler}: it registers\r\n * itself as the handler's connection-bound persistence callback (so bindings are written without\r\n * overwriting app state) and immediately replays every live connection's stored binding via\r\n * {@link AcceptorHandler.rehydrateConnection} — so on a transport that resumes after eviction (e.g. a\r\n * Durable Object waking from hibernation) both the app identity and the action routing come back from a\r\n * single attachment, with no storage reads and no hand-rolled merge.\r\n *\r\n * Lives outside the handler so the generic {@link AcceptorHandler} stays free of any attachment/\r\n * hibernation concern — it exposes only the neutral `setOnConnectionBound` + `rehydrateConnection`\r\n * hooks this builder drives.\r\n */\r\nexport function createConnectionStateStore<TConn, TApp>(\r\n handler: AcceptorHandler<TConn>,\r\n options: IConnectionStateStoreOptions<TConn, TApp>,\r\n): ConnectionStateStore<TConn, TApp> {\r\n const store = new ConnectionStateStore<TConn, TApp>(options);\r\n handler.setOnConnectionBound((connection, binding) => store._persistBinding(connection, binding));\r\n\r\n // Rebuild routing for sockets that survived an eviction.\r\n for (const connection of options.getConnections()) {\r\n const binding = store._readBinding(connection);\r\n if (binding != null) handler.rehydrateConnection(connection, binding);\r\n }\r\n\r\n return store;\r\n}\r\n","import type { AcceptorHandler, IAcceptorConnectionBinding } from \"../AcceptorHandler\";\r\n\r\nexport interface IHibernatableWsServerAdapterOptions<TConn> {\r\n /** The handler to drive (from `createSecureAcceptorHandler` or `createAcceptorHandler`). */\r\n handler: AcceptorHandler<TConn>;\r\n /** All currently-live connections — replayed on construction to rebuild bindings after a wake. */\r\n getConnections: () => TConn[];\r\n /** Read a connection's persisted binding (e.g. `(ws) => ws.deserializeAttachment()`). */\r\n getAttachment: (connection: TConn) => IAcceptorConnectionBinding | undefined;\r\n /** Persist a connection's binding when it is bound (e.g. `(ws, b) => ws.serializeAttachment(b)`). */\r\n setAttachment: (connection: TConn, binding: IAcceptorConnectionBinding) => void;\r\n}\r\n\r\n/**\r\n * The neutral lifecycle surface for a duplex (push-capable) acceptor: feed it each inbound frame and tell\r\n * it when a connection goes away. Carrier-agnostic — a WebSocket, a WebRTC data channel, or any other\r\n * duplex connection drives the same two methods.\r\n */\r\nexport interface IDuplexConnectionRouter<TConn> {\r\n /** Feed one inbound frame from a connection into the handler. */\r\n receive: (connection: TConn, frame: string | ArrayBuffer | Uint8Array) => void;\r\n /** Forget a connection (call on socket close/error). */\r\n drop: (connection: TConn) => void;\r\n}\r\n\r\n/**\r\n * Wire the hibernation lifecycle for an acceptor handler on a transport whose connections outlive process\r\n * eviction (e.g. a Durable Object's hibernatable WebSockets). It owns persistence end to end:\r\n * registers `setAttachment` as the handler's connection-bound callback and immediately replays every\r\n * live connection's stored binding via `getAttachment`, so results/pushes still route after a wake.\r\n *\r\n * Layered on top of the generic {@link AcceptorHandler} — it touches only the handler's neutral\r\n * `setOnConnectionBound` / `rehydrateConnection` / `receive` / `dropConnection` surface, so no\r\n * hibernation concern leaks into the handler itself.\r\n *\r\n * Construct it once when the handler is built, then forward connection events:\r\n * ```ts\r\n * const duplex = createHibernatableWsServerAdapter({ handler, getConnections, getAttachment, setAttachment });\r\n * // webSocketMessage(ws, msg) => duplex.receive(ws, msg);\r\n * // webSocketClose/Error(ws) => duplex.drop(ws);\r\n * ```\r\n */\r\nexport function createHibernatableWsServerAdapter<TConn>(\r\n options: IHibernatableWsServerAdapterOptions<TConn>,\r\n): IDuplexConnectionRouter<TConn> {\r\n const { handler, getConnections, getAttachment, setAttachment } = options;\r\n\r\n handler.setOnConnectionBound(setAttachment);\r\n\r\n // Rebuild bindings for connections that survived an eviction.\r\n for (const connection of getConnections()) {\r\n const binding = getAttachment(connection);\r\n if (binding != null) handler.rehydrateConnection(connection, binding);\r\n }\r\n\r\n return {\r\n receive: (connection, frame) => handler.receive(connection, frame),\r\n drop: (connection) => handler.dropConnection(connection),\r\n };\r\n}\r\n","import { ClientCryptoKeyLink, type StorageAdapter } from \"@nice-code/util\";\r\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\r\nimport type { ActionPayload_Request } from \"../../ActionDefinition/Action/Payload/ActionPayload_Request\";\r\nimport type { RunningAction } from \"../../ActionDefinition/Action/RunningAction\";\r\nimport type { ActionDomain } from \"../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { IActionDomain } from \"../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport type { ActionRuntime } from \"../ActionRuntime\";\r\nimport type { TActionRuntimeHandler } from \"../ActionRuntime.types\";\r\nimport {\r\n type AcceptorHandler,\r\n createAcceptorHandler,\r\n} from \"../Handler/PeerLink/Acceptor/AcceptorHandler\";\r\nimport { createActionFetchHandler } from \"../Handler/PeerLink/Acceptor/createActionFetchHandler\";\r\nimport {\r\n type ConnectionStateStore,\r\n createConnectionStateStore,\r\n type IConnectionAttachment,\r\n} from \"../Handler/PeerLink/Acceptor/Hibernation/ConnectionStateStore\";\r\nimport {\r\n createHibernatableWsServerAdapter,\r\n type IDuplexConnectionRouter,\r\n} from \"../Handler/PeerLink/Acceptor/Hibernation/createHibernatableWsServerAdapter\";\r\nimport { RuntimeCoordinate } from \"../RuntimeCoordinate\";\r\nimport {\r\n type IDuplexAcceptorCarrier,\r\n type IExchangeAcceptorCarrier,\r\n isExchangeAcceptorCarrier,\r\n type TAcceptorCarrier,\r\n} from \"../Transport/Carrier/AcceptorCarrier.types\";\r\nimport {\r\n createStorageTofuVerifyKeyResolver,\r\n ESecurityLevel,\r\n type IClientVerifyKeyResolver,\r\n} from \"../Transport/crypto/actionHandshake\";\r\nimport type { IExchangeAcceptorSecurity } from \"../Transport/SecureSession/exchangeAcceptor\";\r\nimport {\r\n acceptChannel,\r\n acceptChannelConnections,\r\n type TChannelAcceptorCases,\r\n} from \"./ActionChannel\";\r\nimport type { ISecureChannel } from \"./secureChannel\";\r\n\r\n/** Default accepted set, shared by every carrier: negotiate per connection to whatever the client picks. */\r\nconst DEFAULT_SERVER_SECURITY_LEVELS = [\r\n ESecurityLevel.none,\r\n ESecurityLevel.authenticated,\r\n ESecurityLevel.encrypted,\r\n] as const;\r\n\r\n/** Per-connection app-state config for {@link serveChannel}'s `connectionState`. */\r\nexport interface IServeConnectionStateOptions<TApp> {\r\n /**\r\n * Optional Standard Schema (valibot, zod, …) validating the app state on read — a value that fails\r\n * validation reads back as `null`. Omit to store the app state untyped.\r\n */\r\n schema?: StandardSchemaV1<unknown, TApp>;\r\n}\r\n\r\nexport interface IServeChannelOptions<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[],\r\n TConn,\r\n TApp = unknown,\r\n> {\r\n /**\r\n * Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env(\"web_app\")`),\r\n * used to score return-path dispatch back to the right connection.\r\n */\r\n clientEnv: RuntimeCoordinate;\r\n /**\r\n * One backing store for the server's crypto identity *and* its trust-on-first-use verify-key pins\r\n * (their keys don't collide). It is built once and shared across every carrier, so the WebSocket and the\r\n * secure-HTTP endpoint present the exact same verify/exchange keys and trust the same pinned clients.\r\n * Back it with persistent storage (e.g. a Durable Object's storage) so identity + pins survive eviction.\r\n *\r\n * Required only when at least one carrier is secure (the default). A fully-plain server (every carrier\r\n * `secure: false`) needs no storage and may omit it.\r\n */\r\n storage?: StorageAdapter;\r\n /**\r\n * The carriers this channel is served over — the accept-in dual of `connectChannel`'s `transports`.\r\n * Build them with `wsAcceptorCarrier` / `httpAcceptorCarrier`. Any number of duplex (push-capable)\r\n * carriers are supported (e.g. WebSocket + WebRTC), plus at most one exchange (request/reply) carrier;\r\n * all share one crypto identity and one runtime, and each result/push routes back over the carrier its\r\n * client connected on.\r\n */\r\n carriers: readonly TAcceptorCarrier<TConn>[];\r\n /** Your execution handlers (e.g. the local handler holding the action cases). Registered for you. */\r\n handlers?: TActionRuntimeHandler[];\r\n /**\r\n * The server's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storage`. Pass an\r\n * existing link only to share identity with acceptors built outside this call.\r\n */\r\n link?: ClientCryptoKeyLink;\r\n /** Accepted level(s) for every carrier; defaults to negotiating any of none/authenticated/encrypted. */\r\n securityLevel?: ESecurityLevel | readonly ESecurityLevel[];\r\n /** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storage`. */\r\n verifyKeyResolver?: IClientVerifyKeyResolver;\r\n /** Timeout (ms) applied to server-initiated actions awaiting a client response. */\r\n defaultTimeout?: number;\r\n /**\r\n * Co-store per-connection app state alongside the routing binding in the sole duplex carrier's connection\r\n * attachment, so both survive a wake from eviction. Reach the typed store back on `server.connections`.\r\n * Requires the carrier to expose an attachment store (the Cloudflare `durableObjectWsCarrier` does) and\r\n * exactly one duplex carrier.\r\n */\r\n connectionState?: IServeConnectionStateOptions<TApp>;\r\n /**\r\n * Connection-aware action cases for the channel's acceptor (`toAcceptor`) domains — each case receives the\r\n * primed request *and* the originating connection (the connection-aware dual of `handlers`). Registered on\r\n * the runtime for you. Requires exactly one duplex carrier.\r\n */\r\n channelCases?: TChannelAcceptorCases<TO_ACCEPTOR, TConn>;\r\n}\r\n\r\n/**\r\n * One server serving a secure channel over several carriers — the accept-in dual of `connectChannel`,\r\n * returned by {@link serveChannel}. Wire its surface straight to the host's request/socket events.\r\n */\r\nexport interface IChannelServer<TConn, TApp = unknown> {\r\n /**\r\n * The duplex acceptor handlers — one per duplex carrier, in carrier order (empty if none). For pushing,\r\n * prefer {@link pushToClient} (it resolves the owning handler); reach for these for cross-carrier work\r\n * like a per-handler `broadcast`.\r\n */\r\n handlers: AcceptorHandler<TConn>[];\r\n /**\r\n * Unified request handler: answers the CORS preflight, performs the duplex upgrade for an upgrade\r\n * request, serves a secure-exchange action `POST`, else `404`. Forward the host's `fetch` straight to it.\r\n */\r\n fetch: (request: Request) => Promise<Response>;\r\n /**\r\n * Convenience lifecycle for the *sole* duplex carrier — `receive` inbound frames, `drop` on close. Set\r\n * only when exactly one duplex carrier was provided; with several, feed each carrier handle directly\r\n * (every duplex carrier is its own lifecycle handle). `undefined` when there are zero or multiple.\r\n */\r\n duplex?: IDuplexConnectionRouter<TConn>;\r\n /**\r\n * Push a server-initiated action to a connected client (the runtime is bound in, so unlike\r\n * {@link AcceptorHandler.pushToClient} you pass only the target + request). It routes through the duplex\r\n * carrier the target connected on. Throws if no duplex carrier currently holds the target.\r\n */\r\n pushToClient: <DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n target: TConn | RuntimeCoordinate,\r\n request: ActionPayload_Request<DOM, ID>,\r\n options?: { timeout?: number },\r\n ) => RunningAction<DOM, ID>;\r\n /**\r\n * Fan a server-initiated action out to every connection on the sole duplex carrier (skip the origin with\r\n * `except`, filter with `where`). The push-to-many counterpart of {@link pushToClient}. Throws if there\r\n * isn't exactly one duplex carrier (with several, broadcast over a specific `handlers[i]`).\r\n */\r\n broadcast: <DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n makeRequest: () => ActionPayload_Request<DOM, ID>,\r\n options?: {\r\n except?: TConn | null;\r\n where?: (connection: TConn) => boolean;\r\n timeout?: number;\r\n onError?: (error: unknown, connection: TConn) => void;\r\n },\r\n ) => void;\r\n /**\r\n * The per-connection app-state store co-stored with the routing binding in the connection attachment —\r\n * present only when `connectionState` was passed. `get`/`set`/`clearApp`/`entries` it directly; it\r\n * survives hibernation alongside the binding.\r\n */\r\n connections?: ConnectionStateStore<TConn, TApp>;\r\n}\r\n\r\n/**\r\n * Serve a secure channel over one or more carriers from a single call — the accept-in dual of\r\n * `connectChannel`. It builds the crypto identity (a {@link ClientCryptoKeyLink} + a storage-backed TOFU\r\n * resolver) and the security block (coordinate, dictionary version, accepted levels) *once* from\r\n * `(runtime, channel)` and fans them across every carrier, so the WebSocket and the secure-HTTP endpoint\r\n * can never drift apart. It registers your handlers (plus the duplex acceptor it builds) on the runtime,\r\n * wires hibernation when the duplex carrier exposes an attachment store, and returns a single\r\n * {@link IChannelServer} whose `fetch` / `duplex` / `pushToClient` / `broadcast` you forward straight to\r\n * the host:\r\n * ```ts\r\n * const server = serveChannel(runtime, channel, {\r\n * clientEnv, storage,\r\n * carriers: [wsAcceptorCarrier({ send, upgrade, attachmentStore }), httpAcceptorCarrier()],\r\n * connectionState: { schema: vs_player }, // optional: co-store per-connection app state (survives hibernation)\r\n * channelCases: { join: (action, conn) => { … } }, // optional: connection-aware action cases\r\n * });\r\n * // fetch(req) => server.fetch(req)\r\n * // webSocketMessage(conn, m) => server.duplex?.receive(conn, m)\r\n * // webSocketClose/Error(conn) => server.duplex?.drop(conn)\r\n * // server.connections.get(conn) / server.broadcast(() => push.request(…), { except: conn })\r\n * ```\r\n *\r\n * `TConn` (the live-connection token a duplex carrier hands back through `send`/`receive`/`drop`) is\r\n * inferred from the carriers — `WebSocket` for `wsAcceptorCarrier`, the data-channel type for a WebRTC\r\n * carrier, and so on — so it stays carrier-agnostic. Passing `connectionState` narrows the return so\r\n * `server.connections` is non-optional.\r\n */\r\nexport function serveChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[],\r\n TConn,\r\n TApp,\r\n>(\r\n runtime: ActionRuntime,\r\n channel: ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR>,\r\n options: IServeChannelOptions<TO_ACCEPTOR, TConn, TApp> & {\r\n connectionState: IServeConnectionStateOptions<TApp>;\r\n },\r\n): IChannelServer<TConn, TApp> & { connections: ConnectionStateStore<TConn, TApp> };\r\nexport function serveChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n TConn = unknown,\r\n TApp = unknown,\r\n>(\r\n runtime: ActionRuntime,\r\n channel: ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR>,\r\n options: IServeChannelOptions<TO_ACCEPTOR, TConn, TApp>,\r\n): IChannelServer<TConn, TApp>;\r\nexport function serveChannel(\r\n runtime: ActionRuntime,\r\n channel: ISecureChannel<readonly ActionDomain<any>[], readonly ActionDomain<any>[]>,\r\n options: IServeChannelOptions<readonly ActionDomain<any>[], any, any>,\r\n): IChannelServer<any, any> {\r\n type TConn = any;\r\n const duplexCarriers = options.carriers.filter(\r\n (carrier): carrier is IDuplexAcceptorCarrier<TConn> => !isExchangeAcceptorCarrier(carrier),\r\n );\r\n const exchangeCarriers = options.carriers.filter(isExchangeAcceptorCarrier);\r\n\r\n if (exchangeCarriers.length > 1) {\r\n throw new Error(\"serveChannel: at most one exchange carrier is supported\");\r\n }\r\n const exchangeCarrier: IExchangeAcceptorCarrier | undefined = exchangeCarriers[0];\r\n\r\n const singleDuplex = duplexCarriers.length === 1;\r\n if (options.connectionState != null && !singleDuplex) {\r\n throw new Error(\"serveChannel: `connectionState` requires exactly one duplex carrier\");\r\n }\r\n if (options.channelCases != null && !singleDuplex) {\r\n throw new Error(\"serveChannel: `channelCases` requires exactly one duplex carrier\");\r\n }\r\n\r\n const exchangeSecure = exchangeCarrier != null && (exchangeCarrier.secure ?? true);\r\n const anyDuplexSecure = duplexCarriers.some((carrier) => carrier.secure ?? true);\r\n const securityLevel = options.securityLevel ?? DEFAULT_SERVER_SECURITY_LEVELS;\r\n\r\n // The shared crypto identity (link + TOFU resolver) — built once and fanned across every *secure*\r\n // carrier. Only constructed when something needs it; a fully-plain server uses no storage.\r\n let secure:\r\n | {\r\n storage: StorageAdapter;\r\n link: ClientCryptoKeyLink;\r\n verifyKeyResolver: IClientVerifyKeyResolver;\r\n }\r\n | undefined;\r\n if (anyDuplexSecure || exchangeSecure) {\r\n const storage = options.storage;\r\n if (storage == null) {\r\n throw new Error(\r\n \"serveChannel: a secure carrier requires `storage`. Pass it, or set `secure: false` on the carrier for a plain endpoint.\",\r\n );\r\n }\r\n secure = {\r\n storage,\r\n link: options.link ?? new ClientCryptoKeyLink({ storageAdapter: storage }),\r\n verifyKeyResolver: options.verifyKeyResolver ?? createStorageTofuVerifyKeyResolver(storage),\r\n };\r\n }\r\n\r\n // One acceptor handler per duplex carrier, each activated as its own lifecycle handle. Secure carriers →\r\n // `acceptChannel` (handshake + the shared identity, so they present the same keys as the exchange\r\n // endpoint); plain carriers → the base `createAcceptorHandler` over the channel's wire codec, no crypto.\r\n // Phase-A connection-aware return routing then sends each result/push back over the carrier its client\r\n // connected on.\r\n // The plain (in-memory only) router for a connection — no persistence across eviction.\r\n const plainRouter = (handler: AcceptorHandler<TConn>): IDuplexConnectionRouter<TConn> => ({\r\n receive: (connection, frame) => handler.receive(connection, frame),\r\n drop: (connection) => handler.dropConnection(connection),\r\n });\r\n const asObject = (value: unknown): object =>\r\n typeof value === \"object\" && value != null ? value : {};\r\n\r\n const handlers: AcceptorHandler<TConn>[] = [];\r\n // The per-connection app-state store, built once over the sole duplex carrier when `connectionState` is set.\r\n let connections: ConnectionStateStore<TConn, any> | undefined;\r\n for (const carrier of duplexCarriers) {\r\n const handler =\r\n (carrier.secure ?? true) && secure != null\r\n ? acceptChannel<any, any, TConn>(runtime, channel, {\r\n clientEnv: options.clientEnv,\r\n storageAdapter: secure.storage,\r\n link: secure.link,\r\n verifyKeyResolver: secure.verifyKeyResolver,\r\n securityLevel,\r\n send: carrier.send,\r\n defaultTimeout: options.defaultTimeout,\r\n })\r\n : createAcceptorHandler<TConn>({\r\n clientEnv: options.clientEnv,\r\n createFormatMessage: channel.createCodec,\r\n send: carrier.send,\r\n runtime,\r\n defaultTimeout: options.defaultTimeout,\r\n });\r\n\r\n // The attachment is one composite slot `{ app?, binding? }` per connection: serveChannel owns its\r\n // layout so binding *and* app state survive a wake from a single slot.\r\n // - no attachment store → in-memory only (no replay).\r\n // - `connectionState` requested → the connection store owns binding + app persistence and wake-replay.\r\n // - otherwise → the bare hibernation adapter persists/replays just the `.binding` sub-field.\r\n const attach = carrier.attachmentStore;\r\n let router: IDuplexConnectionRouter<TConn>;\r\n if (attach == null) {\r\n router = plainRouter(handler);\r\n } else if (options.connectionState != null) {\r\n connections = createConnectionStateStore<TConn, any>(handler, {\r\n schema: options.connectionState.schema,\r\n getConnections: attach.getConnections,\r\n read: attach.read,\r\n write: attach.write,\r\n });\r\n router = plainRouter(handler); // the store already replayed surviving bindings\r\n } else {\r\n router = createHibernatableWsServerAdapter<TConn>({\r\n handler,\r\n getConnections: attach.getConnections,\r\n getAttachment: (connection) =>\r\n (attach.read(connection) as IConnectionAttachment<unknown> | null | undefined)?.binding,\r\n setAttachment: (connection, binding) =>\r\n attach.write(connection, { ...asObject(attach.read(connection)), binding }),\r\n });\r\n }\r\n carrier._activate(router);\r\n handlers.push(handler);\r\n }\r\n\r\n runtime.addHandlers([...(options.handlers ?? []), ...handlers]);\r\n\r\n // Connection-aware action cases for the channel's acceptor domains, registered on the runtime alongside\r\n // the (sole) duplex acceptor — the connection-aware dual of `handlers`.\r\n if (options.channelCases != null) {\r\n runtime.addHandlers([acceptChannelConnections(handlers[0], channel, options.channelCases)]);\r\n }\r\n\r\n // The exchange (request/reply) security block — derived from the same identity + the channel/runtime\r\n // facts, so it never restates what the duplex side already knows. Omitted for a plain exchange carrier\r\n // (`secure: false`), which then POSTs the raw wire — letting a plain HTTP fallback sit beside a secure WS.\r\n const exchangeSecurity: IExchangeAcceptorSecurity | undefined =\r\n exchangeSecure && secure != null\r\n ? {\r\n link: secure.link,\r\n verifyKeyResolver: secure.verifyKeyResolver,\r\n localCoordinate: runtime.coordinate.toJsonObject(),\r\n dictionaryVersion: channel.dictionaryVersion,\r\n securityLevel,\r\n }\r\n : undefined;\r\n\r\n // Compose the upgrade across the duplex carriers that can be reached via an HTTP upgrade (typically just\r\n // one WebSocket carrier; a WebRTC carrier is signalled out of band and has no `upgrade`). The first\r\n // carrier whose `isUpgrade` matches handles the request.\r\n const defaultIsUpgrade = (request: Request) => request.headers.get(\"Upgrade\") === \"websocket\";\r\n const upgraders: {\r\n isUpgrade: (request: Request, url: URL) => boolean;\r\n upgrade: (request: Request, url: URL) => Response | Promise<Response>;\r\n }[] = [];\r\n for (const carrier of duplexCarriers) {\r\n if (carrier.upgrade == null) continue;\r\n upgraders.push({ isUpgrade: carrier.isUpgrade ?? defaultIsUpgrade, upgrade: carrier.upgrade });\r\n }\r\n\r\n const fetch = createActionFetchHandler(runtime, {\r\n cors: exchangeCarrier?.cors,\r\n onWebSocketUpgrade:\r\n upgraders.length === 0\r\n ? undefined\r\n : (request, url) =>\r\n (upgraders.find((u) => u.isUpgrade(request, url)) ?? upgraders[0]).upgrade(\r\n request,\r\n url,\r\n ),\r\n isWebSocketUpgrade:\r\n upgraders.length === 0\r\n ? undefined\r\n : (request, url) => upgraders.some((u) => u.isUpgrade(request, url)),\r\n // A single forwarding route means the path is already matched: any POST that isn't an upgrade is an\r\n // action exchange. With no exchange carrier there is no HTTP action endpoint, so POSTs fall through.\r\n isActionPath:\r\n exchangeCarrier != null ? (exchangeCarrier.isActionPath ?? (() => true)) : () => false,\r\n security: exchangeSecurity,\r\n useErrorStatus: exchangeCarrier?.useErrorStatus,\r\n });\r\n\r\n // Convenience shortcut for the common single-duplex case (the carrier is its own router). With several,\r\n // feed each carrier handle directly.\r\n const duplex: IDuplexConnectionRouter<TConn> | undefined =\r\n duplexCarriers.length === 1 ? duplexCarriers[0] : undefined;\r\n\r\n const pushToClient = <DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n target: TConn | RuntimeCoordinate,\r\n request: ActionPayload_Request<DOM, ID>,\r\n pushOptions?: { timeout?: number },\r\n ): RunningAction<DOM, ID> => {\r\n // Route the push through the handler that actually holds the target's live connection.\r\n const owner =\r\n target instanceof RuntimeCoordinate\r\n ? handlers.find((handler) => handler.ownsLiveConnectionFor(target))\r\n : handlers.find((handler) => handler.hasConnection(target));\r\n if (owner == null) {\r\n throw new Error(\"serveChannel: no duplex carrier holds a connection for the push target\");\r\n }\r\n return owner.pushToClient(runtime, target, request, pushOptions);\r\n };\r\n\r\n const broadcast = <DOM extends IActionDomain, ID extends keyof DOM[\"actionSchema\"] & string>(\r\n makeRequest: () => ActionPayload_Request<DOM, ID>,\r\n broadcastOptions?: {\r\n except?: TConn | null;\r\n where?: (connection: TConn) => boolean;\r\n timeout?: number;\r\n onError?: (error: unknown, connection: TConn) => void;\r\n },\r\n ): void => {\r\n if (!singleDuplex) {\r\n throw new Error(\r\n \"serveChannel: broadcast requires exactly one duplex carrier — broadcast over a specific handlers[i] instead\",\r\n );\r\n }\r\n handlers[0].broadcast(makeRequest, { runtime, ...broadcastOptions });\r\n };\r\n\r\n return { handlers, fetch, duplex, pushToClient, broadcast, connections };\r\n}\r\n","import type { IDuplexCarrier } from \"../../Carrier.types\";\r\n\r\ntype TFrame = string | ArrayBuffer | Uint8Array;\r\n\r\n/** The peer (server) end of an in-memory pair — what you feed into an `AcceptorHandler`. */\r\nexport interface IInMemoryServerEndpoint {\r\n /** Write a frame back to the client end. */\r\n send(frame: TFrame): void;\r\n /** Register the inbound handler (frames the client sent). */\r\n onMessage(handler: (frame: TFrame) => void): void;\r\n /** Close the pair from this end. */\r\n close(): void;\r\n /** Notified when the pair closes (from either end). */\r\n onClose(handler: () => void): void;\r\n}\r\n\r\nexport interface IInMemoryChannelPair {\r\n /** The client end — pass as a {@link IDuplexCarrier} to a `LinkTransport`. */\r\n clientChannel: IDuplexCarrier;\r\n /** The server end — wire into an `AcceptorHandler` (`send` + `receive`). */\r\n serverEndpoint: IInMemoryServerEndpoint;\r\n}\r\n\r\n/**\r\n * Two cross-wired in-process byte channels — a loopback carrier with no socket. The client end is a\r\n * {@link IDuplexCarrier} you hand to a {@link LinkTransport}; the server end plugs into an\r\n * `AcceptorHandler` (`send: (_, f) => serverEndpoint.send(f)`, and `serverEndpoint.onMessage(f =>\r\n * handler.receive(conn, f))`). Frames are delivered on a microtask, so each side observes the other\r\n * asynchronously — exactly like a real transport — which makes this ideal for tests and for running\r\n * two runtimes in one process (or proving a non-WS carrier end to end).\r\n */\r\nexport function createInMemoryChannelPair(): IInMemoryChannelPair {\r\n let clientMessage: ((frame: TFrame) => void) | undefined;\r\n let clientClose: (() => void) | undefined;\r\n let serverMessage: ((frame: TFrame) => void) | undefined;\r\n let serverClose: (() => void) | undefined;\r\n let open = true;\r\n\r\n const closeBoth = (): void => {\r\n if (!open) return;\r\n open = false;\r\n queueMicrotask(() => {\r\n clientClose?.();\r\n serverClose?.();\r\n });\r\n };\r\n\r\n const clientChannel: IDuplexCarrier = {\r\n ready: Promise.resolve(),\r\n isOpen: () => open,\r\n send: (frame) => {\r\n if (!open) return;\r\n queueMicrotask(() => serverMessage?.(frame));\r\n },\r\n attach: ({ onMessage, onClose }) => {\r\n clientMessage = onMessage;\r\n clientClose = onClose;\r\n },\r\n close: closeBoth,\r\n label: \"in-memory\",\r\n };\r\n\r\n const serverEndpoint: IInMemoryServerEndpoint = {\r\n send: (frame) => {\r\n if (!open) return;\r\n queueMicrotask(() => clientMessage?.(frame));\r\n },\r\n onMessage: (handler) => {\r\n serverMessage = handler;\r\n },\r\n onClose: (handler) => {\r\n serverClose = handler;\r\n },\r\n close: closeBoth,\r\n };\r\n\r\n return { clientChannel, serverEndpoint };\r\n}\r\n","import {\r\n createInMemoryChannelPair,\r\n type IInMemoryServerEndpoint,\r\n} from \"./createInMemoryChannel\";\r\nimport type { IDuplexCarrierSource } from \"../../Carrier.types\";\r\n\r\nexport interface IInMemoryCarrier {\r\n /** The connector end — pass as the `carrier` to {@link secureTransport} / `LinkTransport`. */\r\n carrier: IDuplexCarrierSource;\r\n /** The acceptor end — wire into an `AcceptorHandler` (`send` + `receive`). */\r\n serverEndpoint: IInMemoryServerEndpoint;\r\n}\r\n\r\n/**\r\n * A loopback duplex carrier with no socket — two cross-wired in-process ends. The connector end is an\r\n * {@link IDuplexCarrierSource} for {@link secureTransport}; the acceptor end plugs into an\r\n * `AcceptorHandler`. Ideal for tests and for running two runtimes in one process, or proving a\r\n * non-WS carrier end to end.\r\n */\r\nexport function inMemoryCarrier(): IInMemoryCarrier {\r\n const { clientChannel, serverEndpoint } = createInMemoryChannelPair();\r\n return {\r\n carrier: {\r\n carrierLabel: \"memory\",\r\n open: () => clientChannel,\r\n getCacheKey: () => [\"memory\"],\r\n },\r\n serverEndpoint,\r\n };\r\n}\r\n","import type { IDuplexCarrier } from \"../../Carrier.types\";\r\n\r\n/**\r\n * The slice of the `RTCDataChannel` surface this adapter uses — declared structurally so it accepts the\r\n * browser `RTCDataChannel`, React-Native (`react-native-webrtc`), or any node-webrtc shim without a hard\r\n * dependency on a specific DOM/RN type. A real `RTCDataChannel` satisfies it as-is.\r\n */\r\nexport interface IRtcDataChannelLike {\r\n readyState: string; // \"connecting\" | \"open\" | \"closing\" | \"closed\"\r\n binaryType: string;\r\n label?: string;\r\n send(data: string | ArrayBuffer | ArrayBufferView): void;\r\n close(): void;\r\n addEventListener(type: string, listener: (event: any) => void, options?: unknown): void;\r\n}\r\n\r\n/**\r\n * Adapt a WebRTC `RTCDataChannel` to the carrier-agnostic {@link IDuplexCarrier}, so two browsers\r\n * (or two mobile apps) linked peer-to-peer — no server in the middle — run the *same* secure session as\r\n * a WebSocket. Hand it to `createSecureLinkTransport({ openChannel: () => rtcDataChannelByteChannel(dc) })`.\r\n *\r\n * The data channel must already be created (its negotiation/signaling is the app's concern); this only\r\n * drives bytes over it. Binary frames are requested as `ArrayBuffer` so the binary session codec unpacks\r\n * them synchronously; a `Blob` (if the channel hands one back) is normalized to a buffer.\r\n */\r\nexport function rtcDataChannelByteChannel(dc: IRtcDataChannelLike): IDuplexCarrier {\r\n dc.binaryType = \"arraybuffer\";\r\n\r\n let intentional = false;\r\n let onMessage: ((frame: string | ArrayBuffer | Uint8Array) => void) | undefined;\r\n let onClose: (() => void) | undefined;\r\n const preAttach: (string | ArrayBuffer | Uint8Array)[] = [];\r\n\r\n const deliver = (frame: string | ArrayBuffer | Uint8Array): void => {\r\n if (onMessage != null) onMessage(frame);\r\n else preAttach.push(frame);\r\n };\r\n\r\n dc.addEventListener(\"message\", async (event: { data: unknown }) => {\r\n const frame = await normalizeFrame(event.data);\r\n if (frame !== undefined) deliver(frame);\r\n });\r\n dc.addEventListener(\"close\", () => {\r\n if (!intentional) console.error(\"RTCDataChannel closed\");\r\n onClose?.();\r\n });\r\n dc.addEventListener(\"error\", (event: unknown) => {\r\n console.error(\"RTCDataChannel error:\", event);\r\n onClose?.();\r\n });\r\n\r\n const ready = new Promise<void>((resolve, reject) => {\r\n if (dc.readyState === \"open\") {\r\n resolve();\r\n return;\r\n }\r\n dc.addEventListener(\"open\", () => resolve(), { once: true });\r\n dc.addEventListener(\"error\", (event: unknown) => reject(event), { once: true });\r\n dc.addEventListener(\"close\", () => reject(new Error(\"RTCDataChannel closed before open\")), {\r\n once: true,\r\n });\r\n });\r\n\r\n return {\r\n ready,\r\n isOpen: () => dc.readyState === \"open\",\r\n send: (frame) => {\r\n // A pooled `Uint8Array` may be backed by a `SharedArrayBuffer` that `send` rejects — copy into a\r\n // fresh view (mirrors the WebSocket `sendFrame` guard).\r\n if (typeof frame === \"string\" || frame instanceof ArrayBuffer) dc.send(frame);\r\n else dc.send(new Uint8Array(frame));\r\n },\r\n attach: (handlers) => {\r\n onMessage = handlers.onMessage;\r\n onClose = handlers.onClose;\r\n for (const frame of preAttach) handlers.onMessage(frame);\r\n preAttach.length = 0;\r\n },\r\n close: () => {\r\n intentional = true;\r\n try {\r\n dc.close();\r\n } catch {\r\n // already closing/closed — the close listener still runs cleanup\r\n }\r\n },\r\n get label() {\r\n return dc.label != null && dc.label !== \"\" ? dc.label : undefined;\r\n },\r\n };\r\n}\r\n\r\nasync function normalizeFrame(\r\n data: unknown,\r\n): Promise<string | ArrayBuffer | Uint8Array | undefined> {\r\n if (typeof data === \"string\" || data instanceof ArrayBuffer || data instanceof Uint8Array) {\r\n return data;\r\n }\r\n if (typeof Blob !== \"undefined\" && data instanceof Blob) {\r\n return await data.arrayBuffer();\r\n }\r\n return undefined;\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../../../Transport.types\";\r\nimport {\r\n type IRtcDataChannelLike,\r\n rtcDataChannelByteChannel,\r\n} from \"./rtcDataChannelByteChannel\";\r\nimport type { IDuplexCarrierSource } from \"../../Carrier.types\";\r\n\r\nexport interface IRtcCarrierOptions {\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n}\r\n\r\n/**\r\n * A WebRTC {@link IDuplexCarrierSource} over an already-negotiated `RTCDataChannel` (signaling is the\r\n * app's concern). Hand it to {@link secureTransport} so two browsers/apps linked peer-to-peer run the\r\n * identical secure session as a WebSocket.\r\n */\r\nexport function rtcCarrier(\r\n dataChannel: IRtcDataChannelLike,\r\n options: IRtcCarrierOptions = {},\r\n): IDuplexCarrierSource {\r\n return {\r\n carrierLabel: \"webrtc\",\r\n open: () => rtcDataChannelByteChannel(dataChannel),\r\n getCacheKey: options.getTransportCacheKey ?? (() => [\"webrtc\"]),\r\n getRouteInfo: options.getRouteInfo,\r\n };\r\n}\r\n","import { err } from \"@nice-code/error\";\r\nimport { err_nice_transport } from \"../../../err_nice_transport\";\r\n\r\nexport enum EErrId_NiceTransport_WebSocket {\r\n ws_disconnected = \"ws_disconnected\",\r\n ws_create_failed = \"ws_create_failed\",\r\n ws_error = \"ws_error\",\r\n}\r\n\r\nexport const err_nice_transport_ws = err_nice_transport.createChildDomain({\r\n domain: \"ws_transport\",\r\n schema: {\r\n [EErrId_NiceTransport_WebSocket.ws_disconnected]: err<Record<string, never>>({\r\n message: () => `WebSocket transport disconnected.`,\r\n }),\r\n [EErrId_NiceTransport_WebSocket.ws_create_failed]: err<{\r\n originalError?: Error;\r\n }>({\r\n message: ({ originalError }) =>\r\n `Failed to create WebSocket transport.${originalError ? ` Original error: ${originalError.message}` : \"\"}`,\r\n }),\r\n [EErrId_NiceTransport_WebSocket.ws_error]: err<{\r\n originalError?: Error;\r\n }>({\r\n message: ({ originalError }) =>\r\n `WebSocket transport error.${originalError ? ` Original error: ${originalError.message}` : \"\"}`,\r\n }),\r\n },\r\n});\r\n","/**\r\n * Send a text or binary frame over a socket. A binary formatter may hand back a `Uint8Array` whose\r\n * backing buffer is typed as `ArrayBufferLike` (msgpackr pools buffers / may be `SharedArrayBuffer`),\r\n * which `WebSocket.send`'s `BufferSource` parameter rejects — copy it into a fresh `ArrayBuffer`-backed\r\n * view so the type (and the bytes) are safe to send.\r\n */\r\nexport function sendFrame(ws: WebSocket, data: string | Uint8Array | ArrayBuffer): void {\r\n if (typeof data === \"string\" || data instanceof ArrayBuffer) {\r\n ws.send(data);\r\n return;\r\n }\r\n ws.send(new Uint8Array(data));\r\n}\r\n\r\n/** Compact a WebSocket URL to `host/pathname` for devtools display, falling back to the raw url. */\r\nexport function shortWs(url: string): string {\r\n try {\r\n const u = new URL(url);\r\n return `${u.host}${u.pathname}`;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n","import type { IDuplexCarrier } from \"../../Carrier.types\";\r\nimport { sendFrame } from \"./ws_util\";\r\n\r\n/**\r\n * Adapt a `WebSocket` to the carrier-agnostic {@link IDuplexCarrier}, so the WebSocket becomes\r\n * \"just another carrier\" under the shared secure session. It owns every WebSocket-specific concern —\r\n * awaiting `open`, normalizing `Blob` frames to bytes, suppressing the log on a deliberate `close`, and\r\n * buffering any frame that arrives before the session attaches its handler — leaving the session itself\r\n * carrier-neutral.\r\n */\r\nexport function webSocketByteChannel(ws: WebSocket): IDuplexCarrier {\r\n let intentional = false;\r\n let onMessage: ((frame: string | ArrayBuffer | Uint8Array) => void) | undefined;\r\n let onClose: (() => void) | undefined;\r\n // Frames that land before the session calls `attach` (none expected in practice, but never lose one).\r\n const preAttach: (string | ArrayBuffer | Uint8Array)[] = [];\r\n\r\n const deliver = (frame: string | ArrayBuffer | Uint8Array): void => {\r\n if (onMessage != null) onMessage(frame);\r\n else preAttach.push(frame);\r\n };\r\n\r\n ws.addEventListener(\"message\", async (event) => {\r\n const frame = await normalizeFrame((event as MessageEvent).data);\r\n if (frame !== undefined) deliver(frame);\r\n });\r\n ws.addEventListener(\"close\", (event) => {\r\n if (!intentional) console.error(\"WebSocket closed:\", event);\r\n onClose?.();\r\n });\r\n ws.addEventListener(\"error\", (event) => {\r\n console.error(\"WebSocket error:\", event);\r\n onClose?.();\r\n });\r\n\r\n const ready = new Promise<void>((resolve, reject) => {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n resolve();\r\n return;\r\n }\r\n ws.addEventListener(\"open\", () => resolve(), { once: true });\r\n ws.addEventListener(\"error\", (event) => reject(event), { once: true });\r\n ws.addEventListener(\r\n \"close\",\r\n (event) =>\r\n reject(new Error(`WebSocket closed before open: code=${(event as CloseEvent).code}`)),\r\n { once: true },\r\n );\r\n });\r\n\r\n return {\r\n ready,\r\n isOpen: () => ws.readyState === WebSocket.OPEN,\r\n send: (frame) => sendFrame(ws, frame),\r\n attach: (handlers) => {\r\n onMessage = handlers.onMessage;\r\n onClose = handlers.onClose;\r\n for (const frame of preAttach) handlers.onMessage(frame);\r\n preAttach.length = 0;\r\n },\r\n close: () => {\r\n intentional = true;\r\n try {\r\n ws.close();\r\n } catch {\r\n // already closing/closed — the close listener still runs cleanup\r\n }\r\n },\r\n get label() {\r\n return ws.url != null && ws.url !== \"\" ? ws.url : undefined;\r\n },\r\n };\r\n}\r\n\r\n/** Accept text + binary frames (ArrayBuffer / Uint8Array / Blob); Blobs are converted to a buffer. */\r\nasync function normalizeFrame(\r\n data: unknown,\r\n): Promise<string | ArrayBuffer | Uint8Array | undefined> {\r\n if (typeof data === \"string\" || data instanceof ArrayBuffer || data instanceof Uint8Array) {\r\n return data;\r\n }\r\n if (typeof Blob !== \"undefined\" && data instanceof Blob) {\r\n return await data.arrayBuffer();\r\n }\r\n return undefined;\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../../../Transport.types\";\r\nimport { webSocketByteChannel } from \"./webSocketByteChannel\";\r\nimport { shortWs } from \"./ws_util\";\r\nimport type { IDuplexCarrierSource } from \"../../Carrier.types\";\r\n\r\nexport interface IWsCarrierOptions {\r\n /** Override socket creation (defaults to a `new WebSocket(url)` with `binaryType = \"arraybuffer\"`). */\r\n createWebSocket?: (input: ITransportRouteActionParams) => WebSocket;\r\n /** Override the reuse key (defaults to `[url]`, so one socket is shared per endpoint). */\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /** Override the devtools route info for a specific action. */\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n}\r\n\r\n/**\r\n * A WebSocket {@link IDuplexCarrierSource}: opens an `arraybuffer` socket to `url` (cached per endpoint)\r\n * and adapts it to a carrier. Hand it to {@link secureTransport} (or `LinkTransport`) — the WebSocket is\r\n * now \"just another carrier\" under the shared secure session, with no WS-specific transport class.\r\n */\r\nexport function wsCarrier(url: string, options: IWsCarrierOptions = {}): IDuplexCarrierSource {\r\n return {\r\n carrierLabel: \"ws\",\r\n open: (input) =>\r\n webSocketByteChannel(options.createWebSocket?.(input) ?? defaultWebSocket(url)),\r\n getCacheKey: options.getTransportCacheKey ?? (() => [url]),\r\n getRouteInfo:\r\n options.getRouteInfo ?? (() => ({ carrierLabel: \"ws\", url, summary: `ws ${shortWs(url)}` })),\r\n };\r\n}\r\n\r\nfunction defaultWebSocket(url: string): WebSocket {\r\n const ws = new WebSocket(url);\r\n // Binary responses as ArrayBuffer (not Blob) so the session unpacks them synchronously.\r\n ws.binaryType = \"arraybuffer\";\r\n return ws;\r\n}\r\n","import { ETransportShape } from \"../../../Transport.types\";\r\nimport type { IExchangeAcceptorCarrier } from \"../../AcceptorCarrier.types\";\r\n\r\nexport interface IHttpAcceptorCarrierOptions {\r\n /**\r\n * Whether this endpoint runs the secure exchange protocol (default `true`). Pass `false` for a plain\r\n * endpoint — the body is the raw action wire and the result is the response body, the request/reply dual\r\n * of `plainTransport({ carrier: httpCarrier(...) })`. A plain endpoint ignores the crypto identity, so it\r\n * can sit alongside a secure WebSocket on the same server (e.g. a secure WS preferred, plain HTTP fallback).\r\n */\r\n secure?: boolean;\r\n /** Which requests carry an action exchange envelope on `POST`. Defaults to `serveChannel`'s path match. */\r\n isActionPath?: (url: URL) => boolean;\r\n /**\r\n * CORS headers merged onto every response (a preflight `OPTIONS` is answered `204`). Defaults to the\r\n * permissive `*` set; pass `false` to attach no CORS headers at all.\r\n */\r\n cors?: Record<string, string> | false;\r\n /** Plain mode only: use the error's HTTP status for failures (default `true`). Ignored when secure. */\r\n useErrorStatus?: boolean;\r\n /** Override the devtools carrier-kind label (defaults to `\"http\"`). */\r\n carrierLabel?: string;\r\n}\r\n\r\n/**\r\n * An HTTP {@link IExchangeAcceptorCarrier}: the accept-in dual of {@link httpCarrier}. It serves the\r\n * secure exchange protocol (handshake → token session → encrypted frames) over web-standard\r\n * `Request`/`Response`. The crypto identity, runtime coordinate, dictionary version, and accepted security\r\n * levels are all supplied centrally by `serveChannel`, so this only needs to say which requests carry an\r\n * action envelope and how to answer CORS.\r\n */\r\nexport function httpAcceptorCarrier(\r\n options: IHttpAcceptorCarrierOptions = {},\r\n): IExchangeAcceptorCarrier {\r\n return {\r\n shape: ETransportShape.exchange,\r\n carrierLabel: options.carrierLabel ?? \"http\",\r\n secure: options.secure,\r\n isActionPath: options.isActionPath,\r\n cors: options.cors,\r\n useErrorStatus: options.useErrorStatus,\r\n };\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../../../Transport.types\";\r\nimport type { IExchangeCarrier, IExchangeCarrierSource, TFrame } from \"../../Carrier.types\";\r\n\r\n/** The HTTP request an action is sent over (the body is supplied by the secure exchange session). */\r\nexport interface IHttpCarrierRequest {\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/** The slice of `fetch` the carrier uses — a structural type so callers (and tests) needn't match the\r\n * full platform `fetch` (Bun's adds `preconnect`, etc.). The global `fetch` satisfies it. */\r\nexport type TCarrierFetch = (input: string, init?: RequestInit) => Promise<Response>;\r\n\r\nexport interface IHttpCarrierOptions {\r\n /** Override the reuse key (defaults to `[url]`, so one session is shared per endpoint). */\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /** Override the devtools route info for a specific action. */\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n /** Override `fetch` (e.g. to route to an in-memory handler in tests). Defaults to global `fetch`. */\r\n fetch?: TCarrierFetch;\r\n}\r\n\r\nfunction shortPath(url: string): string {\r\n try {\r\n return new URL(url).pathname || url;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * An HTTP {@link IExchangeCarrierSource}: each `exchange` POSTs one frame body to the action endpoint and\r\n * resolves with the response body as the single correlated reply. Hand it to {@link secureTransport} —\r\n * HTTP then runs the *same* secure session as a duplex carrier (handshake → token → encrypted frames),\r\n * the request/reply correlation provided for free by the HTTP transaction.\r\n *\r\n * `createRequest` derives the URL/headers per action (keep it simple with `() => ({ url })`). The body is\r\n * the session's responsibility, so it is never built here.\r\n */\r\nexport function httpCarrier(\r\n createRequest: (input: ITransportRouteActionParams) => IHttpCarrierRequest,\r\n options: IHttpCarrierOptions = {},\r\n): IExchangeCarrierSource {\r\n const doFetch = options.fetch ?? fetch;\r\n\r\n return {\r\n shape: \"exchange\",\r\n carrierLabel: \"http\",\r\n open: (input): IExchangeCarrier => {\r\n const request = createRequest(input);\r\n return {\r\n label: request.url,\r\n exchange: async (frame: TFrame, opts): Promise<TFrame> => {\r\n const res = await doFetch(request.url, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\", ...request.headers },\r\n body: typeof frame === \"string\" ? frame : new Uint8Array(frame),\r\n signal: opts?.signal,\r\n });\r\n return await res.text();\r\n },\r\n };\r\n },\r\n getCacheKey: options.getTransportCacheKey ?? ((input) => [createRequest(input).url]),\r\n getRouteInfo:\r\n options.getRouteInfo ??\r\n ((input) => {\r\n const { url } = createRequest(input);\r\n return { carrierLabel: \"http\", method: \"POST\", url, summary: `POST ${shortPath(url)}` };\r\n }),\r\n };\r\n}\r\n","import { pack, unpack } from \"msgpackr\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { ITransportRouteActionParams } from \"../Transport.types\";\r\nimport {\r\n assembleWireJson,\r\n buildActionRouteDictionary,\r\n extractWirePayload,\r\n type IActionWireFormat,\r\n PayloadTypeToInt,\r\n ReversePayloadType,\r\n} from \"./actionWireCodec\";\r\n\r\n/**\r\n * Positional layout of the stateless binary envelope. A flat tuple (rather than an object) strips the\r\n * repeated `domain`/`id`/`form`/`type` and context key names from every frame, and we carry only the\r\n * context fields the receiver can't recompute: `cuid` (correlation) and `originClient` (return\r\n * routing).\r\n *\r\n * [ routeInt, typeInt, time, cuid, originClient, payloadData ]\r\n *\r\n * Dropped vs the JSON wire: `form`/`type` strings, `inputHash`/`outputHash` (recomputed on hydrate),\r\n * `context.timeCreated` (reconstructed from `time`) and `context.routing` (rebuilt empty — the\r\n * receiver re-stamps its own route items as it handles the action). For the leanest possible frames\r\n * (integer correlation, identity dropped after a handshake), use `createBinaryWireSessionFactory`.\r\n */\r\nconst ENVELOPE = {\r\n route: 0,\r\n type: 1,\r\n time: 2,\r\n cuid: 3,\r\n originClient: 4,\r\n payload: 5,\r\n} as const;\r\nconst ENVELOPE_LENGTH = 6;\r\n\r\n/**\r\n * Builds a *stateless* `formatMessage` pipeline for {@link LinkTransport}, packing action\r\n * payloads into a compact msgpackr binary frame instead of JSON. The `domain`/`id` route collapses to\r\n * a single integer drawn from a shared dictionary; `form`/`type`, the recomputable\r\n * `inputHash`/`outputHash`, and the per-frame `context.routing`/`context.timeCreated` are all dropped\r\n * (see {@link ENVELOPE}).\r\n *\r\n * No validation runs here: `incoming` blindly reconstructs the wire JSON shape and hands it back to\r\n * the connection, which flows into `ActionRuntime` → `domain.hydrateAnyAction()` where the Valibot\r\n * schemas validate it exactly as they would for a JSON frame.\r\n *\r\n * Both ends of the socket MUST construct the adapter with the same domains in the same order — the\r\n * integer dictionary is positional. Mismatched dictionaries will route to the wrong action.\r\n *\r\n * Because `incoming` returns `undefined` for text frames, a binary server can still serve plain-JSON\r\n * clients on the same runtime (the connection falls back to its built-in JSON parser).\r\n */\r\nexport function createBinaryWireAdapter(domains: ActionDomain<any>[]): IActionWireFormat {\r\n const { routeToInt, intToRoute } = buildActionRouteDictionary(domains);\r\n\r\n return {\r\n outgoing: (input: ITransportRouteActionParams): Uint8Array => {\r\n const json = input.action.toJsonObject();\r\n const routeKey = `${json.domain}:${json.id}`;\r\n const routeInt = routeToInt.get(routeKey);\r\n\r\n if (routeInt == null) {\r\n throw new Error(`[binary-wire] Cannot pack unregistered action route: ${routeKey}`);\r\n }\r\n\r\n const envelope = new Array(ENVELOPE_LENGTH);\r\n envelope[ENVELOPE.route] = routeInt;\r\n envelope[ENVELOPE.type] = PayloadTypeToInt[json.type];\r\n envelope[ENVELOPE.time] = json.time;\r\n envelope[ENVELOPE.cuid] = json.context.cuid;\r\n envelope[ENVELOPE.originClient] = json.context.originClient;\r\n envelope[ENVELOPE.payload] = extractWirePayload(json);\r\n\r\n return pack(envelope);\r\n },\r\n\r\n incoming: (frame: string | ArrayBuffer | Uint8Array | Blob) => {\r\n // Only binary frames are ours. Text frames fall through to the JSON parser; Blobs should have\r\n // been converted to a buffer by the connection before reaching us — if not, we can't unpack\r\n // them synchronously, so defer.\r\n let buffer: Uint8Array;\r\n if (frame instanceof ArrayBuffer) {\r\n buffer = new Uint8Array(frame);\r\n } else if (frame instanceof Uint8Array) {\r\n buffer = frame;\r\n } else {\r\n return undefined;\r\n }\r\n\r\n try {\r\n const envelope = unpack(buffer);\r\n\r\n if (!Array.isArray(envelope) || envelope.length !== ENVELOPE_LENGTH) return undefined;\r\n\r\n const routeMeta = intToRoute[envelope[ENVELOPE.route]];\r\n const payloadType = ReversePayloadType[envelope[ENVELOPE.type]];\r\n if (routeMeta == null || payloadType == null) return undefined;\r\n\r\n const time = envelope[ENVELOPE.time];\r\n // Rebuild the context: `routing` starts empty (the receiver re-stamps its own hops) and\r\n // `timeCreated` is approximated by the payload `time` — neither affects hydration/validation.\r\n const context = {\r\n cuid: envelope[ENVELOPE.cuid],\r\n timeCreated: time,\r\n routing: [],\r\n originClient: envelope[ENVELOPE.originClient],\r\n };\r\n\r\n return assembleWireJson(routeMeta, payloadType, time, context, envelope[ENVELOPE.payload]);\r\n } catch (e) {\r\n console.error(\"[binary-wire] Failed to unpack binary action frame\", e);\r\n return undefined;\r\n }\r\n },\r\n };\r\n}\r\n","import type { IActionTransportResolvers } from \"./Transport.types\";\r\nimport {\r\n type ETransportShape,\r\n type ITransportRouteActionParams,\r\n type ITransportRouteInfo,\r\n} from \"./Transport.types\";\r\nimport type { TransportConnection } from \"./TransportConnection\";\r\n\r\n/**\r\n * Context handed to a {@link Transport} definition when a handler builds a live connection from it.\r\n * Only bidirectional transports (WebSocket / Custom) make use of `resolvers`.\r\n */\r\nexport interface ITransportConnectionContext {\r\n resolvers?: IActionTransportResolvers;\r\n}\r\n\r\n/**\r\n * Reusable transport definition. Devs construct these (`secureTransport({ carrier: wsCarrier(url) })`,\r\n * `plainTransport({ carrier: httpCarrier(...) })`, …) and pass them to a\r\n * `ConnectorHandler`. A single\r\n * definition can be shared across multiple handlers — each handler builds its own live\r\n * {@link TransportConnection} via {@link TransportConnection._createConnection}.\r\n */\r\nexport abstract class Transport<T extends ETransportShape = ETransportShape> {\r\n abstract readonly type: T;\r\n\r\n /** Internal: build a fresh, per-handler live connection from this definition. */\r\n abstract _createConnection(ctx: ITransportConnectionContext): TransportConnection<T>;\r\n\r\n /**\r\n * Resolve human-readable info about how a specific action would be routed through this transport\r\n * (e.g. the request URL/method, or the WebSocket endpoint). Surfaced in the action devtools.\r\n */\r\n abstract getRouteInfo(input: ITransportRouteActionParams): ITransportRouteInfo;\r\n}\r\n","import { nanoid } from \"nanoid\";\r\nimport { EActionPayloadType } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport { ERunningActionUpdateType } from \"../../../ActionDefinition/Action/RunningAction.types\";\r\nimport { isActionPayload_Result_JsonObject } from \"../../../utils/isActionPayload_Result_JsonObject\";\r\nimport type { IExchangeCarrier, TFrame } from \"../Carrier/Carrier.types\";\r\nimport { createActionFrameCrypto, type IActionFrameCrypto } from \"../crypto/actionFrameCrypto\";\r\nimport {\r\n createClientHandshake,\r\n decodeHandshakeMessage,\r\n EHandshakeMessageType,\r\n ESecurityLevel,\r\n encodeHandshakeMessage,\r\n} from \"../crypto/actionHandshake\";\r\nimport { EErrId_NiceTransport, err_nice_transport } from \"../err_nice_transport\";\r\nimport type {\r\n IActionTransportReadyData_Methods,\r\n ISecureClientConfig,\r\n TSendActionDataMethod,\r\n TUpdateActionRunConfig,\r\n} from \"../Transport.types\";\r\nimport {\r\n base64ToBytes,\r\n bytesToBase64,\r\n decodeExchangeReply,\r\n encodeExchange,\r\n type TExchangeReply,\r\n type TExchangeRequest,\r\n} from \"./exchangeProtocol\";\r\n\r\n/**\r\n * Connector-side (dial-out) secure session over an {@link IExchangeCarrier} (HTTP): the request → single\r\n * correlated reply counterpart to the duplex `establishLinkSession`. The secure session is identical in\r\n * spirit — handshake, then per-frame crypto — but carried by independent exchanges rather than a push\r\n * channel, so it can deliver no unsolicited frame (`canPush = false`); each action's result rides the\r\n * reply to its own request, completing the {@link RunningAction} inline (there is no return path).\r\n *\r\n * At `none` there is no handshake or token: an `act` envelope carries the plaintext wire both ways. At\r\n * `authenticated`/`encrypted` a one-time handshake (two `hs` exchanges) yields a session token replayed\r\n * on every later `act`; at `encrypted` the wire is AES-GCM ciphertext.\r\n */\r\nexport interface IExchangeSessionContext {\r\n carrier: IExchangeCarrier;\r\n updateRunConfig?: TUpdateActionRunConfig;\r\n /** When present (and not `none`) the handshake runs at bring-up; absent ⇒ plain exchange. */\r\n secure?: ISecureClientConfig;\r\n}\r\n\r\ninterface IExchangeSecureState {\r\n token?: string;\r\n crypto?: IActionFrameCrypto;\r\n}\r\n\r\nconst textEncoder = new TextEncoder();\r\nconst textDecoder = new TextDecoder();\r\n\r\n/** Plain path (no handshake/token): every action rides a bare `act` envelope, plaintext both ways. */\r\nexport function finalizePlainExchangeMethods(\r\n ctx: IExchangeSessionContext,\r\n): IActionTransportReadyData_Methods {\r\n return buildExchangeMethods(ctx, {});\r\n}\r\n\r\n/** Secure path: run the handshake (two exchanges) once at bring-up, then reuse the token + crypto. */\r\nexport async function finalizeSecureExchangeMethods(\r\n ctx: IExchangeSessionContext & { secure: ISecureClientConfig },\r\n): Promise<IActionTransportReadyData_Methods> {\r\n const state = await runConnectorExchangeHandshake(ctx.carrier, ctx.secure);\r\n return buildExchangeMethods(ctx, state);\r\n}\r\n\r\nfunction buildExchangeMethods(\r\n ctx: IExchangeSessionContext,\r\n state: IExchangeSecureState,\r\n): IActionTransportReadyData_Methods {\r\n const sendActionData: TSendActionDataMethod = (inputs) => {\r\n void runExchange(ctx.carrier, state, inputs).catch((err) => inputs.runningAction._abort(err));\r\n };\r\n\r\n return { sendActionData, updateRunConfig: ctx.updateRunConfig };\r\n}\r\n\r\nasync function runExchange(\r\n carrier: IExchangeCarrier,\r\n state: IExchangeSecureState,\r\n inputs: Parameters<TSendActionDataMethod>[0],\r\n): Promise<void> {\r\n const { action, runningAction, timeout } = inputs;\r\n\r\n const ac = new AbortController();\r\n let timedOut = false;\r\n const timeoutId = setTimeout(() => {\r\n timedOut = true;\r\n ac.abort();\r\n }, timeout);\r\n const unsubscribe = runningAction.addUpdateListeners([\r\n (update) => {\r\n if (update.type === ERunningActionUpdateType.finished) {\r\n clearTimeout(timeoutId);\r\n ac.abort();\r\n }\r\n },\r\n ]);\r\n\r\n try {\r\n const request = await buildRequestEnvelope(state, action);\r\n const replyRaw = await carrier.exchange(encodeExchange(request), { signal: ac.signal });\r\n\r\n // Only a request awaits a reply (progress/result payloads aren't sent by a connector over exchange).\r\n if (action.type !== EActionPayloadType.request) return;\r\n\r\n const reply = decodeExchangeReply(asString(replyRaw));\r\n if (reply == null) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.invalid_action_response, {\r\n actionId: action.id,\r\n });\r\n }\r\n if (reply.k === \"err\") {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.send_failed, {\r\n actionState: action.type,\r\n actionId: action.id,\r\n message: reply.message,\r\n });\r\n }\r\n\r\n const wire = await extractReplyWire(state, reply);\r\n if (wire == null || !isActionPayload_Result_JsonObject(wire)) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.invalid_action_response, {\r\n actionId: action.id,\r\n });\r\n }\r\n\r\n runningAction._completeWithResult(action._domain.hydrateResultPayload(wire));\r\n } catch (err) {\r\n if (timedOut) {\r\n throw err_nice_transport.fromId(EErrId_NiceTransport.timeout, { timeout });\r\n }\r\n throw err;\r\n } finally {\r\n clearTimeout(timeoutId);\r\n unsubscribe();\r\n }\r\n}\r\n\r\nasync function buildRequestEnvelope(\r\n state: IExchangeSecureState,\r\n action: Parameters<TSendActionDataMethod>[0][\"action\"],\r\n): Promise<TExchangeRequest> {\r\n const wire = action.toJsonObject();\r\n if (state.crypto != null) {\r\n const ciphertext = await state.crypto.encryptFrame(textEncoder.encode(JSON.stringify(wire)));\r\n return { k: \"act\", t: state.token, c: bytesToBase64(ciphertext) };\r\n }\r\n return { k: \"act\", t: state.token, w: wire };\r\n}\r\n\r\nasync function extractReplyWire(\r\n state: IExchangeSecureState,\r\n reply: TExchangeReply,\r\n): Promise<ReturnType<Parameters<TSendActionDataMethod>[0][\"action\"][\"toJsonObject\"]> | undefined> {\r\n if (reply.k !== \"act\") return undefined;\r\n if (\"c\" in reply) {\r\n if (state.crypto == null) return undefined;\r\n const plain = await state.crypto.decryptFrame(base64ToBytes(reply.c));\r\n return JSON.parse(textDecoder.decode(plain));\r\n }\r\n return reply.w;\r\n}\r\n\r\nasync function runConnectorExchangeHandshake(\r\n carrier: IExchangeCarrier,\r\n secure: ISecureClientConfig,\r\n): Promise<IExchangeSecureState> {\r\n await secure.link.initialize();\r\n\r\n const handshake = createClientHandshake({\r\n link: secure.link,\r\n localCoordinate: secure.localCoordinate,\r\n dictionaryVersion: secure.dictionaryVersion,\r\n securityLevel: secure.securityLevel,\r\n });\r\n const hsid = nanoid();\r\n\r\n // Exchange 1: hello → welcome.\r\n const hello = await handshake.createHello();\r\n const welcomeReply = decodeExchangeReply(\r\n asString(\r\n await carrier.exchange(encodeExchange({ k: \"hs\", hsid, m: encodeHandshakeMessage(hello) })),\r\n ),\r\n );\r\n if (welcomeReply?.k !== \"hs\") throw new Error(\"[exchange-handshake] expected a welcome reply\");\r\n const welcome = decodeHandshakeMessage(welcomeReply.m);\r\n if (welcome == null) throw new Error(\"[exchange-handshake] malformed welcome\");\r\n if (welcome.t === EHandshakeMessageType.reject) {\r\n throw new Error(`[exchange-handshake] rejected by peer: ${welcome.reason}`);\r\n }\r\n if (welcome.t !== EHandshakeMessageType.welcome) {\r\n throw new Error(`[exchange-handshake] expected welcome, got ${welcome.t}`);\r\n }\r\n\r\n // Exchange 2: prove → accept (+ session token).\r\n const prove = await handshake.onWelcome(welcome);\r\n const acceptReply = decodeExchangeReply(\r\n asString(\r\n await carrier.exchange(encodeExchange({ k: \"hs\", hsid, m: encodeHandshakeMessage(prove) })),\r\n ),\r\n );\r\n if (acceptReply?.k !== \"hs\") throw new Error(\"[exchange-handshake] expected an accept reply\");\r\n const accept = decodeHandshakeMessage(acceptReply.m);\r\n if (accept == null) throw new Error(\"[exchange-handshake] malformed accept\");\r\n if (accept.t === EHandshakeMessageType.reject) {\r\n throw new Error(`[exchange-handshake] rejected by peer: ${accept.reason}`);\r\n }\r\n if (accept.t !== EHandshakeMessageType.accept) {\r\n throw new Error(`[exchange-handshake] expected accept, got ${accept.t}`);\r\n }\r\n if (acceptReply.t == null) throw new Error(\"[exchange-handshake] accept missing session token\");\r\n\r\n const result = await handshake.onAccept(accept);\r\n const crypto =\r\n result.securityLevel === ESecurityLevel.encrypted\r\n ? createActionFrameCrypto({ link: secure.link, linkedClientId: result.linkedClientId })\r\n : undefined;\r\n\r\n return { token: acceptReply.t, crypto };\r\n}\r\n\r\nfunction asString(frame: TFrame): string {\r\n if (typeof frame === \"string\") return frame;\r\n return textDecoder.decode(frame instanceof ArrayBuffer ? new Uint8Array(frame) : frame);\r\n}\r\n","import {\r\n ETransportStatus,\r\n type IActionTransportReadyData_Base,\r\n type TTransportStatusInfo,\r\n type TTransportStatusInfo_GetTransport_Output,\r\n} from \"../Transport.types\";\r\n\r\nexport function addTransportStatusMetadata<READY extends IActionTransportReadyData_Base>(\r\n transportStatus: TTransportStatusInfo_GetTransport_Output<READY>,\r\n): TTransportStatusInfo<READY> {\r\n if (transportStatus.status === ETransportStatus.ready) {\r\n return {\r\n status: ETransportStatus.ready,\r\n readyData: transportStatus.readyData,\r\n };\r\n }\r\n\r\n if (transportStatus.status === ETransportStatus.initializing) {\r\n return {\r\n status: ETransportStatus.initializing,\r\n initializationPromise: transportStatus.initializationPromise,\r\n timeStarted: Date.now(),\r\n };\r\n }\r\n\r\n if (transportStatus.status === ETransportStatus.failed) {\r\n return {\r\n status: ETransportStatus.failed,\r\n error: transportStatus.error,\r\n timeFailed: Date.now(),\r\n };\r\n }\r\n\r\n if (transportStatus.status === ETransportStatus.unsupported) {\r\n return {\r\n status: ETransportStatus.unsupported,\r\n };\r\n }\r\n\r\n return {\r\n status: ETransportStatus.uninitialized,\r\n };\r\n}\r\n","import { addTransportStatusMetadata } from \"./helpers/addTransportStatusMetadata\";\r\nimport type { Transport } from \"./Transport\";\r\nimport {\r\n type ETransportShape,\r\n ETransportStatus,\r\n type IActionTransportDef,\r\n type IActionTransportInitialized,\r\n type IActionTransportReadyData_Base,\r\n type IActionTransportReadyData_Methods,\r\n type ITransportRouteActionParams,\r\n type ITransportRouteInfo,\r\n type TTransportInitializationFinishedInfo,\r\n type TTransportStatusInfo,\r\n} from \"./Transport.types\";\r\n\r\nlet transportOrd = 0;\r\n\r\n/**\r\n * Live, per-handler transport runtime built from a reusable {@link Transport} definition. Holds the\r\n * connection-scoped state (ordinal, initialized config, sockets / abort sets) that must not be shared\r\n * across handlers. Construct these via `definition._createConnection(...)`, never directly.\r\n */\r\nexport abstract class TransportConnection<\r\n T extends ETransportShape = ETransportShape,\r\n RP extends ITransportRouteActionParams = ITransportRouteActionParams,\r\n RD extends IActionTransportReadyData_Base = IActionTransportReadyData_Base,\r\n I extends IActionTransportInitialized<RP, RD> = IActionTransportInitialized<RP, RD>,\r\n DEF extends IActionTransportDef<T, I> = IActionTransportDef<T, I>,\r\n> {\r\n readonly transOrd = transportOrd++;\r\n readonly type: T;\r\n readonly initialized: I;\r\n\r\n /** Backref to the public definition that created this connection (used for devtools route info). */\r\n definition?: Transport<T>;\r\n\r\n constructor(readonly def: DEF) {\r\n this.type = def.type;\r\n this.initialized = def.initialize();\r\n }\r\n\r\n /**\r\n * Devtools route info for an action routed through this live connection. Defaults to the stateless\r\n * {@link definition}'s info; connections override to enrich it from live state (e.g. the actual\r\n * resolved socket URL) when the definition couldn't resolve it on its own.\r\n */\r\n getRouteInfo(input: RP): ITransportRouteInfo | undefined {\r\n return this.definition?.getRouteInfo(input);\r\n }\r\n\r\n /**\r\n * Build the live send/receive methods from a `ready` readyData, synchronously. This is the plain\r\n * (no-handshake) path and the only required per-transport hook. Stream carriers that must await the\r\n * carrier opening and/or run a handshake additionally override {@link _needsAsyncBringUp},\r\n * {@link _awaitCarrierReady}, and {@link _finalizeReady}.\r\n */\r\n protected abstract _finalizeTransportMethods(inputs: RD): IActionTransportReadyData_Methods;\r\n\r\n /**\r\n * Whether a `ready`-status transport still needs asynchronous bring-up before its methods exist —\r\n * awaiting the carrier to open and/or running a handshake. Default `false`: a stateless transport\r\n * (HTTP) is usable the instant `getTransport` reports `ready`, so it stays a terminal *synchronous*\r\n * fallback in {@link ConnectionTransportManager}. Stream carriers (Link/WS) override to `true`.\r\n */\r\n protected _needsAsyncBringUp(_readyData: RD): boolean {\r\n return false;\r\n }\r\n\r\n /** Await the carrier becoming ready to send (e.g. a socket `open`). Default: nothing to await. */\r\n protected _awaitCarrierReady(_readyData: RD): Promise<void> {\r\n return Promise.resolve();\r\n }\r\n\r\n /**\r\n * Finalize during async bring-up — may run a handshake, so it can be async. Defaults to the\r\n * synchronous {@link _finalizeTransportMethods}; secure stream carriers override to branch plain/secure.\r\n */\r\n protected _finalizeReady(\r\n readyData: RD,\r\n ): IActionTransportReadyData_Methods | Promise<IActionTransportReadyData_Methods> {\r\n return this._finalizeTransportMethods(readyData);\r\n }\r\n\r\n protected _getCacheKey(input: RP): string | null {\r\n const parts = this.initialized.getTransportCacheKey?.(input);\r\n if (parts == null) return null;\r\n return parts.join(\"\\x00\");\r\n }\r\n\r\n getCacheKey(input: RP): string | null {\r\n const inner = this._getCacheKey(input);\r\n if (inner == null) return null;\r\n return `${this.transOrd}:${inner}`;\r\n }\r\n\r\n /**\r\n * Whether this transport can serve the given action right now. Consulted by the manager before\r\n * cache-key resolution and `getTransport`; a `false` result skips this transport (treated as\r\n * `unsupported`) and the manager falls through to the next in preference order. Defaults to `true`\r\n * when the transport declares no gate.\r\n */\r\n isAvailable(input: RP): boolean {\r\n return this.initialized.isAvailable?.(input) ?? true;\r\n }\r\n\r\n getTransport(input: RP): TTransportStatusInfo<IActionTransportReadyData_Methods> {\r\n return this._processTransportStatus(input);\r\n }\r\n\r\n protected _processTransportStatus(\r\n input: RP,\r\n ): TTransportStatusInfo<IActionTransportReadyData_Methods> {\r\n const statusInfo = addTransportStatusMetadata(this.initialized.getTransport(input));\r\n\r\n if (statusInfo.status === ETransportStatus.ready) {\r\n // Already-usable + stateless → finalize synchronously (terminal fallback). Otherwise report\r\n // `initializing` and bring the carrier up (await open, run handshake) off the dispatch path.\r\n if (!this._needsAsyncBringUp(statusInfo.readyData)) {\r\n return {\r\n status: ETransportStatus.ready,\r\n readyData: this._finalizeTransportMethods(statusInfo.readyData),\r\n };\r\n }\r\n return {\r\n status: ETransportStatus.initializing,\r\n timeStarted: Date.now(),\r\n initializationPromise: this._bringUp(statusInfo.readyData),\r\n };\r\n }\r\n\r\n if (statusInfo.status === ETransportStatus.initializing) {\r\n const initializationPromise: Promise<\r\n TTransportInitializationFinishedInfo<IActionTransportReadyData_Methods>\r\n > = statusInfo.initializationPromise.then((result) =>\r\n result.status === ETransportStatus.ready ? this._bringUp(result.readyData) : result,\r\n );\r\n return {\r\n status: ETransportStatus.initializing,\r\n timeStarted: statusInfo.timeStarted,\r\n initializationPromise,\r\n };\r\n }\r\n\r\n // unsupported / failed / uninitialized — pass through.\r\n return statusInfo;\r\n }\r\n\r\n /** Await carrier readiness, then finalize (possibly running a handshake) into the live methods. */\r\n private async _bringUp(\r\n readyData: RD,\r\n ): Promise<TTransportInitializationFinishedInfo<IActionTransportReadyData_Methods>> {\r\n await this._awaitCarrierReady(readyData);\r\n return {\r\n status: ETransportStatus.ready,\r\n readyData: await this._finalizeReady(readyData),\r\n };\r\n }\r\n}\r\n","import { ESecurityLevel } from \"../crypto/actionHandshake\";\r\nimport {\r\n finalizePlainExchangeMethods,\r\n finalizeSecureExchangeMethods,\r\n type IExchangeSessionContext,\r\n} from \"../SecureSession/establishExchangeSession\";\r\nimport {\r\n ETransportShape,\r\n type IActionTransportReadyData_Methods,\r\n type ITransportRouteActionParams,\r\n} from \"../Transport.types\";\r\nimport { TransportConnection } from \"../TransportConnection\";\r\nimport type {\r\n IActionTransportDef_Exchange,\r\n IActionTransportInitialized_Exchange,\r\n IActionTransportReadyData_Exchange,\r\n} from \"./TransportExchange.types\";\r\n\r\n/**\r\n * Carrier-agnostic live connection for the exchange (request → single reply) shape — the HTTP\r\n * counterpart to {@link LinkConnection}. It owns only the bring-up (run the secure handshake on first\r\n * use); the request/reply lifecycle + crypto live in the shared `establishExchangeSession`.\r\n */\r\nexport class ExchangeConnection extends TransportConnection<\r\n ETransportShape.exchange,\r\n ITransportRouteActionParams,\r\n IActionTransportReadyData_Exchange,\r\n IActionTransportInitialized_Exchange,\r\n IActionTransportDef_Exchange\r\n> {\r\n constructor(def: Omit<IActionTransportDef_Exchange, \"type\">) {\r\n super({ ...def, type: ETransportShape.exchange });\r\n }\r\n\r\n protected override _getCacheKey(input: ITransportRouteActionParams): string {\r\n return this.initialized.getTransportCacheKey?.(input).join(\"\\x00\") ?? \"\";\r\n }\r\n\r\n // Only a secure exchange needs async bring-up (the handshake). A plain (`none`) exchange is usable the\r\n // instant the carrier opens — finalized synchronously like HTTP today.\r\n protected override _needsAsyncBringUp(data: IActionTransportReadyData_Exchange): boolean {\r\n return data.secureChannel != null && data.secureChannel.securityLevel !== ESecurityLevel.none;\r\n }\r\n\r\n protected override _finalizeReady(\r\n data: IActionTransportReadyData_Exchange,\r\n ): IActionTransportReadyData_Methods | Promise<IActionTransportReadyData_Methods> {\r\n const secure = data.secureChannel;\r\n if (secure != null && secure.securityLevel !== ESecurityLevel.none) {\r\n return finalizeSecureExchangeMethods({ ...this._sessionContext(data), secure });\r\n }\r\n return this._finalizeTransportMethods(data);\r\n }\r\n\r\n _finalizeTransportMethods(\r\n data: IActionTransportReadyData_Exchange,\r\n ): IActionTransportReadyData_Methods {\r\n return finalizePlainExchangeMethods(this._sessionContext(data));\r\n }\r\n\r\n private _sessionContext(data: IActionTransportReadyData_Exchange): IExchangeSessionContext {\r\n return {\r\n carrier: data.carrier,\r\n updateRunConfig: data.updateRunConfig,\r\n secure: data.secureChannel,\r\n };\r\n }\r\n}\r\n","import type { IExchangeCarrier } from \"../Carrier/Carrier.types\";\r\nimport { type ITransportConnectionContext, Transport } from \"../Transport\";\r\nimport {\r\n ETransportShape,\r\n ETransportStatus,\r\n type ISecureClientConfig,\r\n type ITransportRouteActionParams,\r\n type ITransportRouteInfo,\r\n type TUpdateActionRunConfig,\r\n} from \"../Transport.types\";\r\nimport { ExchangeConnection } from \"./ExchangeConnection\";\r\n\r\nexport interface IExchangeTransportOptions {\r\n /** Open (or reuse) the exchange carrier for an action — e.g. `httpCarrier(...).open`. */\r\n openCarrier: (input: ITransportRouteActionParams) => IExchangeCarrier;\r\n /** Secure config; when set (and `securityLevel !== none`) the handshake runs once at bring-up. */\r\n security?: ISecureClientConfig;\r\n updateRunConfig?: TUpdateActionRunConfig;\r\n /** Keys identifying a reusable session, so one carrier is shared across actions to the same peer. */\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /**\r\n * Optional availability gate. When it returns `false`, the manager skips this transport for that action\r\n * (reporting `unsupported`) and falls through to the next — without opening the carrier or computing its\r\n * cache key. Re-evaluated per dispatch, so the transport can become available later with no reconnect.\r\n */\r\n available?: (input: ITransportRouteActionParams) => boolean;\r\n /** Short label for the devtools chip (defaults to \"exchange\"). */\r\n label?: string;\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n}\r\n\r\n/**\r\n * A carrier-agnostic exchange (request → single reply) transport: it drives nice-action's secure session\r\n * over any {@link IExchangeCarrier} (HTTP being the one built-in). The duplex counterpart is\r\n * {@link LinkTransport}; this is the no-push half — its reply rides the response to its own request, so it\r\n * can't deliver an unsolicited frame (the runtime never picks it for the return path).\r\n */\r\nexport class ExchangeTransport extends Transport<ETransportShape.exchange> {\r\n readonly type = ETransportShape.exchange;\r\n\r\n constructor(private readonly options: IExchangeTransportOptions) {\r\n super();\r\n }\r\n\r\n static create(options: IExchangeTransportOptions): ExchangeTransport {\r\n return new ExchangeTransport(options);\r\n }\r\n\r\n _createConnection(_ctx: ITransportConnectionContext): ExchangeConnection {\r\n const options = this.options;\r\n\r\n return new ExchangeConnection({\r\n initialize: () => ({\r\n getTransportCacheKey: options.getTransportCacheKey,\r\n isAvailable: options.available,\r\n getTransport: (input) => ({\r\n status: ETransportStatus.ready,\r\n readyData: {\r\n carrier: options.openCarrier(input),\r\n secureChannel: options.security,\r\n updateRunConfig: options.updateRunConfig,\r\n },\r\n }),\r\n }),\r\n });\r\n }\r\n\r\n getRouteInfo(input: ITransportRouteActionParams): ITransportRouteInfo {\r\n if (this.options.getRouteInfo != null) return this.options.getRouteInfo(input);\r\n return {\r\n carrierLabel: this.options.label ?? \"exchange\",\r\n summary: this.options.label ?? \"exchange\",\r\n };\r\n }\r\n}\r\n","import type { IActionTransportResolvers } from \"../Transport.types\";\r\n\r\nexport const createUnsetTransportResolvers = (\r\n transportLabel: string,\r\n): IActionTransportResolvers => ({\r\n onIncomingActionDataJson: (json) => {\r\n console.warn(\r\n `Received incoming action JSON [${json.domain}:${json.id}] on Transport [${transportLabel}] but no incoming data listener has been set.`,\r\n );\r\n },\r\n});\r\n","import type { NiceError } from \"@nice-code/error\";\r\nimport { EActionPayloadType } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { RunningAction } from \"../../../ActionDefinition/Action/RunningAction\";\r\nimport { ERunningActionUpdateType } from \"../../../ActionDefinition/Action/RunningAction.types\";\r\nimport { decodeActionFrame } from \"../../../utils/decodeActionFrame\";\r\nimport type { IDuplexCarrier } from \"../Carrier/Carrier.types\";\r\nimport { createActionFrameCrypto, type IActionFrameCrypto } from \"../crypto/actionFrameCrypto\";\r\nimport {\r\n createClientHandshake,\r\n decodeHandshakeMessage,\r\n EHandshakeMessageType,\r\n ESecurityLevel,\r\n encodeHandshakeMessage,\r\n type THandshakeMessage,\r\n} from \"../crypto/actionHandshake\";\r\nimport { EErrId_NiceTransport, err_nice_transport } from \"../err_nice_transport\";\r\nimport type { TLinkFormatMessage } from \"../Link/TransportLink.types\";\r\nimport type {\r\n IActionTransportReadyData_Methods,\r\n IActionTransportResolvers,\r\n ISecureClientConfig,\r\n TSendActionDataMethod,\r\n TUpdateActionRunConfig,\r\n} from \"../Transport.types\";\r\nimport { createFrameCryptoPipe, type IFrameCryptoPipe } from \"./frameCryptoPipe\";\r\n\r\nconst HANDSHAKE_TIMEOUT_MS = 15_000;\r\n\r\n/**\r\n * Connector-side (dial-out) secure session over an {@link IDuplexCarrier}: the handshake → frame crypto\r\n * → codec → action send/receive loop. The crypto itself (ordered encrypt-send / decrypt) lives in the\r\n * shared {@link createFrameCryptoPipe}, which the acceptor reuses too — so the secure logic lives once.\r\n * `LinkConnection` (WebRTC, Bluetooth, in-memory, …) and `WebSocketConnection` (socket wrapped as a\r\n * carrier) both delegate here.\r\n */\r\nexport interface ILinkSessionContext {\r\n channel: IDuplexCarrier;\r\n resolvers: IActionTransportResolvers;\r\n formatMessage?: TLinkFormatMessage;\r\n updateRunConfig?: TUpdateActionRunConfig;\r\n /** The error used to abort in-flight actions when the channel is closed/gone (carrier-specific). */\r\n makeDisconnectError: (actionId: string) => NiceError;\r\n}\r\n\r\n/** Plain path (no handshake): route every inbound frame to the runtime; send without crypto. */\r\nexport function finalizePlainLinkMethods(\r\n ctx: ILinkSessionContext,\r\n): IActionTransportReadyData_Methods {\r\n const disconnectListeners: (() => void)[] = [];\r\n const abortSet = new Set<RunningAction<any, any>>();\r\n const pipe = makePipe(ctx, undefined);\r\n\r\n ctx.channel.attach({\r\n onMessage: (frame) => void handleIncomingActionFrame(ctx, pipe, frame),\r\n onClose: () => onChannelClosed(ctx, disconnectListeners, abortSet),\r\n onError: () => onChannelClosed(ctx, disconnectListeners, abortSet),\r\n });\r\n\r\n return buildSendMethods(ctx, pipe, disconnectListeners, abortSet);\r\n}\r\n\r\n/**\r\n * Secure path: a single message handler feeds the handshake until it completes, then routes action\r\n * frames (decrypting at the `encrypted` level). Frames that race ahead of activation are buffered and\r\n * flushed once the handshake lands, so nothing is lost.\r\n */\r\nexport async function finalizeSecureLinkMethods(\r\n ctx: ILinkSessionContext & { secure: ISecureClientConfig },\r\n): Promise<IActionTransportReadyData_Methods> {\r\n const disconnectListeners: (() => void)[] = [];\r\n const abortSet = new Set<RunningAction<any, any>>();\r\n\r\n // Holder so the (synchronously-attached) message handler can reach the pipe once the handshake builds\r\n // it, without a single-assignment `let`.\r\n const session: { pipe?: IFrameCryptoPipe } = {};\r\n let active = false;\r\n const handshakeQueue: THandshakeMessage[] = [];\r\n const handshakeWaiters: ((message: THandshakeMessage) => void)[] = [];\r\n const pendingActionFrames: (string | ArrayBuffer | Uint8Array)[] = [];\r\n\r\n ctx.channel.attach({\r\n onMessage: (frame) => {\r\n if (active && session.pipe != null) {\r\n void handleIncomingActionFrame(ctx, session.pipe, frame);\r\n return;\r\n }\r\n // Handshake phase: text frames are control messages; buffer anything else for after activation.\r\n if (typeof frame === \"string\") {\r\n const message = decodeHandshakeMessage(frame);\r\n if (message != null) {\r\n const waiter = handshakeWaiters.shift();\r\n if (waiter != null) waiter(message);\r\n else handshakeQueue.push(message);\r\n return;\r\n }\r\n }\r\n pendingActionFrames.push(frame);\r\n },\r\n onClose: () => onChannelClosed(ctx, disconnectListeners, abortSet),\r\n onError: () => onChannelClosed(ctx, disconnectListeners, abortSet),\r\n });\r\n\r\n const nextHandshakeMessage = (): Promise<THandshakeMessage> => {\r\n const queued = handshakeQueue.shift();\r\n if (queued != null) return Promise.resolve(queued);\r\n return new Promise<THandshakeMessage>((resolve, reject) => {\r\n const timeout = setTimeout(\r\n () => reject(new Error(\"[link-handshake] timed out waiting for peer reply\")),\r\n HANDSHAKE_TIMEOUT_MS,\r\n );\r\n handshakeWaiters.push((message) => {\r\n clearTimeout(timeout);\r\n resolve(message);\r\n });\r\n });\r\n };\r\n\r\n const crypto = await runClientHandshake(ctx.channel, ctx.secure, nextHandshakeMessage);\r\n const pipe = makePipe(ctx, crypto);\r\n session.pipe = pipe;\r\n\r\n active = true;\r\n for (const frame of pendingActionFrames) await handleIncomingActionFrame(ctx, pipe, frame);\r\n pendingActionFrames.length = 0;\r\n\r\n return buildSendMethods(ctx, pipe, disconnectListeners, abortSet);\r\n}\r\n\r\nfunction makePipe(\r\n ctx: ILinkSessionContext,\r\n crypto: IActionFrameCrypto | undefined,\r\n): IFrameCryptoPipe {\r\n return createFrameCryptoPipe({\r\n write: (frame) => ctx.channel.send(frame),\r\n isOpen: () => ctx.channel.isOpen(),\r\n crypto,\r\n });\r\n}\r\n\r\nasync function runClientHandshake(\r\n channel: IDuplexCarrier,\r\n secure: ISecureClientConfig,\r\n nextHandshakeMessage: () => Promise<THandshakeMessage>,\r\n): Promise<IActionFrameCrypto | undefined> {\r\n await secure.link.initialize();\r\n\r\n const handshake = createClientHandshake({\r\n link: secure.link,\r\n localCoordinate: secure.localCoordinate,\r\n dictionaryVersion: secure.dictionaryVersion,\r\n securityLevel: secure.securityLevel,\r\n });\r\n\r\n channel.send(encodeHandshakeMessage(await handshake.createHello()));\r\n\r\n const welcome = await nextHandshakeMessage();\r\n if (welcome.t === EHandshakeMessageType.reject) {\r\n throw new Error(`[link-handshake] rejected by peer: ${welcome.reason}`);\r\n }\r\n if (welcome.t !== EHandshakeMessageType.welcome) {\r\n throw new Error(`[link-handshake] expected welcome, got ${welcome.t}`);\r\n }\r\n\r\n channel.send(encodeHandshakeMessage(await handshake.onWelcome(welcome)));\r\n\r\n const accept = await nextHandshakeMessage();\r\n if (accept.t === EHandshakeMessageType.reject) {\r\n throw new Error(`[link-handshake] rejected by peer: ${accept.reason}`);\r\n }\r\n if (accept.t !== EHandshakeMessageType.accept) {\r\n throw new Error(`[link-handshake] expected accept, got ${accept.t}`);\r\n }\r\n\r\n const result = await handshake.onAccept(accept);\r\n return result.securityLevel === ESecurityLevel.encrypted\r\n ? createActionFrameCrypto({ link: secure.link, linkedClientId: result.linkedClientId })\r\n : undefined;\r\n}\r\n\r\nfunction buildSendMethods(\r\n ctx: ILinkSessionContext,\r\n pipe: IFrameCryptoPipe,\r\n disconnectListeners: (() => void)[],\r\n abortSet: Set<RunningAction<any, any>>,\r\n): IActionTransportReadyData_Methods {\r\n const channel = ctx.channel;\r\n\r\n const sendActionData: TSendActionDataMethod = (inputs) => {\r\n const { action, runningAction, timeout } = inputs;\r\n\r\n if (!channel.isOpen()) {\r\n if (action.type === EActionPayloadType.request) {\r\n runningAction._abort(ctx.makeDisconnectError(action.id));\r\n }\r\n return;\r\n }\r\n\r\n if (action.type === EActionPayloadType.request) {\r\n abortSet.add(runningAction);\r\n const timeoutId = setTimeout(() => {\r\n runningAction._abort(err_nice_transport.fromId(EErrId_NiceTransport.timeout, { timeout }));\r\n }, timeout);\r\n runningAction.addUpdateListeners([\r\n (update) => {\r\n if (update.type === ERunningActionUpdateType.finished) {\r\n clearTimeout(timeoutId);\r\n abortSet.delete(runningAction);\r\n }\r\n },\r\n ]);\r\n }\r\n\r\n pipe.send(ctx.formatMessage?.outgoing(inputs) ?? JSON.stringify(inputs.action.toJsonObject()));\r\n };\r\n\r\n return {\r\n sendActionData,\r\n updateRunConfig: ctx.updateRunConfig,\r\n addOnDisconnectListener: (cb) => {\r\n disconnectListeners.push(cb);\r\n },\r\n disconnect: () => {\r\n try {\r\n channel.close();\r\n } catch {\r\n // already closing/closed — the close handler still runs cleanup\r\n }\r\n },\r\n sendReturnData: (payload, clients) => {\r\n const formatted =\r\n clients != null ? ctx.formatMessage?.outgoing({ action: payload, ...clients }) : undefined;\r\n pipe.send(formatted ?? JSON.stringify(payload.toJsonObject()));\r\n },\r\n };\r\n}\r\n\r\nasync function handleIncomingActionFrame(\r\n ctx: ILinkSessionContext,\r\n pipe: IFrameCryptoPipe,\r\n frame: string | ArrayBuffer | Uint8Array,\r\n): Promise<void> {\r\n const decoded = await pipe.decryptIncoming(frame);\r\n if (decoded === undefined) return;\r\n\r\n const rawJson = decodeActionFrame(decoded, ctx.formatMessage);\r\n if (rawJson != null) ctx.resolvers.onIncomingActionDataJson(rawJson);\r\n}\r\n\r\nfunction onChannelClosed(\r\n ctx: ILinkSessionContext,\r\n disconnectListeners: (() => void)[],\r\n abortSet: Set<RunningAction<any, any>>,\r\n): void {\r\n for (const cb of disconnectListeners) cb();\r\n const error = ctx.makeDisconnectError(\"—\");\r\n for (const ra of [...abortSet]) ra._abort(error);\r\n}\r\n","import type { NiceError } from \"@nice-code/error\";\r\nimport { ESecurityLevel } from \"../crypto/actionHandshake\";\r\nimport { EErrId_NiceTransport, err_nice_transport } from \"../err_nice_transport\";\r\nimport { createUnsetTransportResolvers } from \"../helpers/createUnsetTransportResolvers\";\r\nimport {\r\n finalizePlainLinkMethods,\r\n finalizeSecureLinkMethods,\r\n type ILinkSessionContext,\r\n} from \"../SecureSession/establishLinkSession\";\r\nimport {\r\n ETransportShape,\r\n type IActionTransportReadyData_Methods,\r\n type IActionTransportResolvers,\r\n type ITransportRouteActionParams,\r\n} from \"../Transport.types\";\r\nimport { TransportConnection } from \"../TransportConnection\";\r\nimport type {\r\n IActionTransportDef_Link,\r\n IActionTransportInitialized_Link,\r\n IActionTransportReadyData_Link,\r\n} from \"./TransportLink.types\";\r\n\r\n/** Abort error for a closed link channel (carrier-neutral — the carrier itself isn't named). */\r\nfunction linkDisconnectError(actionId: string): NiceError {\r\n return err_nice_transport.fromId(EErrId_NiceTransport.send_failed, {\r\n actionId,\r\n actionState: \"request\",\r\n message: \"link channel disconnected\",\r\n });\r\n}\r\n\r\n/**\r\n * Carrier-agnostic live connection. It owns only the *bring-up* (open the carrier, then run the secure\r\n * session); the session itself — handshake, frame crypto, codec, send/receive — lives in the shared\r\n * {@link finalizeSecureLinkMethods}/{@link finalizePlainLinkMethods}, so a WebSocket, a WebRTC data\r\n * channel, a Bluetooth characteristic, and an in-memory pipe all run the identical secure layer.\r\n */\r\nexport class LinkConnection extends TransportConnection<\r\n ETransportShape.duplex,\r\n ITransportRouteActionParams,\r\n IActionTransportReadyData_Link,\r\n IActionTransportInitialized_Link,\r\n IActionTransportDef_Link\r\n> {\r\n private resolvers: IActionTransportResolvers;\r\n\r\n constructor(def: Omit<IActionTransportDef_Link, \"type\">, resolvers?: IActionTransportResolvers) {\r\n super({ ...def, type: ETransportShape.duplex });\r\n this.resolvers = resolvers ?? createUnsetTransportResolvers(\"link\");\r\n }\r\n\r\n protected override _getCacheKey(input: ITransportRouteActionParams): string {\r\n return this.initialized.getTransportCacheKey?.(input).join(\"\\x00\") ?? \"\";\r\n }\r\n\r\n // A link is always brought up asynchronously: open the carrier (`channel.ready`), then run the\r\n // handshake when secure. The base reports `initializing` and drives these hooks.\r\n protected override _needsAsyncBringUp(): boolean {\r\n return true;\r\n }\r\n\r\n protected override _awaitCarrierReady(data: IActionTransportReadyData_Link): Promise<void> {\r\n return data.channel.ready;\r\n }\r\n\r\n protected override _finalizeReady(\r\n data: IActionTransportReadyData_Link,\r\n ): IActionTransportReadyData_Methods | Promise<IActionTransportReadyData_Methods> {\r\n const secure = data.secureChannel;\r\n if (secure != null && secure.securityLevel !== ESecurityLevel.none) {\r\n return finalizeSecureLinkMethods({ ...this._sessionContext(data), secure });\r\n }\r\n return this._finalizeTransportMethods(data);\r\n }\r\n\r\n private _sessionContext(data: IActionTransportReadyData_Link): ILinkSessionContext {\r\n return {\r\n channel: data.channel,\r\n resolvers: this.resolvers,\r\n formatMessage: data.formatMessage,\r\n updateRunConfig: data.updateRunConfig,\r\n makeDisconnectError: linkDisconnectError,\r\n };\r\n }\r\n\r\n // Public (not `protected`) so the binary-frame test can finalize a connection's methods directly.\r\n _finalizeTransportMethods(\r\n data: IActionTransportReadyData_Link,\r\n ): IActionTransportReadyData_Methods {\r\n return finalizePlainLinkMethods(this._sessionContext(data));\r\n }\r\n}\r\n","import type { IDuplexCarrier } from \"../Carrier/Carrier.types\";\r\nimport { type ITransportConnectionContext, Transport } from \"../Transport\";\r\nimport {\r\n ETransportShape,\r\n ETransportStatus,\r\n type ISecureClientConfig,\r\n type ITransportRouteActionParams,\r\n type ITransportRouteInfo,\r\n type TUpdateActionRunConfig,\r\n} from \"../Transport.types\";\r\nimport { LinkConnection } from \"./LinkConnection\";\r\nimport type { TLinkFormatMessage } from \"./TransportLink.types\";\r\n\r\nexport interface ILinkTransportOptions {\r\n /**\r\n * Open (or reuse) the carrier for an action — a WebSocket adapter, a WebRTC data channel, a Bluetooth\r\n * characteristic, an in-memory pipe, anything that satisfies {@link IDuplexCarrier}.\r\n */\r\n openChannel: (input: ITransportRouteActionParams) => IDuplexCarrier;\r\n /** Shared codec for every channel (stateless). */\r\n formatMessage?: TLinkFormatMessage;\r\n /**\r\n * Per-channel codec factory — called once per opened channel so stateful codecs (e.g. the binary\r\n * session) get their own instance. Takes precedence over `formatMessage`.\r\n */\r\n createFormatMessage?: () => TLinkFormatMessage;\r\n /** Secure-channel config; when set (and `securityLevel !== none`) the handshake runs on init. */\r\n security?: ISecureClientConfig;\r\n updateRunConfig?: TUpdateActionRunConfig;\r\n /** Keys identifying a reusable channel, so one carrier is shared across actions to the same peer. */\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /**\r\n * Optional availability gate. When it returns `false`, the manager skips this transport for that action\r\n * (reporting `unsupported`) and falls through to the next — without opening the carrier or computing its\r\n * cache key. Re-evaluated per dispatch, so the transport can become available later with no reconnect.\r\n */\r\n available?: (input: ITransportRouteActionParams) => boolean;\r\n /** Short label for the devtools chip (defaults to \"link\"). */\r\n label?: string;\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n}\r\n\r\n/**\r\n * A carrier-agnostic transport: it drives nice-action's secure session + action routing over any\r\n * {@link IDuplexCarrier}. The WebSocket transport is the special case that opens a `WebSocket`;\r\n * this opens whatever `openChannel` returns, so the identical secure layer works over WebRTC, Bluetooth,\r\n * or an in-memory pipe. Reported with an overridable carrier label in the devtools (defaults to \"link\").\r\n */\r\nexport class LinkTransport extends Transport<ETransportShape.duplex> {\r\n readonly type = ETransportShape.duplex;\r\n\r\n constructor(private readonly options: ILinkTransportOptions) {\r\n super();\r\n }\r\n\r\n static create(options: ILinkTransportOptions): LinkTransport {\r\n return new LinkTransport(options);\r\n }\r\n\r\n _createConnection(ctx: ITransportConnectionContext): LinkConnection {\r\n const options = this.options;\r\n\r\n return new LinkConnection(\r\n {\r\n initialize: () => ({\r\n getTransportCacheKey: options.getTransportCacheKey,\r\n isAvailable: options.available,\r\n getTransport: (input) => ({\r\n status: ETransportStatus.ready,\r\n readyData: {\r\n channel: options.openChannel(input),\r\n formatMessage: options.createFormatMessage?.() ?? options.formatMessage,\r\n updateRunConfig: options.updateRunConfig,\r\n secureChannel: options.security,\r\n },\r\n }),\r\n }),\r\n },\r\n ctx.resolvers,\r\n );\r\n }\r\n\r\n getRouteInfo(input: ITransportRouteActionParams): ITransportRouteInfo {\r\n if (this.options.getRouteInfo != null) return this.options.getRouteInfo(input);\r\n return {\r\n carrierLabel: this.options.label ?? \"link\",\r\n summary: this.options.label ?? \"link\",\r\n };\r\n }\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../Transport.types\";\r\n\r\n/**\r\n * Carrier shapes — the only transport-specific surface a new protocol must implement. The secure\r\n * session (handshake + frame crypto + codec) and the action routing on top of it are carrier-agnostic;\r\n * a carrier just moves frames. Two shapes capture every carrier:\r\n *\r\n * - {@link IDuplexCarrier} — a persistent, push-capable byte stream (WebSocket, WebRTC `RTCDataChannel`,\r\n * Bluetooth GATT, an in-memory pipe). Either side can send at any time, so it supports server→client\r\n * pushes (the return path + broadcast).\r\n * - {@link IExchangeCarrier} — a request → single-correlated-reply carrier with no unsolicited push\r\n * (HTTP, and anything request/response-shaped). The reply rides the response to its own request.\r\n *\r\n * Frames are `string` (text — handshake control messages and JSON action frames) or binary\r\n * (`Uint8Array`/`ArrayBuffer` — the optimized binary wire / encrypted frames).\r\n */\r\nexport type TFrame = string | Uint8Array | ArrayBuffer;\r\n\r\n/**\r\n * A bidirectional, push-capable byte stream. Reduces every duplex carrier to \"open, send bytes, receive\r\n * bytes, close\" — a WebSocket, a WebRTC data channel, a Bluetooth characteristic, or an in-memory pipe\r\n * all satisfy this, so the identical secure session runs over each.\r\n */\r\nexport interface IDuplexCarrier {\r\n /** Resolves once the carrier is open and ready to send; rejects if it closes/errors before opening. */\r\n readonly ready: Promise<void>;\r\n /** Whether the carrier is currently open (a synchronous guard before `send`). */\r\n isOpen(): boolean;\r\n /** Write one frame to the peer. */\r\n send(frame: TFrame): void;\r\n /**\r\n * Register the carrier's handlers. Called exactly once by the session after `ready`. `onMessage`\r\n * receives every inbound frame; `onClose` fires when the carrier goes away.\r\n */\r\n attach(handlers: {\r\n onMessage: (frame: TFrame) => void;\r\n onClose: () => void;\r\n onError?: (error: unknown) => void;\r\n }): void;\r\n /** Close the carrier deliberately (a teardown). */\r\n close(): void;\r\n /** Optional human-readable endpoint for the devtools route chip. */\r\n readonly label?: string;\r\n}\r\n\r\n/**\r\n * A request → single-correlated-reply carrier with no unsolicited push (HTTP). One `exchange` sends a\r\n * frame and resolves with exactly the one reply frame for it; the carrier itself correlates them (the\r\n * HTTP transaction), so no correlation id is needed on the wire.\r\n */\r\nexport interface IExchangeCarrier {\r\n /** Send one frame, await the single correlated reply frame. */\r\n exchange(frame: TFrame, opts?: { signal?: AbortSignal }): Promise<TFrame>;\r\n /** Optional human-readable endpoint for the devtools route chip. */\r\n readonly label?: string;\r\n}\r\n\r\nexport type TCarrier = IDuplexCarrier | IExchangeCarrier;\r\n\r\n/**\r\n * A reusable opener for a {@link IDuplexCarrier} plus the per-action metadata a duplex transport needs.\r\n * Built by the small carrier factories (`wsCarrier`, `rtcCarrier`, `inMemoryCarrier`) and handed to\r\n * {@link secureTransport} / `LinkTransport` — so adding a new carrier is \"write one of these\", nothing\r\n * else.\r\n */\r\nexport interface IDuplexCarrierSource {\r\n /** Open (or reuse) the carrier for an action. */\r\n open: (input: ITransportRouteActionParams) => IDuplexCarrier;\r\n /** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */\r\n getCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /** Devtools route info for an action routed over this carrier. */\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n /** Short carrier-kind label for the devtools chip (e.g. `\"ws\"`, `\"webrtc\"`, `\"memory\"`). */\r\n readonly carrierLabel: string;\r\n}\r\n\r\n/**\r\n * The exchange-shape counterpart to {@link IDuplexCarrierSource}: a reusable opener for an\r\n * {@link IExchangeCarrier} plus the per-action metadata an exchange transport needs. Built by\r\n * `httpCarrier` and handed to {@link secureTransport} — adding a new request/reply protocol is \"write\r\n * one of these\". The `shape` tag lets {@link secureTransport} pick the duplex vs exchange transport.\r\n */\r\nexport interface IExchangeCarrierSource {\r\n /** Discriminant so a generic factory can tell an exchange source from a duplex one. */\r\n readonly shape: \"exchange\";\r\n /** Open (or reuse) the carrier for an action. */\r\n open: (input: ITransportRouteActionParams) => IExchangeCarrier;\r\n /** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */\r\n getCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /** Devtools route info for an action routed over this carrier. */\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n /** Short carrier-kind label for the devtools chip (e.g. `\"http\"`). */\r\n readonly carrierLabel: string;\r\n}\r\n\r\n/**\r\n * Narrow a carrier source to the exchange shape via its `shape` discriminant — the one branch the\r\n * transport factories ({@link secureTransport}, {@link plainTransport}) use to pick the duplex vs\r\n * exchange transport. A duplex source carries no `shape`, so the `else` branch is the duplex one.\r\n */\r\nexport function isExchangeCarrierSource(\r\n carrier: IDuplexCarrierSource | IExchangeCarrierSource,\r\n): carrier is IExchangeCarrierSource {\r\n return \"shape\" in carrier && carrier.shape === \"exchange\";\r\n}\r\n","import {\r\n type IDuplexCarrierSource,\r\n type IExchangeCarrierSource,\r\n isExchangeCarrierSource,\r\n} from \"./Carrier/Carrier.types\";\r\nimport { ExchangeTransport } from \"./Exchange/ExchangeTransport\";\r\nimport { LinkTransport } from \"./Link/LinkTransport\";\r\nimport type { TLinkFormatMessage } from \"./Link/TransportLink.types\";\r\nimport type { ITransportRouteActionParams, TUpdateActionRunConfig } from \"./Transport.types\";\r\n\r\nexport interface IPlainTransportOptions {\r\n /**\r\n * How to reach the peer with no security layer. A duplex carrier (`wsCarrier(url)`,\r\n * `rtcCarrier(dc)`, `inMemoryCarrier().carrier`) builds a push-capable {@link LinkTransport}; an\r\n * exchange carrier (`httpCarrier(...)`) builds a request/reply {@link ExchangeTransport}.\r\n */\r\n carrier: IDuplexCarrierSource | IExchangeCarrierSource;\r\n /**\r\n * Codec for a *duplex* carrier (a duplex link frames the action wire itself). Required for duplex;\r\n * ignored for an exchange carrier, which JSON-encodes the action wire in its envelope.\r\n */\r\n formatMessage?: TLinkFormatMessage;\r\n /** Per-channel codec factory for stateful duplex codecs (e.g. the binary session). */\r\n createFormatMessage?: () => TLinkFormatMessage;\r\n /**\r\n * Optional availability gate. When it returns `false`, this transport reports as `unsupported` for that\r\n * action and the manager falls through to the next transport in preference order — without opening the\r\n * carrier or computing its cache key. Re-evaluated per dispatch, so a transport can become available\r\n * later (e.g. once a session/connection precondition holds) with no reconnect. Omit = always available.\r\n */\r\n available?: (input: ITransportRouteActionParams) => boolean;\r\n updateRunConfig?: TUpdateActionRunConfig;\r\n /** Override the devtools chip label (defaults to the carrier's `carrierLabel`). */\r\n label?: string;\r\n}\r\n\r\n/**\r\n * The plain (no-handshake, no-crypto) sibling of {@link secureTransport}: swap the carrier to change\r\n * protocol, with no security layer. Over an {@link IExchangeCarrierSource} it builds an\r\n * {@link ExchangeTransport} that POSTs the bare action wire and completes inline (HTTP is just\r\n * `carrier: httpCarrier(...)`); over an {@link IDuplexCarrierSource} it builds a push-capable\r\n * {@link LinkTransport} with the given codec. HTTP is therefore no longer a bespoke transport class —\r\n * it is \"just another carrier\", exactly like a WebSocket under {@link secureTransport}.\r\n */\r\nexport function plainTransport(\r\n options: IPlainTransportOptions & { carrier: IExchangeCarrierSource },\r\n): ExchangeTransport;\r\nexport function plainTransport(\r\n options: IPlainTransportOptions & { carrier: IDuplexCarrierSource },\r\n): LinkTransport;\r\nexport function plainTransport(\r\n options: IPlainTransportOptions,\r\n): LinkTransport | ExchangeTransport {\r\n const carrier = options.carrier;\r\n\r\n if (isExchangeCarrierSource(carrier)) {\r\n return ExchangeTransport.create({\r\n openCarrier: carrier.open,\r\n getTransportCacheKey: carrier.getCacheKey,\r\n available: options.available,\r\n getRouteInfo: carrier.getRouteInfo,\r\n label: options.label ?? carrier.carrierLabel,\r\n updateRunConfig: options.updateRunConfig,\r\n });\r\n }\r\n\r\n return LinkTransport.create({\r\n openChannel: carrier.open,\r\n formatMessage: options.formatMessage,\r\n createFormatMessage: options.createFormatMessage,\r\n getTransportCacheKey: carrier.getCacheKey,\r\n available: options.available,\r\n getRouteInfo: carrier.getRouteInfo,\r\n label: options.label ?? carrier.carrierLabel,\r\n updateRunConfig: options.updateRunConfig,\r\n });\r\n}\r\n","import { ClientCryptoKeyLink, type StorageAdapter } from \"@nice-code/util\";\r\nimport type { ActionRuntime } from \"../ActionRuntime\";\r\nimport {\r\n type IDuplexCarrierSource,\r\n type IExchangeCarrierSource,\r\n isExchangeCarrierSource,\r\n} from \"./Carrier/Carrier.types\";\r\nimport type { ISecureChannel } from \"../Channel/secureChannel\";\r\nimport type { ESecurityLevel } from \"./crypto/actionHandshake\";\r\nimport { ExchangeTransport } from \"./Exchange/ExchangeTransport\";\r\nimport { LinkTransport } from \"./Link/LinkTransport\";\r\nimport type { ITransportRouteActionParams } from \"./Transport.types\";\r\n\r\nexport interface ISecureTransportOptions {\r\n /** The shared channel identity (per-connection codec + dictionary version) — same one both ends use. */\r\n channel: ISecureChannel;\r\n /** This client's runtime — its coordinate is the authenticated identity sent in the handshake. */\r\n runtime: ActionRuntime;\r\n /** Backing store for this client's crypto identity (a stable verify key across reloads). */\r\n storageAdapter: StorageAdapter;\r\n /** The level this client requests; the peer must allow it. */\r\n securityLevel: ESecurityLevel;\r\n /**\r\n * Optional availability gate. When it returns `false`, this transport reports as `unsupported` for that\r\n * action and the manager falls through to the next transport in preference order — without opening the\r\n * carrier or computing its cache key. Re-evaluated per dispatch, so a transport can become available\r\n * later (e.g. once a session/connection precondition holds) with no reconnect. Omit = always available.\r\n */\r\n available?: (input: ITransportRouteActionParams) => boolean;\r\n /**\r\n * How to reach the peer. A duplex carrier (`wsCarrier(url)`, `rtcCarrier(dc)`,\r\n * `inMemoryCarrier().carrier`) runs the push-capable session; an exchange carrier (`httpCarrier(...)`)\r\n * runs the request/reply session over the same handshake + crypto.\r\n */\r\n carrier: IDuplexCarrierSource | IExchangeCarrierSource;\r\n}\r\n\r\n/**\r\n * The one secure-transport factory — swap the carrier to change protocol. Folds in the boilerplate (the\r\n * {@link ClientCryptoKeyLink} from `storageAdapter`, the `security` block from the runtime coordinate +\r\n * channel version) and drives it over whatever carrier you pass: a {@link IDuplexCarrierSource} builds a\r\n * push-capable {@link LinkTransport} (WS is just `carrier: wsCarrier(url)`), an\r\n * {@link IExchangeCarrierSource} builds a request/reply {@link ExchangeTransport} (HTTP, with the same\r\n * authentication/encryption). Replaces the old `createSecureWebSocketTransport` / `createSecureLinkTransport`.\r\n */\r\nexport function secureTransport(\r\n options: ISecureTransportOptions & { carrier: IDuplexCarrierSource },\r\n): LinkTransport;\r\nexport function secureTransport(\r\n options: ISecureTransportOptions & { carrier: IExchangeCarrierSource },\r\n): ExchangeTransport;\r\nexport function secureTransport(\r\n options: ISecureTransportOptions,\r\n): LinkTransport | ExchangeTransport {\r\n const link = new ClientCryptoKeyLink({ storageAdapter: options.storageAdapter });\r\n const security = {\r\n securityLevel: options.securityLevel,\r\n link,\r\n localCoordinate: options.runtime.coordinate.toJsonObject(),\r\n dictionaryVersion: options.channel.dictionaryVersion,\r\n };\r\n const carrier = options.carrier;\r\n\r\n if (isExchangeCarrierSource(carrier)) {\r\n return ExchangeTransport.create({\r\n openCarrier: carrier.open,\r\n getTransportCacheKey: carrier.getCacheKey,\r\n available: options.available,\r\n getRouteInfo: carrier.getRouteInfo,\r\n label: carrier.carrierLabel,\r\n security,\r\n });\r\n }\r\n\r\n return LinkTransport.create({\r\n openChannel: carrier.open,\r\n createFormatMessage: options.channel.createCodec,\r\n getTransportCacheKey: carrier.getCacheKey,\r\n available: options.available,\r\n getRouteInfo: carrier.getRouteInfo,\r\n label: carrier.carrierLabel,\r\n security,\r\n });\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["ENVELOPE","ENVELOPE_LENGTH","normalizeFrame"],"sources":["../src/ActionDefinition/Action/Context/ActionContext.ts","../src/ActionDefinition/Action/Core/ActionCore.ts","../src/utils/isAction_Context_JsonObject.ts","../src/utils/isAction_Core_JsonObject.ts","../src/utils/isAction_Any_JsonObject.ts","../src/utils/assertIsActionJson.ts","../src/utils/isAction_Any_Instance.ts","../src/ActionDefinition/Domain/ActionDomainBase.ts","../src/ActionRuntime/ActionRuntimeManager.ts","../src/ActionDefinition/Domain/ActionRootDomain.ts","../src/ActionDefinition/Domain/ActionDomain.ts","../src/ActionDefinition/Domain/helpers/createRootActionDomain.ts","../src/ActionRuntime/Transport/codec/actionWireCodec.ts","../src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.ts","../src/ActionRuntime/Channel/secureChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/inMemory/createInMemoryChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/inMemory/inMemoryCarrier.ts","../src/ActionRuntime/Transport/Carrier/duplex/rtc/rtcDataChannelByteChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/rtc/rtcCarrier.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/err_nice_transport_ws.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/ws_util.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/webSocketByteChannel.ts","../src/ActionRuntime/Transport/Carrier/duplex/ws/wsCarrier.ts","../src/ActionRuntime/Transport/Carrier/exchange/http/httpCarrier.ts","../src/ActionRuntime/Transport/codec/createBinaryWireAdapter.ts"],"sourcesContent":["import { RuntimeCoordinate } from \"../../../ActionRuntime/RuntimeCoordinate\";\nimport type { ActionDomain } from \"../../Domain/ActionDomain\";\nimport type {\n IActionDomain,\n TInferInputFromSchema,\n TInferOutputFromSchema,\n} from \"../../Domain/ActionDomain.types\";\nimport { ActionBase } from \"../ActionBase\";\nimport { EActionForm } from \"../ActionBase.types\";\nimport type {\n IActionContext,\n IActionContext_Data,\n IActionContext_Data_JsonObject,\n IActionContext_JsonObject,\n IActionRouteItem,\n} from \"./ActionContext.types\";\n\nexport class ActionContext<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n >\n extends ActionBase<EActionForm.context, DOM, ID>\n implements IActionContext<DOM, ID>\n{\n readonly form = EActionForm.context;\n readonly _routing: IActionRouteItem[];\n readonly timeCreated: number;\n readonly cuid: string;\n originClient: RuntimeCoordinate;\n\n constructor(\n readonly _domain: ActionDomain<DOM>,\n id: ID,\n hydrationData: IActionContext_Data,\n ) {\n super(EActionForm.context, _domain, id);\n this.timeCreated = hydrationData.timeCreated;\n this.cuid = hydrationData.cuid;\n this._routing = hydrationData.routing;\n this.originClient = hydrationData.originClient;\n }\n\n _setOriginClient(client: RuntimeCoordinate): void {\n this.originClient = client;\n }\n\n toJsonString(): string {\n return JSON.stringify(this.toJsonObject());\n }\n\n toContextDataJsonObject(): IActionContext_Data_JsonObject {\n return {\n timeCreated: this.timeCreated,\n cuid: this.cuid,\n routing: this.routing.map((item) => ({\n runtime: item.runtime.toJsonObject(),\n handler: item.handler,\n time: item.time,\n })),\n originClient: this.originClient.toJsonObject(),\n };\n }\n\n toJsonObject(): IActionContext_JsonObject<DOM, ID> {\n return {\n ...super.toJsonObject(),\n ...this.toContextDataJsonObject(),\n };\n }\n\n get routing(): IActionRouteItem[] {\n return this._routing;\n }\n\n addRouteItem(item: IActionRouteItem): void {\n this._routing.push(item);\n }\n\n deserializeInput(\n serialized: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.deserializeInput(serialized);\n }\n\n serializeInput(\n raw: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"] {\n return this.schema.serializeInput(raw);\n }\n\n validateInput(input: unknown): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.validateInput(input, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n\n validateOutput(output: unknown): TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"] {\n return this.schema.validateOutput(output, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n}\n","import { nanoid } from \"nanoid\";\nimport { RuntimeCoordinate } from \"../../../ActionRuntime/RuntimeCoordinate\";\nimport type { ActionDomain } from \"../../Domain/ActionDomain\";\nimport type {\n IActionDomain,\n TInferInputFromSchema,\n TInferOutputFromSchema,\n} from \"../../Domain/ActionDomain.types\";\nimport type { TNarrowActionType } from \"../Action.combined.types\";\nimport { ActionBase } from \"../ActionBase\";\nimport { EActionForm, type IActionBase, type IActionBase_JsonObject } from \"../ActionBase.types\";\nimport { ActionContext } from \"../Context/ActionContext\";\nimport { ActionPayload } from \"../Payload/ActionPayload\";\nimport { ActionPayload_Request } from \"../Payload/ActionPayload_Request\";\nimport type { IActionCore } from \"./ActionCore.types\";\n\nexport class ActionCore<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n >\n extends ActionBase<EActionForm.core, DOM, ID>\n implements IActionCore<DOM, ID>\n{\n readonly form = EActionForm.core;\n\n constructor(\n readonly _domain: ActionDomain<DOM>,\n id: ID,\n ) {\n super(EActionForm.core, _domain, id);\n }\n\n is<ACT extends IActionBase<any, any, any>>(\n action: ACT | unknown | null | undefined,\n ): action is TNarrowActionType<DOM, ACT, ID> {\n return (\n action instanceof ActionPayload && action.domain === this.domain && action.id === this.id\n );\n }\n\n toJsonObject(): IActionBase_JsonObject<EActionForm.core, DOM, ID> {\n return {\n id: this.id,\n form: this.form,\n domain: this.domain,\n allDomains: this.allDomains,\n };\n }\n\n request(\n ...args: [TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"]] extends [never]\n ? [input?: never]\n : [input: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"]]\n ): ActionPayload_Request<DOM, ID> {\n const input: unknown = args[0];\n const validatedInput = this.schema.validateInput(input, {\n actionId: this.id,\n domain: this.domain,\n });\n\n const context = new ActionContext(this._domain, this.id, {\n cuid: nanoid(),\n timeCreated: Date.now(),\n routing: [],\n originClient: RuntimeCoordinate.unknown,\n });\n\n return new ActionPayload_Request({ context }, validatedInput, {\n time: Date.now(),\n });\n }\n\n // async run(\n // input: TInferInputFromSchema<DOM[\"actions\"][ID]>[\"Input\"],\n // options?: IExecuteActionOptions<DOM, ID>,\n // ): Promise<RunningAction<DOM, ID>> {\n // return this.request(input).run(options);\n // }\n\n // async runToOutput(\n // input: TInferInputFromSchema<DOM[\"actions\"][ID]>[\"Input\"],\n // options?: IExecuteActionOptions<DOM, ID>,\n // ): Promise<TInferOutputFromSchema<DOM[\"actions\"][ID]>[\"Output\"]> {\n // return this.request(input).runToOutput(options);\n // }\n\n // async runToOutputSafe(\n // input: TInferInputFromSchema<DOM[\"actions\"][ID]>[\"Input\"],\n // options?: IExecuteActionOptions<DOM, ID>,\n // ): Promise<\n // TActionResult<\n // TInferOutputFromSchema<DOM[\"actions\"][ID]>[\"Output\"],\n // TInferActionError<DOM[\"actions\"][ID]>\n // >\n // > {\n // return this.request(input).runToOutputSafe(options);\n // }\n\n deserializeInput(\n serialized: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.deserializeInput(serialized);\n }\n\n serializeInput(\n raw: TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"],\n ): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"SerdeInput\"] {\n return this.schema.serializeInput(raw);\n }\n\n validateInput(input: unknown): TInferInputFromSchema<DOM[\"actionSchema\"][ID]>[\"Input\"] {\n return this.schema.validateInput(input, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n\n validateOutput(output: unknown): TInferOutputFromSchema<DOM[\"actionSchema\"][ID]>[\"Output\"] {\n return this.schema.validateOutput(output, {\n domain: this.domain,\n actionId: this.id,\n });\n }\n}\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionContext_JsonObject } from \"../ActionDefinition/Action/Context/ActionContext.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isAction_Context_JsonObject = (obj: unknown): obj is IActionContext_JsonObject => {\n return isAction_Base_JsonObject(obj) && obj.form === EActionForm.context;\n};\n","import { EActionForm } from \"../ActionDefinition/Action/ActionBase.types\";\nimport type { IActionCore_JsonObject } from \"../ActionDefinition/Action/Core/ActionCore.types\";\nimport { isAction_Base_JsonObject } from \"./isAction_Base_JsonObject\";\n\nexport const isAction_Core_JsonObject = (obj: unknown): obj is IActionCore_JsonObject => {\n return isAction_Base_JsonObject(obj) && obj.form === EActionForm.core;\n};\n","import type { TAction_Any_JsonObject } from \"../ActionDefinition/Action/Action.combined.types\";\nimport { isAction_Context_JsonObject } from \"./isAction_Context_JsonObject\";\nimport { isAction_Core_JsonObject } from \"./isAction_Core_JsonObject\";\nimport { isActionPayload_Any_JsonObject } from \"./isActionPayload_Any_JsonObject\";\n\nexport function isAction_Any_JsonObject(obj: unknown): obj is TAction_Any_JsonObject {\n return (\n isActionPayload_Any_JsonObject(obj) ||\n isAction_Context_JsonObject(obj) ||\n isAction_Core_JsonObject(obj)\n );\n}\n","import type { IActionBase_JsonObject } from \"../ActionDefinition/Action/ActionBase.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../errors/err_nice_action\";\nimport { isAction_Any_JsonObject } from \"./isAction_Any_JsonObject\";\n\nexport function assertIsActionJson(obj: unknown): asserts obj is IActionBase_JsonObject {\n if (!isAction_Any_JsonObject(obj)) {\n throw err_nice_action.fromId(EErrId_NiceAction.wire_not_action_data);\n }\n}\n","import type { TAction_Any_Instance } from \"../ActionDefinition/Action/Action.combined.types\";\nimport type { IActionBase } from \"../ActionDefinition/Action/ActionBase.types\";\nimport { ActionContext } from \"../ActionDefinition/Action/Context/ActionContext\";\nimport { ActionCore } from \"../ActionDefinition/Action/Core/ActionCore\";\nimport { ActionPayload } from \"../ActionDefinition/Action/Payload/ActionPayload\";\n\nexport function isAction_Any_Instance<ACT extends IActionBase<any, any>>(\n value: unknown | ACT,\n): value is TAction_Any_Instance<any, any> {\n return (\n value instanceof ActionCore || value instanceof ActionPayload || value instanceof ActionContext\n );\n}\n","import type {\n TDistributeRunningActionUpdateListener,\n TRunningActionUpdateListener,\n} from \"../Action/RunningAction.types\";\nimport type { IActionDomain } from \"./ActionDomain.types\";\n\nexport abstract class ActionDomainBase<ACT_DOM extends IActionDomain = IActionDomain>\n implements IActionDomain<ACT_DOM[\"allDomains\"], ACT_DOM[\"actionSchema\"]>\n{\n readonly domain: ACT_DOM[\"domain\"];\n readonly allDomains: ACT_DOM[\"allDomains\"];\n readonly actionSchema: ACT_DOM[\"actionSchema\"];\n\n protected _listeners: TRunningActionUpdateListener<any, any>[] = [];\n\n constructor(definition: ACT_DOM) {\n this.domain = definition.domain;\n this.allDomains = definition.allDomains;\n this.actionSchema = definition.actionSchema;\n }\n\n /**\n * Add an observer that is called after every action dispatched through this domain.\n * Returns an unsubscribe function — call it to remove the listener.\n */\n addActionListener(\n listener: TDistributeRunningActionUpdateListener<\n ACT_DOM,\n keyof ACT_DOM[\"actionSchema\"] & string\n >,\n ): () => void {\n this._listeners.push(listener as TRunningActionUpdateListener<any, any>);\n return () => {\n this._listeners = this._listeners.filter((l) => l !== listener);\n };\n }\n\n /**\n * @internal\n * Observers registered directly on this domain via {@link addActionListener}.\n * Used to wire observers (e.g. devtools) onto RunningActions that aren't created\n * through the local-dispatch path — notably inbound actions pushed from a backend\n * or another client over a bidirectional transport.\n */\n _getActionObservers(): TRunningActionUpdateListener<any, any>[] {\n return this._listeners;\n }\n}\n","import type { TActionPayload_Any_Instance } from \"../ActionDefinition/Action/Payload/ActionPayload.types\";\nimport { EErrId_NiceAction, err_nice_action } from \"../errors/err_nice_action\";\nimport type { ActionRuntime } from \"./ActionRuntime\";\nimport type { IActionHandlerAndRuntime, IActionRuntimeManagerContext } from \"./ActionRuntime.types\";\nimport type { IHandleActionOptions } from \"./Handler/ActionHandler.types\";\nimport {\n type IRuntimeCoordinate,\n RuntimeCoordinate,\n type TRuntimeCoordinateStringId,\n} from \"./RuntimeCoordinate\";\nimport { runtimeCoordinateToStringIds } from \"./utils/runtimeCoordinateToStringIds\";\n\nexport class ActionRuntimeManager {\n private _runtimes: Map<TRuntimeCoordinateStringId, ActionRuntime> = new Map();\n private _preferredRuntimeClientId: TRuntimeCoordinateStringId | null = null;\n private _context: IActionRuntimeManagerContext;\n\n constructor(context?: IActionRuntimeManagerContext) {\n this._context = context ?? {};\n }\n\n registerRuntime(runtime: ActionRuntime): void {\n const runtimeId = runtime.coordinate.stringId;\n if (this._runtimes.has(runtimeId)) {\n throw err_nice_action.fromId(EErrId_NiceAction.client_runtime_already_registered, {\n context: this._context,\n client: runtime.coordinate,\n });\n }\n\n for (const id of runtime.coordinate.toStringIds()) {\n if (this._runtimes.has(id)) {\n continue;\n }\n\n this._runtimes.set(id, runtime);\n }\n }\n\n getRuntimeAndHandlerForAction(\n action: TActionPayload_Any_Instance<any, any>,\n options?: IHandleActionOptions,\n throwOnIssue?: boolean,\n ): IActionHandlerAndRuntime | undefined {\n const localRuntime = options?.targetLocalRuntime;\n\n if (localRuntime != null) {\n const runtime = throwOnIssue\n ? this.getBestRuntimeOrThrow(options?.targetLocalRuntime?.coordinate)\n : this.getBestRuntime(options?.targetLocalRuntime?.coordinate);\n\n if (runtime == null) {\n return;\n }\n\n const handler = runtime._getHandlerForAction(action, options);\n\n if (handler != null) {\n return { handler, runtime };\n }\n\n if (throwOnIssue) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n specifiedClient: localRuntime.coordinate,\n });\n }\n }\n\n // If no client specified, try to find a runtime that can handle the action\n for (const runtime of this._runtimes.values()) {\n const handler = runtime._getHandlerForAction(action);\n if (handler) {\n return { handler, runtime };\n }\n }\n\n if (throwOnIssue) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_action_execution_handler, {\n domain: action.domain,\n actionId: action.id,\n specifiedClient: options?.targetLocalRuntime?.coordinate,\n });\n }\n }\n\n getRuntimeAndHandlerForActionOrThrow(\n action: TActionPayload_Any_Instance<any, any>,\n options?: IHandleActionOptions,\n ): IActionHandlerAndRuntime {\n return this.getRuntimeAndHandlerForAction(action, options, true)!;\n }\n\n setPreferredRuntime(runtime: ActionRuntime): void {\n const runtimeId = runtime.coordinate.stringId;\n this._preferredRuntimeClientId = runtimeId;\n }\n\n getPreferredRuntime(): ActionRuntime | undefined {\n if (this._preferredRuntimeClientId) {\n const runtime = this._runtimes.get(this._preferredRuntimeClientId);\n if (runtime) {\n return runtime;\n }\n }\n return this._runtimes.values().next().value;\n }\n\n getBestRuntimeForSpecifier(clientSpecifier: IRuntimeCoordinate): ActionRuntime | undefined {\n const actionClient = new RuntimeCoordinate(clientSpecifier);\n const ids = actionClient.toStringIds();\n\n for (const id of ids) {\n const runtime = this._runtimes.get(id);\n if (runtime) {\n return runtime;\n }\n }\n }\n\n getBestRuntime(clientSpecifier?: IRuntimeCoordinate): ActionRuntime | undefined {\n return clientSpecifier != null\n ? this.getBestRuntimeForSpecifier(clientSpecifier)\n : this.getPreferredRuntime();\n }\n\n hasRuntime(runtime: ActionRuntime): boolean {\n return this._runtimes.has(runtime.coordinate.stringId);\n }\n\n getBestRuntimeOrThrow(specifier?: IRuntimeCoordinate): ActionRuntime {\n const runtime = this.getBestRuntime(specifier);\n\n if (!runtime) {\n if (specifier == null) {\n throw err_nice_action.fromId(EErrId_NiceAction.no_client_runtimes_registered, {\n context: this._context,\n });\n }\n\n throw err_nice_action.fromId(EErrId_NiceAction.client_runtime_not_registered, {\n context: this._context,\n clientStringId: runtimeCoordinateToStringIds(specifier)[0],\n });\n }\n\n return runtime;\n }\n}\n","import type { ActionRuntime } from \"../../ActionRuntime/ActionRuntime\";\nimport type { IActionHandlerAndRuntime } from \"../../ActionRuntime/ActionRuntime.types\";\nimport { ActionRuntimeManager } from \"../../ActionRuntime/ActionRuntimeManager\";\nimport type { IExecuteActionOptions } from \"../../ActionRuntime/Handler/ActionHandler.types\";\nimport type { IRuntimeCoordinate } from \"../../ActionRuntime/RuntimeCoordinate\";\nimport { EErrId_NiceAction, err_nice_action } from \"../../errors/err_nice_action\";\nimport type { ActionPayload_Request } from \"../Action/Payload/ActionPayload_Request\";\nimport { RunningAction } from \"../Action/RunningAction\";\nimport { ActionDomain } from \"./ActionDomain\";\nimport type {\n IActionDomain,\n IActionDomainChildOptions,\n IActionRootDomain,\n TActionDomainChildDef,\n} from \"./ActionDomain.types\";\nimport { ActionDomainBase } from \"./ActionDomainBase\";\n\nexport class ActionRootDomain<\n ROOT_DOM extends IActionRootDomain = IActionRootDomain,\n> extends ActionDomainBase<ROOT_DOM> {\n private _actionRuntimeManager: ActionRuntimeManager;\n\n constructor(\n readonly domainDefinition: {\n domain: ROOT_DOM[\"domain\"];\n },\n ) {\n const domainId = domainDefinition.domain;\n\n super({\n domain: domainId,\n allDomains: [domainId],\n actionSchema: {},\n } as ROOT_DOM);\n\n this._actionRuntimeManager = new ActionRuntimeManager({ domain: domainId });\n }\n\n createChildDomain<SUB_DOM extends IActionDomainChildOptions>(\n subDomainDef: SUB_DOM & {\n [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never;\n },\n ): ActionDomain<TActionDomainChildDef<ROOT_DOM, SUB_DOM>> {\n if (this.allDomains.includes(subDomainDef.domain)) {\n throw err_nice_action.fromId(EErrId_NiceAction.domain_already_exists_in_hierarchy, {\n domain: subDomainDef.domain,\n allParentDomains: this.allDomains,\n parentDomain: this.domain,\n });\n }\n\n return new ActionDomain<TActionDomainChildDef<ROOT_DOM, SUB_DOM>>(\n {\n allDomains: [...this.allDomains, subDomainDef.domain],\n domain: subDomainDef.domain,\n actionSchema: subDomainDef.actions,\n },\n { rootDomain: this },\n );\n }\n\n _registerRuntime(runtime: ActionRuntime): void {\n this._actionRuntimeManager.registerRuntime(runtime);\n }\n\n _hasRuntime(runtime: ActionRuntime): boolean {\n return this._actionRuntimeManager.hasRuntime(runtime);\n }\n\n getRuntime(clientSpecifier: IRuntimeCoordinate): ActionRuntime | undefined {\n return this._actionRuntimeManager.getBestRuntimeForSpecifier(clientSpecifier);\n }\n\n async _runAction<\n DOM extends IActionDomain,\n ID extends keyof DOM[\"actionSchema\"] & string = keyof DOM[\"actionSchema\"] & string,\n ACT extends ActionPayload_Request<DOM, ID> = ActionPayload_Request<DOM, ID>,\n >(actionPayload: ACT, options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>> {\n const allListeners = [...this._listeners, ...(options?.listeners ?? [])];\n\n let handlerAndRuntime: IActionHandlerAndRuntime;\n try {\n handlerAndRuntime = this._actionRuntimeManager.getRuntimeAndHandlerForActionOrThrow(\n actionPayload,\n options,\n );\n } catch (err) {\n const runningAction = new RunningAction<DOM, ID>({\n context: actionPayload.context,\n request: actionPayload,\n callSite: actionPayload._callSite,\n });\n runningAction.addUpdateListeners(allListeners);\n runningAction._failWithError(err);\n throw err;\n }\n\n const { handler, runtime } = handlerAndRuntime;\n\n actionPayload.context._setOriginClient(runtime.coordinate);\n\n const runningAction = await handler.handleActionRequest(actionPayload, {\n targetLocalRuntime: runtime,\n });\n\n runningAction.addUpdateListeners(allListeners);\n\n return runningAction;\n }\n}\n","import type { ActionRuntime } from \"../../ActionRuntime/ActionRuntime\";\nimport type { IExecuteActionOptions } from \"../../ActionRuntime/Handler/ActionHandler.types\";\nimport { ActionLocalHandler } from \"../../ActionRuntime/Handler/Local/ActionLocalHandler\";\nimport { RuntimeCoordinate } from \"../../ActionRuntime/RuntimeCoordinate\";\nimport { EErrId_NiceAction, err_nice_action } from \"../../errors/err_nice_action\";\nimport { assertIsActionJson } from \"../../utils/assertIsActionJson\";\nimport { isAction_Any_Instance } from \"../../utils/isAction_Any_Instance\";\nimport type {\n TAction_Any_JsonObject,\n TDistributeActionPayload_Request,\n TDistributeActionPayload_Result,\n TDistributedDomainActions,\n TNarrowActionJsonTypeToActionInstanceType,\n} from \"../Action/Action.combined.types\";\nimport { EActionForm, type IActionBase } from \"../Action/ActionBase.types\";\nimport { ActionContext } from \"../Action/Context/ActionContext\";\nimport type { IActionContext_Data_JsonObject } from \"../Action/Context/ActionContext.types\";\nimport { ActionCore } from \"../Action/Core/ActionCore\";\nimport {\n EActionPayloadType,\n type IActionPayload_Request_JsonObject,\n type IActionPayload_Result_JsonObject,\n} from \"../Action/Payload/ActionPayload.types\";\nimport { ActionPayload_Request } from \"../Action/Payload/ActionPayload_Request\";\nimport { ActionPayload_Result } from \"../Action/Payload/ActionPayload_Result\";\nimport type { RunningAction } from \"../Action/RunningAction\";\nimport type { TRunningActionUpdateListener } from \"../Action/RunningAction.types\";\nimport type {\n IActionDomain,\n IActionDomainChildOptions,\n TActionDomainChildDef,\n TWrappableDomainActionHandler,\n} from \"./ActionDomain.types\";\nimport { ActionDomainBase } from \"./ActionDomainBase\";\nimport { type ActionRootDomain } from \"./ActionRootDomain\";\n\ntype TActionMap<ACT_DOM extends IActionDomain> = {\n [K in keyof ACT_DOM[\"actionSchema\"] & string]: ActionCore<ACT_DOM, K>;\n};\n\nexport class ActionDomain<\n ACT_DOM extends IActionDomain = IActionDomain,\n> extends ActionDomainBase<ACT_DOM> {\n private _rootDomain: ActionRootDomain<any>;\n private readonly _actionMap: TActionMap<ACT_DOM>;\n\n constructor(\n definition: ACT_DOM,\n {\n rootDomain,\n }: {\n rootDomain: ActionRootDomain<any>;\n },\n ) {\n super(definition);\n this._rootDomain = rootDomain;\n this._actionMap = this.createActionMap();\n }\n\n get rootDomain() {\n return this._rootDomain;\n }\n\n /**\n * @internal\n * All action observers that should see actions on this domain: the root domain's\n * observers plus this subdomain's own. Mirrors the listener set the local-dispatch\n * path assembles in `runAction`/`_runAction`, so inbound actions (pushed from a\n * backend or another client) can be wired up identically and surface in devtools.\n */\n _collectActionObservers(): TRunningActionUpdateListener<any, any>[] {\n return [...this._rootDomain._getActionObservers(), ...this._getActionObservers()];\n }\n\n _registerRuntime(runtime: ActionRuntime): void {\n this._rootDomain._registerRuntime(runtime);\n }\n\n createChildDomain<SUB_DOM extends IActionDomainChildOptions>(\n subDomainDef: SUB_DOM & {\n [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never;\n },\n ): ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>> {\n if (this.allDomains.includes(subDomainDef.domain)) {\n throw err_nice_action.fromId(EErrId_NiceAction.domain_already_exists_in_hierarchy, {\n domain: subDomainDef.domain,\n allParentDomains: this.allDomains,\n parentDomain: this.domain,\n });\n }\n\n return new ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>>(\n {\n allDomains: [...this.allDomains, subDomainDef.domain],\n domain: subDomainDef.domain,\n actionSchema: subDomainDef.actions,\n },\n { rootDomain: this._rootDomain },\n );\n }\n\n get action(): TActionMap<ACT_DOM> {\n return this._actionMap;\n }\n\n actionsMap(): TActionMap<ACT_DOM> {\n return this._actionMap;\n }\n\n actionForId<ID extends keyof ACT_DOM[\"actionSchema\"] & string>(id: ID): ActionCore<ACT_DOM, ID> {\n const actionSchema = this.actionSchema[id];\n if (!actionSchema) {\n throw err_nice_action.fromId(EErrId_NiceAction.action_id_not_in_domain, {\n domain: this.domain,\n actionId: id as string,\n });\n }\n\n return new ActionCore<ACT_DOM, ID>(this, id);\n }\n\n wrapAsPartialLocalHandler(\n wrappedActionExecutor: Partial<TWrappableDomainActionHandler<ACT_DOM>>,\n ): ActionLocalHandler {\n const _handler = new ActionLocalHandler();\n const executor = wrappedActionExecutor as unknown as Record<string, (input: any) => any>;\n\n for (const actionKey in wrappedActionExecutor) {\n if (!this.actionSchema[actionKey]) {\n continue;\n }\n\n _handler.forAction(this.actionForId(actionKey), (request) =>\n executor[request.id](request.input),\n );\n }\n\n return _handler;\n }\n\n wrapAsLocalHandler(\n wrappedActionExecutor: TWrappableDomainActionHandler<ACT_DOM>,\n ): ActionLocalHandler {\n const _handler = new ActionLocalHandler();\n const executor = wrappedActionExecutor as unknown as Record<string, (input: any) => any>;\n return _handler.forDomain(this, (request) => executor[request.id](request.input));\n }\n\n hydrateContext<ID extends keyof ACT_DOM[\"actionSchema\"] & string>(\n id: ID,\n contextData: IActionContext_Data_JsonObject,\n ): ActionContext<ACT_DOM, ID> {\n return new ActionContext(this, id, {\n timeCreated: contextData.timeCreated,\n cuid: contextData.cuid,\n routing: contextData.routing.map((item) => {\n return {\n runtime: new RuntimeCoordinate(item.runtime),\n handler: item.handler,\n time: item.time,\n };\n }),\n originClient: contextData.originClient\n ? new RuntimeCoordinate(contextData.originClient)\n : RuntimeCoordinate.unknown,\n });\n }\n\n isDomainAction<ACT extends IActionBase<any, ACT_DOM, any>>(\n action: ACT | unknown | null | undefined,\n ): action is TDistributedDomainActions<ACT_DOM, ACT> {\n return isAction_Any_Instance(action) && action.domain === this.domain;\n }\n\n hydrateRequestPayload<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n P extends IActionPayload_Request_JsonObject<ACT_DOM, ID>,\n >(serialized: P): TDistributeActionPayload_Request<ACT_DOM, ID> {\n if (serialized.type !== EActionPayloadType.request) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_state_mismatch, {\n expected: EActionPayloadType.request,\n received: serialized.type,\n });\n }\n\n if (serialized.domain !== this.domain) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_domain_mismatch, {\n expected: this.domain,\n received: serialized.domain,\n });\n }\n\n const id = serialized.id;\n if (!this.actionSchema[id]) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_id_not_found, {\n domain: this.domain,\n actionId: serialized.id,\n });\n }\n\n const contextAction = this.hydrateContext(id, serialized.context);\n\n return new ActionPayload_Request(\n { context: contextAction },\n contextAction.deserializeInput(serialized.input),\n {\n time: serialized.time,\n },\n ) as TDistributeActionPayload_Request<ACT_DOM, ID>;\n }\n\n hydrateResultPayload<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n R extends IActionPayload_Result_JsonObject<ACT_DOM, ID>,\n >(serialized: R): TDistributeActionPayload_Result<ACT_DOM, ID> {\n if (serialized.type !== EActionPayloadType.result) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_state_mismatch, {\n expected: EActionPayloadType.result,\n received: serialized.type,\n });\n }\n\n if (serialized.domain !== this.domain) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_domain_mismatch, {\n expected: this.domain,\n received: serialized.domain,\n });\n }\n\n const id = serialized.id;\n\n if (!this.actionSchema[id]) {\n throw err_nice_action.fromId(EErrId_NiceAction.hydration_action_id_not_found, {\n domain: this.domain,\n actionId: serialized.id,\n });\n }\n\n const contextAction = this.hydrateContext(id, serialized.context);\n\n const result = serialized.result.ok\n ? {\n ok: true as const,\n output: contextAction.schema.deserializeOutput(serialized.result.output),\n }\n : serialized.result;\n\n return new ActionPayload_Result({ context: contextAction }, result, {\n time: serialized.time,\n }) as TDistributeActionPayload_Result<ACT_DOM, ID>;\n }\n\n hydrateAnyAction<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n AJ extends TAction_Any_JsonObject<ACT_DOM, ID>,\n >(actionJson: AJ): TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID> {\n assertIsActionJson(actionJson);\n\n if (actionJson.form === EActionForm.data) {\n if (actionJson.type === EActionPayloadType.request) {\n return this.hydrateRequestPayload(\n actionJson,\n ) as unknown as TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;\n }\n\n if (actionJson.type === EActionPayloadType.result) {\n return this.hydrateResultPayload(\n actionJson,\n ) as unknown as TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;\n }\n }\n\n return this.actionForId(actionJson.id) as TNarrowActionJsonTypeToActionInstanceType<\n ACT_DOM,\n AJ,\n ID\n >;\n }\n\n async runAction<\n ID extends keyof ACT_DOM[\"actionSchema\"] & string,\n ACT extends ActionPayload_Request<ACT_DOM, ID>,\n >(\n request: ACT,\n options?: IExecuteActionOptions<ACT_DOM, ID>,\n ): Promise<RunningAction<ACT_DOM, ID>> {\n const allListeners: TRunningActionUpdateListener<any, any>[] = [\n ...(options?.listeners ?? []),\n ...this._listeners,\n ];\n\n return this._rootDomain._runAction(request, {\n ...options,\n listeners: allListeners,\n });\n }\n\n private createActionMap(): {\n [K in keyof ACT_DOM[\"actionSchema\"] & string]: ActionCore<ACT_DOM, K>;\n } {\n const map = {} as {\n [K in keyof ACT_DOM[\"actionSchema\"] & string]: ActionCore<ACT_DOM, K>;\n };\n\n for (const id in this.actionSchema) {\n map[id] = new ActionCore(this, id);\n }\n\n return map;\n }\n}\n","import type { IActionRootDomain } from \"../ActionDomain.types\";\nimport { ActionRootDomain } from \"../ActionRootDomain\";\n\nexport const createActionRootDomain = <ID extends string>(definition: {\n domain: ID;\n}): ActionRootDomain<IActionRootDomain<ID>> => {\n return new ActionRootDomain<IActionRootDomain<ID>>(definition);\n};\n","import { EActionForm } from \"../../../ActionDefinition/Action/ActionBase.types\";\r\nimport type { IActionContext_Data_JsonObject } from \"../../../ActionDefinition/Action/Context/ActionContext.types\";\r\nimport {\r\n EActionPayloadType,\r\n type IActionPayload_Base_JsonObject,\r\n type TActionPayload_Any_JsonObject,\r\n} from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { TPossibleDomainIdList } from \"../../../ActionDefinition/Domain/ActionDomain.types\";\r\nimport type { ITransportRouteActionParams } from \"../Transport.types\";\r\n\r\n/**\r\n * Shared building blocks for the binary action codecs (the stateless {@link createBinaryWireAdapter} and\r\n * the per-connection `createBinaryWireSessionFactory`). Both map a `domain:id` route to a tiny integer\r\n * and reduce the verbose JSON wire to a positional tuple — they only differ in how much context they\r\n * carry per frame, so the dictionary + payload (de)assembly live here.\r\n */\r\n\r\n/**\r\n * The carrier-neutral codec a Link connection uses to (de)serialize action payloads on the wire — the\r\n * same shape every duplex carrier (WS/WebRTC/in-memory) shares.\r\n */\r\nexport interface IActionWireFormat {\r\n /**\r\n * Pack an outgoing action payload. Return a `string` for text frames (JSON) or a binary\r\n * `Uint8Array`/`ArrayBuffer` for optimized binary frames (e.g. msgpackr).\r\n */\r\n outgoing: (input: ITransportRouteActionParams) => string | Uint8Array | ArrayBuffer;\r\n /**\r\n * Unpack an incoming frame back into the wire JSON object the runtime hydrates + validates. Return\r\n * `undefined` to defer to the connection's built-in JSON parser — this is how binary adapters stay\r\n * backward compatible with plain-JSON clients on the same socket.\r\n */\r\n incoming?: (\r\n input: string | ArrayBuffer | Uint8Array | Blob,\r\n ) => TActionPayload_Any_JsonObject<any, any> | undefined;\r\n}\r\n\r\n/**\r\n * Tiny integer codes for the payload type, so the verbose `\"request\"`/`\"result\"`/`\"progress\"`\r\n * strings never hit the wire. The index in {@link ReversePayloadType} must line up with the value.\r\n */\r\nexport const PayloadTypeToInt: Record<\r\n EActionPayloadType.request | EActionPayloadType.result | EActionPayloadType.progress,\r\n number\r\n> = {\r\n [EActionPayloadType.request]: 0,\r\n [EActionPayloadType.result]: 1,\r\n [EActionPayloadType.progress]: 2,\r\n};\r\nexport const ReversePayloadType = [\r\n EActionPayloadType.request,\r\n EActionPayloadType.result,\r\n EActionPayloadType.progress,\r\n] as const;\r\n\r\nexport interface IActionRouteMeta {\r\n domain: string;\r\n id: string;\r\n allDomains: TPossibleDomainIdList;\r\n}\r\n\r\nexport interface IActionRouteDictionary {\r\n /** `domain:id` → wire integer. */\r\n routeToInt: Map<string, number>;\r\n /** wire integer → route metadata for reconstruction. */\r\n intToRoute: IActionRouteMeta[];\r\n}\r\n\r\n/**\r\n * Build the positional `domain:id` ↔ integer dictionary. Both ends of a channel MUST build it from\r\n * the same domains in the same order — the mapping is positional, so a mismatch routes to the wrong\r\n * action. Add new transported domains to the end of the list.\r\n */\r\nexport function buildActionRouteDictionary(domains: ActionDomain<any>[]): IActionRouteDictionary {\r\n const routeToInt = new Map<string, number>();\r\n const intToRoute: IActionRouteMeta[] = [];\r\n\r\n for (const dom of domains) {\r\n for (const actionId of Object.keys(dom.actionSchema)) {\r\n const routeKey = `${dom.domain}:${actionId}`;\r\n if (routeToInt.has(routeKey)) continue;\r\n routeToInt.set(routeKey, intToRoute.length);\r\n intToRoute.push({ domain: dom.domain, id: actionId, allDomains: dom.allDomains });\r\n }\r\n }\r\n\r\n return { routeToInt, intToRoute };\r\n}\r\n\r\n/** Pull the type-specific payload (`input` / `result` / `progress`) out of a wire JSON object. */\r\nexport function extractWirePayload(json: TActionPayload_Any_JsonObject<any, any>): unknown {\r\n if (json.type === EActionPayloadType.request) return json.input;\r\n if (json.type === EActionPayloadType.result) return json.result;\r\n if (json.type === EActionPayloadType.progress) return json.progress;\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Reassemble a full wire JSON object from its decoded parts. `inputHash`/`outputHash` are emitted\r\n * empty — the hydration constructors recompute them — and the result still satisfies\r\n * `isActionPayload_Any_JsonObject` so it flows through validation like a JSON frame.\r\n */\r\nexport function assembleWireJson(\r\n routeMeta: IActionRouteMeta,\r\n payloadType: (typeof ReversePayloadType)[number],\r\n time: number,\r\n context: IActionContext_Data_JsonObject,\r\n // Runtime-dynamic payload straight off the wire (msgpack/JSON) — Valibot validates it on hydrate.\r\n payloadData: any,\r\n): TActionPayload_Any_JsonObject<any, any> {\r\n const base: Omit<IActionPayload_Base_JsonObject<EActionPayloadType>, \"type\"> = {\r\n form: EActionForm.data,\r\n domain: routeMeta.domain,\r\n id: routeMeta.id,\r\n allDomains: routeMeta.allDomains,\r\n time,\r\n context,\r\n };\r\n\r\n if (payloadType === EActionPayloadType.request) {\r\n return { ...base, type: EActionPayloadType.request, input: payloadData, inputHash: \"\" };\r\n }\r\n if (payloadType === EActionPayloadType.result) {\r\n return { ...base, type: EActionPayloadType.result, result: payloadData, outputHash: \"\" };\r\n }\r\n return { ...base, type: EActionPayloadType.progress, progress: payloadData };\r\n}\r\n","import { pack, unpack } from \"msgpackr\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { EActionPayloadType } from \"../../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport { UNSET_RUNTIME_ENV_ID } from \"../../../nice_action.static\";\r\nimport { type IRuntimeCoordinate, RuntimeCoordinate } from \"../../RuntimeCoordinate\";\r\nimport type { ITransportRouteActionParams } from \"../Transport.types\";\r\nimport {\r\n assembleWireJson,\r\n buildActionRouteDictionary,\r\n extractWirePayload,\r\n type IActionWireFormat,\r\n PayloadTypeToInt,\r\n ReversePayloadType,\r\n} from \"./actionWireCodec\";\r\n\r\n/**\r\n * Positional layout of the *session* binary envelope — the leanest frame. Compared to the stateless\r\n * adapter it replaces the 21-char `cuid` with a small per-connection integer and only carries\r\n * `originClient` on the very first request of each direction (the peer remembers it afterwards).\r\n *\r\n * [ routeInt, typeInt, corrId, time, originClient?, payloadData ]\r\n */\r\nconst ENVELOPE = {\r\n route: 0,\r\n type: 1,\r\n corr: 2,\r\n time: 3,\r\n originClient: 4,\r\n payload: 5,\r\n} as const;\r\nconst ENVELOPE_LENGTH = 6;\r\n\r\n/**\r\n * How long a pending correlation entry is kept before it's swept. A correlation only matters until its\r\n * action resolves or times out, so anything older than the longest realistic action timeout can be\r\n * dropped — this bounds memory when requests time out or a connection dies mid-flight (their replies\r\n * would never arrive, leaving the entry orphaned). Generous default so live correlations are never\r\n * pruned (the default transport timeout is 10s).\r\n */\r\nconst DEFAULT_CORRELATION_TTL_MS = 5 * 60_000;\r\n\r\ntype TFormatMessage = IActionWireFormat;\r\n\r\ninterface IPendingCorrelation<V> {\r\n value: V;\r\n /** Insertion time (ms), used to expire orphaned entries. */\r\n time: number;\r\n}\r\n\r\nexport interface IBinaryWireSessionOptions {\r\n /** Override how long an unresolved correlation is retained before being swept (ms). */\r\n correlationTtlMs?: number;\r\n}\r\n\r\nfunction isKnownIdentity(\r\n coordinate: IRuntimeCoordinate | null | undefined,\r\n): coordinate is IRuntimeCoordinate {\r\n return coordinate != null && coordinate.envId !== UNSET_RUNTIME_ENV_ID;\r\n}\r\n\r\n/**\r\n * Drop entries older than `ttlMs`. Maps keep insertion order and entries are inserted in time order,\r\n * so the oldest are first — stop sweeping at the first live entry.\r\n */\r\nfunction pruneExpired<K, V>(map: Map<K, IPendingCorrelation<V>>, now: number, ttlMs: number): void {\r\n for (const [key, entry] of map) {\r\n if (now - entry.time <= ttlMs) break;\r\n map.delete(key);\r\n }\r\n}\r\n\r\n/**\r\n * Builds a factory of *stateful, per-connection* codecs for {@link LinkTransport} /\r\n * `AcceptorHandler` — the maximally compact binary wire. Call the returned factory once per live\r\n * connection (each socket on the client, each accepted connection on the server) so every channel\r\n * gets its own correlation + identity state.\r\n *\r\n * On top of everything {@link createBinaryWireAdapter} drops, a session also drops:\r\n * - **`cuid`** — replaced by a per-connection integer correlation id. The initiator maps it to its\r\n * real cuid; the responder echoes it; each side reconstructs the cuid from its own map. Correlation\r\n * only needs to be unique per socket, so a counter suffices.\r\n * - **`originClient` after the first request** — the first request each side sends carries its\r\n * identity; the peer remembers it and injects it into later frames. Replies omit it entirely (a\r\n * reply carries the initiator's own origin, which the initiator already knows).\r\n *\r\n * Both ends MUST build the factory from the same domains in the same order (positional dictionary).\r\n * Text frames still return `undefined` from `incoming`, so JSON clients remain interoperable.\r\n *\r\n * Hibernation note: after a server connection is evicted its session resets, so a still-connected\r\n * client (whose session persists) will keep omitting `originClient`. The server must therefore restore\r\n * the connection→client binding from its own store (see `AcceptorHandler.rehydrateConnection`) and\r\n * inject `originClient` from there — the session alone can't recover it.\r\n */\r\nexport function createBinaryWireSessionFactory(\r\n domains: ActionDomain<any>[],\r\n options?: IBinaryWireSessionOptions,\r\n): () => TFormatMessage {\r\n const { routeToInt, intToRoute } = buildActionRouteDictionary(domains);\r\n const unknownIdentity = RuntimeCoordinate.unknown.toJsonObject();\r\n const ttlMs = options?.correlationTtlMs ?? DEFAULT_CORRELATION_TTL_MS;\r\n\r\n return (): TFormatMessage => {\r\n let outCounter = 0;\r\n // Requests this side initiated: correlation id → our cuid (to resolve the eventual reply).\r\n const corrToCuid = new Map<number, IPendingCorrelation<string>>();\r\n // Requests this side is responding to: our (synthesized) cuid → the correlation id to echo back.\r\n const cuidToCorr = new Map<string, IPendingCorrelation<number>>();\r\n let selfIdentity: IRuntimeCoordinate | undefined;\r\n let peerIdentity: IRuntimeCoordinate | undefined;\r\n\r\n return {\r\n outgoing: (input: ITransportRouteActionParams): Uint8Array => {\r\n const json = input.action.toJsonObject();\r\n const routeKey = `${json.domain}:${json.id}`;\r\n const routeInt = routeToInt.get(routeKey);\r\n if (routeInt == null) {\r\n throw new Error(`[binary-wire] Cannot pack unregistered action route: ${routeKey}`);\r\n }\r\n\r\n const now = Date.now();\r\n pruneExpired(corrToCuid, now, ttlMs);\r\n pruneExpired(cuidToCorr, now, ttlMs);\r\n\r\n let corr: number;\r\n let wireIdentity: IRuntimeCoordinate | undefined;\r\n\r\n if (json.type === EActionPayloadType.request) {\r\n // Initiator: assign a fresh per-connection correlation id, remember our cuid for the reply.\r\n corr = outCounter++;\r\n corrToCuid.set(corr, { value: json.context.cuid, time: now });\r\n\r\n // Send our identity only on the first request — the peer remembers it from then on.\r\n if (selfIdentity == null && isKnownIdentity(json.context.originClient)) {\r\n selfIdentity = json.context.originClient;\r\n wireIdentity = json.context.originClient;\r\n }\r\n } else {\r\n // Responder: echo the correlation id the request arrived with.\r\n corr = cuidToCorr.get(json.context.cuid)?.value ?? -1;\r\n if (json.type === EActionPayloadType.result) cuidToCorr.delete(json.context.cuid);\r\n }\r\n\r\n const envelope = new Array(ENVELOPE_LENGTH);\r\n envelope[ENVELOPE.route] = routeInt;\r\n envelope[ENVELOPE.type] = PayloadTypeToInt[json.type];\r\n envelope[ENVELOPE.corr] = corr;\r\n envelope[ENVELOPE.time] = json.time;\r\n envelope[ENVELOPE.originClient] = wireIdentity; // undefined except the first request\r\n envelope[ENVELOPE.payload] = extractWirePayload(json);\r\n\r\n return pack(envelope);\r\n },\r\n\r\n incoming: (frame: string | ArrayBuffer | Uint8Array | Blob) => {\r\n let buffer: Uint8Array;\r\n if (frame instanceof ArrayBuffer) {\r\n buffer = new Uint8Array(frame);\r\n } else if (frame instanceof Uint8Array) {\r\n buffer = frame;\r\n } else {\r\n return undefined;\r\n }\r\n\r\n try {\r\n const envelope = unpack(buffer);\r\n if (!Array.isArray(envelope) || envelope.length !== ENVELOPE_LENGTH) return undefined;\r\n\r\n const routeMeta = intToRoute[envelope[ENVELOPE.route]];\r\n const payloadType = ReversePayloadType[envelope[ENVELOPE.type]];\r\n if (routeMeta == null || payloadType == null) return undefined;\r\n\r\n const now = Date.now();\r\n pruneExpired(corrToCuid, now, ttlMs);\r\n pruneExpired(cuidToCorr, now, ttlMs);\r\n\r\n const corr: number = envelope[ENVELOPE.corr];\r\n const time: number = envelope[ENVELOPE.time];\r\n const wireIdentity: IRuntimeCoordinate | undefined = envelope[ENVELOPE.originClient];\r\n\r\n let cuid: string;\r\n let originClient: IRuntimeCoordinate;\r\n\r\n if (payloadType === EActionPayloadType.request) {\r\n // Incoming request: synthesize a local cuid, remember the correlation for our reply.\r\n cuid = nanoid();\r\n cuidToCorr.set(cuid, { value: corr, time: now });\r\n\r\n if (isKnownIdentity(wireIdentity)) peerIdentity = wireIdentity;\r\n originClient = peerIdentity ?? unknownIdentity;\r\n } else {\r\n // Incoming reply: map the correlation id back to the cuid of the request we initiated.\r\n cuid = corrToCuid.get(corr)?.value ?? nanoid();\r\n if (payloadType === EActionPayloadType.result) corrToCuid.delete(corr);\r\n // A reply carries our own origin (the request originated on this side).\r\n originClient = selfIdentity ?? unknownIdentity;\r\n }\r\n\r\n const context = { cuid, timeCreated: time, routing: [], originClient };\r\n return assembleWireJson(\r\n routeMeta,\r\n payloadType,\r\n time,\r\n context,\r\n envelope[ENVELOPE.payload],\r\n );\r\n } catch (e) {\r\n console.error(\"[binary-wire] Failed to unpack binary action session frame\", e);\r\n return undefined;\r\n }\r\n },\r\n };\r\n };\r\n}\r\n","import type { ActionDomain } from \"../../ActionDefinition/Domain/ActionDomain\";\r\nimport {\r\n buildActionRouteDictionary,\r\n type IActionWireFormat,\r\n} from \"../Transport/codec/actionWireCodec\";\r\nimport {\r\n createBinaryWireSessionFactory,\r\n type IBinaryWireSessionOptions,\r\n} from \"../Transport/codec/createBinaryWireSessionFactory\";\r\nimport { defineChannel, type IActionChannel } from \"./ActionChannel\";\r\n\r\n/** The per-connection binary session codec — built once per socket from the channel's domains. */\r\ntype TChannelCodec = IActionWireFormat;\r\n\r\n/**\r\n * The shared identity of a secure channel (carrier-agnostic — WS, WebRTC, HTTP, …): the wire\r\n * dictionary version both ends check during the handshake, plus the per-connection codec factory both\r\n * ends build from the *same* domain list. Define it once (typically in code shared by both peers) and\r\n * hand it to `secureTransport` on the connector and `serveChannel` (or the lower-level `acceptChannel` /\r\n * `createSecureAcceptorHandler`) on the acceptor, so the codec and version can never drift apart.\r\n */\r\nexport interface ISecureChannel<\r\n TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\r\n> extends IActionChannel<TO_ACCEPTOR, TO_CONNECTOR> {\r\n /** Wire dictionary version — derived from the domains by default; the handshake rejects a mismatch. */\r\n dictionaryVersion: string;\r\n /** Per-connection session codec factory (call once per live connection). */\r\n createCodec: () => TChannelCodec;\r\n}\r\n\r\n/**\r\n * Derive a stable wire-dictionary version from the ordered route list (FNV-1a over `domain:id,…`), so\r\n * the version moves automatically whenever the transported domains change — a stale peer is then\r\n * rejected by the handshake instead of silently misrouting a positionally-packed frame.\r\n */\r\nfunction deriveDictionaryVersion(domains: ActionDomain<any>[]): string {\r\n const { intToRoute } = buildActionRouteDictionary(domains);\r\n const signature = intToRoute.map((route) => `${route.domain}:${route.id}`).join(\",\");\r\n\r\n let hash = 0x811c9dc5;\r\n for (let i = 0; i < signature.length; i++) {\r\n hash ^= signature.charCodeAt(i);\r\n hash = Math.imul(hash, 0x01000193);\r\n }\r\n return `auto:${(hash >>> 0).toString(16).padStart(8, \"0\")}`;\r\n}\r\n\r\n/**\r\n * Bundle a secure channel's shared identity from its transported domains. Both ends MUST call this\r\n * with the same domains in the same order (the binary wire dictionary is positional). The\r\n * `dictionaryVersion` is derived from those domains unless you pin an explicit one.\r\n *\r\n * Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`\r\n * (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see\r\n * {@link connectChannel} and `acceptChannelConnections`) instead of being restated at each end. The\r\n * wire dictionary spans `[...toAcceptor, ...toConnector]` in that order; add new domains to the end of\r\n * their list to keep older peers compatible. (`domains` is still accepted as a legacy alias for\r\n * `toAcceptor`.)\r\n */\r\nexport function defineSecureChannel<\r\n const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [],\r\n const TO_CONNECTOR extends readonly ActionDomain<any>[] = [],\r\n>(options: {\r\n /** Domains the connector sends to the acceptor (connector→acceptor requests), in a stable order. */\r\n toAcceptor: TO_ACCEPTOR;\r\n /** Domains the acceptor pushes to the connector (acceptor→connector), in a stable order. */\r\n toConnector: TO_CONNECTOR;\r\n /** Pin a human-readable version instead of the derived hash (must match on both ends). */\r\n dictionaryVersion?: string;\r\n /** Tuning for the per-connection binary session (e.g. correlation TTL). */\r\n sessionOptions?: IBinaryWireSessionOptions;\r\n}): ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR> {\r\n // The routing half (role) is just a plain channel; this adds the WS binary wire identity on top.\r\n const base = defineChannel<TO_ACCEPTOR, TO_CONNECTOR>({\r\n toAcceptor: options.toAcceptor,\r\n toConnector: options.toConnector,\r\n });\r\n // Dictionary order is positional and must match on both ends: connector→acceptor routes first, then\r\n // acceptor→connector pushes. (`domains` already covers the legacy single-list case via toAcceptorDomains.)\r\n const allDomains: ActionDomain<any>[] = [...base.toAcceptorDomains, ...base.toConnectorDomains];\r\n\r\n return {\r\n ...base,\r\n dictionaryVersion: options.dictionaryVersion ?? deriveDictionaryVersion(allDomains),\r\n createCodec: createBinaryWireSessionFactory(allDomains, options.sessionOptions),\r\n };\r\n}\r\n\r\n// The secure WS transport is now built via `secureTransport({ carrier: wsCarrier(url) })` — this file\r\n// only defines the carrier-neutral channel identity (`defineSecureChannel` / `ISecureChannel`).\r\n","import type { IDuplexCarrier } from \"../../Carrier.types\";\r\n\r\ntype TFrame = string | ArrayBuffer | Uint8Array;\r\n\r\n/** The peer (server) end of an in-memory pair — what you feed into an `AcceptorHandler`. */\r\nexport interface IInMemoryServerEndpoint {\r\n /** Write a frame back to the client end. */\r\n send(frame: TFrame): void;\r\n /** Register the inbound handler (frames the client sent). */\r\n onMessage(handler: (frame: TFrame) => void): void;\r\n /** Close the pair from this end. */\r\n close(): void;\r\n /** Notified when the pair closes (from either end). */\r\n onClose(handler: () => void): void;\r\n}\r\n\r\nexport interface IInMemoryChannelPair {\r\n /** The client end — pass as a {@link IDuplexCarrier} to a `LinkTransport`. */\r\n clientChannel: IDuplexCarrier;\r\n /** The server end — wire into an `AcceptorHandler` (`send` + `receive`). */\r\n serverEndpoint: IInMemoryServerEndpoint;\r\n}\r\n\r\n/**\r\n * Two cross-wired in-process byte channels — a loopback carrier with no socket. The client end is a\r\n * {@link IDuplexCarrier} you hand to a {@link LinkTransport}; the server end plugs into an\r\n * `AcceptorHandler` (`send: (_, f) => serverEndpoint.send(f)`, and `serverEndpoint.onMessage(f =>\r\n * handler.receive(conn, f))`). Frames are delivered on a microtask, so each side observes the other\r\n * asynchronously — exactly like a real transport — which makes this ideal for tests and for running\r\n * two runtimes in one process (or proving a non-WS carrier end to end).\r\n */\r\nexport function createInMemoryChannelPair(): IInMemoryChannelPair {\r\n let clientMessage: ((frame: TFrame) => void) | undefined;\r\n let clientClose: (() => void) | undefined;\r\n let serverMessage: ((frame: TFrame) => void) | undefined;\r\n let serverClose: (() => void) | undefined;\r\n let open = true;\r\n\r\n const closeBoth = (): void => {\r\n if (!open) return;\r\n open = false;\r\n queueMicrotask(() => {\r\n clientClose?.();\r\n serverClose?.();\r\n });\r\n };\r\n\r\n const clientChannel: IDuplexCarrier = {\r\n ready: Promise.resolve(),\r\n isOpen: () => open,\r\n send: (frame) => {\r\n if (!open) return;\r\n queueMicrotask(() => serverMessage?.(frame));\r\n },\r\n attach: ({ onMessage, onClose }) => {\r\n clientMessage = onMessage;\r\n clientClose = onClose;\r\n },\r\n close: closeBoth,\r\n label: \"in-memory\",\r\n };\r\n\r\n const serverEndpoint: IInMemoryServerEndpoint = {\r\n send: (frame) => {\r\n if (!open) return;\r\n queueMicrotask(() => clientMessage?.(frame));\r\n },\r\n onMessage: (handler) => {\r\n serverMessage = handler;\r\n },\r\n onClose: (handler) => {\r\n serverClose = handler;\r\n },\r\n close: closeBoth,\r\n };\r\n\r\n return { clientChannel, serverEndpoint };\r\n}\r\n","import {\r\n createInMemoryChannelPair,\r\n type IInMemoryServerEndpoint,\r\n} from \"./createInMemoryChannel\";\r\nimport type { IDuplexCarrierSource } from \"../../Carrier.types\";\r\n\r\nexport interface IInMemoryCarrier {\r\n /** The connector end — pass as the `carrier` to {@link secureTransport} / `LinkTransport`. */\r\n carrier: IDuplexCarrierSource;\r\n /** The acceptor end — wire into an `AcceptorHandler` (`send` + `receive`). */\r\n serverEndpoint: IInMemoryServerEndpoint;\r\n}\r\n\r\n/**\r\n * A loopback duplex carrier with no socket — two cross-wired in-process ends. The connector end is an\r\n * {@link IDuplexCarrierSource} for {@link secureTransport}; the acceptor end plugs into an\r\n * `AcceptorHandler`. Ideal for tests and for running two runtimes in one process, or proving a\r\n * non-WS carrier end to end.\r\n */\r\nexport function inMemoryCarrier(): IInMemoryCarrier {\r\n const { clientChannel, serverEndpoint } = createInMemoryChannelPair();\r\n return {\r\n carrier: {\r\n carrierLabel: \"memory\",\r\n open: () => clientChannel,\r\n getCacheKey: () => [\"memory\"],\r\n },\r\n serverEndpoint,\r\n };\r\n}\r\n","import type { IDuplexCarrier } from \"../../Carrier.types\";\r\n\r\n/**\r\n * The slice of the `RTCDataChannel` surface this adapter uses — declared structurally so it accepts the\r\n * browser `RTCDataChannel`, React-Native (`react-native-webrtc`), or any node-webrtc shim without a hard\r\n * dependency on a specific DOM/RN type. A real `RTCDataChannel` satisfies it as-is.\r\n */\r\nexport interface IRtcDataChannelLike {\r\n readyState: string; // \"connecting\" | \"open\" | \"closing\" | \"closed\"\r\n binaryType: string;\r\n label?: string;\r\n send(data: string | ArrayBuffer | ArrayBufferView): void;\r\n close(): void;\r\n addEventListener(type: string, listener: (event: any) => void, options?: unknown): void;\r\n}\r\n\r\n/**\r\n * Adapt a WebRTC `RTCDataChannel` to the carrier-agnostic {@link IDuplexCarrier}, so two browsers\r\n * (or two mobile apps) linked peer-to-peer — no server in the middle — run the *same* secure session as\r\n * a WebSocket. Hand it to `createSecureLinkTransport({ openChannel: () => rtcDataChannelByteChannel(dc) })`.\r\n *\r\n * The data channel must already be created (its negotiation/signaling is the app's concern); this only\r\n * drives bytes over it. Binary frames are requested as `ArrayBuffer` so the binary session codec unpacks\r\n * them synchronously; a `Blob` (if the channel hands one back) is normalized to a buffer.\r\n */\r\nexport function rtcDataChannelByteChannel(dc: IRtcDataChannelLike): IDuplexCarrier {\r\n dc.binaryType = \"arraybuffer\";\r\n\r\n let intentional = false;\r\n let onMessage: ((frame: string | ArrayBuffer | Uint8Array) => void) | undefined;\r\n let onClose: (() => void) | undefined;\r\n const preAttach: (string | ArrayBuffer | Uint8Array)[] = [];\r\n\r\n const deliver = (frame: string | ArrayBuffer | Uint8Array): void => {\r\n if (onMessage != null) onMessage(frame);\r\n else preAttach.push(frame);\r\n };\r\n\r\n dc.addEventListener(\"message\", async (event: { data: unknown }) => {\r\n const frame = await normalizeFrame(event.data);\r\n if (frame !== undefined) deliver(frame);\r\n });\r\n dc.addEventListener(\"close\", () => {\r\n if (!intentional) console.error(\"RTCDataChannel closed\");\r\n onClose?.();\r\n });\r\n dc.addEventListener(\"error\", (event: unknown) => {\r\n console.error(\"RTCDataChannel error:\", event);\r\n onClose?.();\r\n });\r\n\r\n const ready = new Promise<void>((resolve, reject) => {\r\n if (dc.readyState === \"open\") {\r\n resolve();\r\n return;\r\n }\r\n dc.addEventListener(\"open\", () => resolve(), { once: true });\r\n dc.addEventListener(\"error\", (event: unknown) => reject(event), { once: true });\r\n dc.addEventListener(\"close\", () => reject(new Error(\"RTCDataChannel closed before open\")), {\r\n once: true,\r\n });\r\n });\r\n\r\n return {\r\n ready,\r\n isOpen: () => dc.readyState === \"open\",\r\n send: (frame) => {\r\n // A pooled `Uint8Array` may be backed by a `SharedArrayBuffer` that `send` rejects — copy into a\r\n // fresh view (mirrors the WebSocket `sendFrame` guard).\r\n if (typeof frame === \"string\" || frame instanceof ArrayBuffer) dc.send(frame);\r\n else dc.send(new Uint8Array(frame));\r\n },\r\n attach: (handlers) => {\r\n onMessage = handlers.onMessage;\r\n onClose = handlers.onClose;\r\n for (const frame of preAttach) handlers.onMessage(frame);\r\n preAttach.length = 0;\r\n },\r\n close: () => {\r\n intentional = true;\r\n try {\r\n dc.close();\r\n } catch {\r\n // already closing/closed — the close listener still runs cleanup\r\n }\r\n },\r\n get label() {\r\n return dc.label != null && dc.label !== \"\" ? dc.label : undefined;\r\n },\r\n };\r\n}\r\n\r\nasync function normalizeFrame(\r\n data: unknown,\r\n): Promise<string | ArrayBuffer | Uint8Array | undefined> {\r\n if (typeof data === \"string\" || data instanceof ArrayBuffer || data instanceof Uint8Array) {\r\n return data;\r\n }\r\n if (typeof Blob !== \"undefined\" && data instanceof Blob) {\r\n return await data.arrayBuffer();\r\n }\r\n return undefined;\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../../../Transport.types\";\r\nimport {\r\n type IRtcDataChannelLike,\r\n rtcDataChannelByteChannel,\r\n} from \"./rtcDataChannelByteChannel\";\r\nimport type { IDuplexCarrierSource } from \"../../Carrier.types\";\r\n\r\nexport interface IRtcCarrierOptions {\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n}\r\n\r\n/**\r\n * A WebRTC {@link IDuplexCarrierSource} over an already-negotiated `RTCDataChannel` (signaling is the\r\n * app's concern). Hand it to {@link secureTransport} so two browsers/apps linked peer-to-peer run the\r\n * identical secure session as a WebSocket.\r\n */\r\nexport function rtcCarrier(\r\n dataChannel: IRtcDataChannelLike,\r\n options: IRtcCarrierOptions = {},\r\n): IDuplexCarrierSource {\r\n return {\r\n carrierLabel: \"webrtc\",\r\n open: () => rtcDataChannelByteChannel(dataChannel),\r\n getCacheKey: options.getTransportCacheKey ?? (() => [\"webrtc\"]),\r\n getRouteInfo: options.getRouteInfo,\r\n };\r\n}\r\n","import { err } from \"@nice-code/error\";\r\nimport { err_nice_transport } from \"../../../err_nice_transport\";\r\n\r\nexport enum EErrId_NiceTransport_WebSocket {\r\n ws_disconnected = \"ws_disconnected\",\r\n ws_create_failed = \"ws_create_failed\",\r\n ws_error = \"ws_error\",\r\n}\r\n\r\nexport const err_nice_transport_ws = err_nice_transport.createChildDomain({\r\n domain: \"ws_transport\",\r\n schema: {\r\n [EErrId_NiceTransport_WebSocket.ws_disconnected]: err<Record<string, never>>({\r\n message: () => `WebSocket transport disconnected.`,\r\n }),\r\n [EErrId_NiceTransport_WebSocket.ws_create_failed]: err<{\r\n originalError?: Error;\r\n }>({\r\n message: ({ originalError }) =>\r\n `Failed to create WebSocket transport.${originalError ? ` Original error: ${originalError.message}` : \"\"}`,\r\n }),\r\n [EErrId_NiceTransport_WebSocket.ws_error]: err<{\r\n originalError?: Error;\r\n }>({\r\n message: ({ originalError }) =>\r\n `WebSocket transport error.${originalError ? ` Original error: ${originalError.message}` : \"\"}`,\r\n }),\r\n },\r\n});\r\n","/**\r\n * Send a text or binary frame over a socket. A binary formatter may hand back a `Uint8Array` whose\r\n * backing buffer is typed as `ArrayBufferLike` (msgpackr pools buffers / may be `SharedArrayBuffer`),\r\n * which `WebSocket.send`'s `BufferSource` parameter rejects — copy it into a fresh `ArrayBuffer`-backed\r\n * view so the type (and the bytes) are safe to send.\r\n */\r\nexport function sendFrame(ws: WebSocket, data: string | Uint8Array | ArrayBuffer): void {\r\n if (typeof data === \"string\" || data instanceof ArrayBuffer) {\r\n ws.send(data);\r\n return;\r\n }\r\n ws.send(new Uint8Array(data));\r\n}\r\n\r\n/** Compact a WebSocket URL to `host/pathname` for devtools display, falling back to the raw url. */\r\nexport function shortWs(url: string): string {\r\n try {\r\n const u = new URL(url);\r\n return `${u.host}${u.pathname}`;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n","import type { IDuplexCarrier } from \"../../Carrier.types\";\r\nimport { sendFrame } from \"./ws_util\";\r\n\r\n/**\r\n * Adapt a `WebSocket` to the carrier-agnostic {@link IDuplexCarrier}, so the WebSocket becomes\r\n * \"just another carrier\" under the shared secure session. It owns every WebSocket-specific concern —\r\n * awaiting `open`, normalizing `Blob` frames to bytes, suppressing the log on a deliberate `close`, and\r\n * buffering any frame that arrives before the session attaches its handler — leaving the session itself\r\n * carrier-neutral.\r\n */\r\nexport function webSocketByteChannel(ws: WebSocket): IDuplexCarrier {\r\n let intentional = false;\r\n let onMessage: ((frame: string | ArrayBuffer | Uint8Array) => void) | undefined;\r\n let onClose: (() => void) | undefined;\r\n // Frames that land before the session calls `attach` (none expected in practice, but never lose one).\r\n const preAttach: (string | ArrayBuffer | Uint8Array)[] = [];\r\n\r\n const deliver = (frame: string | ArrayBuffer | Uint8Array): void => {\r\n if (onMessage != null) onMessage(frame);\r\n else preAttach.push(frame);\r\n };\r\n\r\n ws.addEventListener(\"message\", async (event) => {\r\n const frame = await normalizeFrame((event as MessageEvent).data);\r\n if (frame !== undefined) deliver(frame);\r\n });\r\n ws.addEventListener(\"close\", (event) => {\r\n if (!intentional) console.error(\"WebSocket closed:\", event);\r\n onClose?.();\r\n });\r\n ws.addEventListener(\"error\", (event) => {\r\n console.error(\"WebSocket error:\", event);\r\n onClose?.();\r\n });\r\n\r\n const ready = new Promise<void>((resolve, reject) => {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n resolve();\r\n return;\r\n }\r\n ws.addEventListener(\"open\", () => resolve(), { once: true });\r\n ws.addEventListener(\"error\", (event) => reject(event), { once: true });\r\n ws.addEventListener(\r\n \"close\",\r\n (event) =>\r\n reject(new Error(`WebSocket closed before open: code=${(event as CloseEvent).code}`)),\r\n { once: true },\r\n );\r\n });\r\n\r\n return {\r\n ready,\r\n isOpen: () => ws.readyState === WebSocket.OPEN,\r\n send: (frame) => sendFrame(ws, frame),\r\n attach: (handlers) => {\r\n onMessage = handlers.onMessage;\r\n onClose = handlers.onClose;\r\n for (const frame of preAttach) handlers.onMessage(frame);\r\n preAttach.length = 0;\r\n },\r\n close: () => {\r\n intentional = true;\r\n try {\r\n ws.close();\r\n } catch {\r\n // already closing/closed — the close listener still runs cleanup\r\n }\r\n },\r\n get label() {\r\n return ws.url != null && ws.url !== \"\" ? ws.url : undefined;\r\n },\r\n };\r\n}\r\n\r\n/** Accept text + binary frames (ArrayBuffer / Uint8Array / Blob); Blobs are converted to a buffer. */\r\nasync function normalizeFrame(\r\n data: unknown,\r\n): Promise<string | ArrayBuffer | Uint8Array | undefined> {\r\n if (typeof data === \"string\" || data instanceof ArrayBuffer || data instanceof Uint8Array) {\r\n return data;\r\n }\r\n if (typeof Blob !== \"undefined\" && data instanceof Blob) {\r\n return await data.arrayBuffer();\r\n }\r\n return undefined;\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../../../Transport.types\";\r\nimport { webSocketByteChannel } from \"./webSocketByteChannel\";\r\nimport { shortWs } from \"./ws_util\";\r\nimport type { IDuplexCarrierSource } from \"../../Carrier.types\";\r\n\r\nexport interface IWsCarrierOptions {\r\n /** Override socket creation (defaults to a `new WebSocket(url)` with `binaryType = \"arraybuffer\"`). */\r\n createWebSocket?: (input: ITransportRouteActionParams) => WebSocket;\r\n /** Override the reuse key (defaults to `[url]`, so one socket is shared per endpoint). */\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /** Override the devtools route info for a specific action. */\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n}\r\n\r\n/**\r\n * A WebSocket {@link IDuplexCarrierSource}: opens an `arraybuffer` socket to `url` (cached per endpoint)\r\n * and adapts it to a carrier. Hand it to {@link secureTransport} (or `LinkTransport`) — the WebSocket is\r\n * now \"just another carrier\" under the shared secure session, with no WS-specific transport class.\r\n */\r\nexport function wsCarrier(url: string, options: IWsCarrierOptions = {}): IDuplexCarrierSource {\r\n return {\r\n carrierLabel: \"ws\",\r\n open: (input) =>\r\n webSocketByteChannel(options.createWebSocket?.(input) ?? defaultWebSocket(url)),\r\n getCacheKey: options.getTransportCacheKey ?? (() => [url]),\r\n getRouteInfo:\r\n options.getRouteInfo ?? (() => ({ carrierLabel: \"ws\", url, summary: `ws ${shortWs(url)}` })),\r\n };\r\n}\r\n\r\nfunction defaultWebSocket(url: string): WebSocket {\r\n const ws = new WebSocket(url);\r\n // Binary responses as ArrayBuffer (not Blob) so the session unpacks them synchronously.\r\n ws.binaryType = \"arraybuffer\";\r\n return ws;\r\n}\r\n","import type { ITransportRouteActionParams, ITransportRouteInfo } from \"../../../Transport.types\";\r\nimport type { IExchangeCarrier, IExchangeCarrierSource, TFrame } from \"../../Carrier.types\";\r\n\r\n/** The HTTP request an action is sent over (the body is supplied by the secure exchange session). */\r\nexport interface IHttpCarrierRequest {\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/** The slice of `fetch` the carrier uses — a structural type so callers (and tests) needn't match the\r\n * full platform `fetch` (Bun's adds `preconnect`, etc.). The global `fetch` satisfies it. */\r\nexport type TCarrierFetch = (input: string, init?: RequestInit) => Promise<Response>;\r\n\r\nexport interface IHttpCarrierOptions {\r\n /** Override the reuse key (defaults to `[url]`, so one session is shared per endpoint). */\r\n getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];\r\n /** Override the devtools route info for a specific action. */\r\n getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;\r\n /** Override `fetch` (e.g. to route to an in-memory handler in tests). Defaults to global `fetch`. */\r\n fetch?: TCarrierFetch;\r\n}\r\n\r\nfunction shortPath(url: string): string {\r\n try {\r\n return new URL(url).pathname || url;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * An HTTP {@link IExchangeCarrierSource}: each `exchange` POSTs one frame body to the action endpoint and\r\n * resolves with the response body as the single correlated reply. Hand it to {@link secureTransport} —\r\n * HTTP then runs the *same* secure session as a duplex carrier (handshake → token → encrypted frames),\r\n * the request/reply correlation provided for free by the HTTP transaction.\r\n *\r\n * `createRequest` derives the URL/headers per action (keep it simple with `() => ({ url })`). The body is\r\n * the session's responsibility, so it is never built here.\r\n */\r\nexport function httpCarrier(\r\n createRequest: (input: ITransportRouteActionParams) => IHttpCarrierRequest,\r\n options: IHttpCarrierOptions = {},\r\n): IExchangeCarrierSource {\r\n const doFetch = options.fetch ?? fetch;\r\n\r\n return {\r\n shape: \"exchange\",\r\n carrierLabel: \"http\",\r\n open: (input): IExchangeCarrier => {\r\n const request = createRequest(input);\r\n return {\r\n label: request.url,\r\n exchange: async (frame: TFrame, opts): Promise<TFrame> => {\r\n const res = await doFetch(request.url, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\", ...request.headers },\r\n body: typeof frame === \"string\" ? frame : new Uint8Array(frame),\r\n signal: opts?.signal,\r\n });\r\n return await res.text();\r\n },\r\n };\r\n },\r\n getCacheKey: options.getTransportCacheKey ?? ((input) => [createRequest(input).url]),\r\n getRouteInfo:\r\n options.getRouteInfo ??\r\n ((input) => {\r\n const { url } = createRequest(input);\r\n return { carrierLabel: \"http\", method: \"POST\", url, summary: `POST ${shortPath(url)}` };\r\n }),\r\n };\r\n}\r\n","import { pack, unpack } from \"msgpackr\";\r\nimport type { ActionDomain } from \"../../../ActionDefinition/Domain/ActionDomain\";\r\nimport type { ITransportRouteActionParams } from \"../Transport.types\";\r\nimport {\r\n assembleWireJson,\r\n buildActionRouteDictionary,\r\n extractWirePayload,\r\n type IActionWireFormat,\r\n PayloadTypeToInt,\r\n ReversePayloadType,\r\n} from \"./actionWireCodec\";\r\n\r\n/**\r\n * Positional layout of the stateless binary envelope. A flat tuple (rather than an object) strips the\r\n * repeated `domain`/`id`/`form`/`type` and context key names from every frame, and we carry only the\r\n * context fields the receiver can't recompute: `cuid` (correlation) and `originClient` (return\r\n * routing).\r\n *\r\n * [ routeInt, typeInt, time, cuid, originClient, payloadData ]\r\n *\r\n * Dropped vs the JSON wire: `form`/`type` strings, `inputHash`/`outputHash` (recomputed on hydrate),\r\n * `context.timeCreated` (reconstructed from `time`) and `context.routing` (rebuilt empty — the\r\n * receiver re-stamps its own route items as it handles the action). For the leanest possible frames\r\n * (integer correlation, identity dropped after a handshake), use `createBinaryWireSessionFactory`.\r\n */\r\nconst ENVELOPE = {\r\n route: 0,\r\n type: 1,\r\n time: 2,\r\n cuid: 3,\r\n originClient: 4,\r\n payload: 5,\r\n} as const;\r\nconst ENVELOPE_LENGTH = 6;\r\n\r\n/**\r\n * Builds a *stateless* `formatMessage` pipeline for {@link LinkTransport}, packing action\r\n * payloads into a compact msgpackr binary frame instead of JSON. The `domain`/`id` route collapses to\r\n * a single integer drawn from a shared dictionary; `form`/`type`, the recomputable\r\n * `inputHash`/`outputHash`, and the per-frame `context.routing`/`context.timeCreated` are all dropped\r\n * (see {@link ENVELOPE}).\r\n *\r\n * No validation runs here: `incoming` blindly reconstructs the wire JSON shape and hands it back to\r\n * the connection, which flows into `ActionRuntime` → `domain.hydrateAnyAction()` where the Valibot\r\n * schemas validate it exactly as they would for a JSON frame.\r\n *\r\n * Both ends of the socket MUST construct the adapter with the same domains in the same order — the\r\n * integer dictionary is positional. Mismatched dictionaries will route to the wrong action.\r\n *\r\n * Because `incoming` returns `undefined` for text frames, a binary server can still serve plain-JSON\r\n * clients on the same runtime (the connection falls back to its built-in JSON parser).\r\n */\r\nexport function createBinaryWireAdapter(domains: ActionDomain<any>[]): IActionWireFormat {\r\n const { routeToInt, intToRoute } = buildActionRouteDictionary(domains);\r\n\r\n return {\r\n outgoing: (input: ITransportRouteActionParams): Uint8Array => {\r\n const json = input.action.toJsonObject();\r\n const routeKey = `${json.domain}:${json.id}`;\r\n const routeInt = routeToInt.get(routeKey);\r\n\r\n if (routeInt == null) {\r\n throw new Error(`[binary-wire] Cannot pack unregistered action route: ${routeKey}`);\r\n }\r\n\r\n const envelope = new Array(ENVELOPE_LENGTH);\r\n envelope[ENVELOPE.route] = routeInt;\r\n envelope[ENVELOPE.type] = PayloadTypeToInt[json.type];\r\n envelope[ENVELOPE.time] = json.time;\r\n envelope[ENVELOPE.cuid] = json.context.cuid;\r\n envelope[ENVELOPE.originClient] = json.context.originClient;\r\n envelope[ENVELOPE.payload] = extractWirePayload(json);\r\n\r\n return pack(envelope);\r\n },\r\n\r\n incoming: (frame: string | ArrayBuffer | Uint8Array | Blob) => {\r\n // Only binary frames are ours. Text frames fall through to the JSON parser; Blobs should have\r\n // been converted to a buffer by the connection before reaching us — if not, we can't unpack\r\n // them synchronously, so defer.\r\n let buffer: Uint8Array;\r\n if (frame instanceof ArrayBuffer) {\r\n buffer = new Uint8Array(frame);\r\n } else if (frame instanceof Uint8Array) {\r\n buffer = frame;\r\n } else {\r\n return undefined;\r\n }\r\n\r\n try {\r\n const envelope = unpack(buffer);\r\n\r\n if (!Array.isArray(envelope) || envelope.length !== ENVELOPE_LENGTH) return undefined;\r\n\r\n const routeMeta = intToRoute[envelope[ENVELOPE.route]];\r\n const payloadType = ReversePayloadType[envelope[ENVELOPE.type]];\r\n if (routeMeta == null || payloadType == null) return undefined;\r\n\r\n const time = envelope[ENVELOPE.time];\r\n // Rebuild the context: `routing` starts empty (the receiver re-stamps its own hops) and\r\n // `timeCreated` is approximated by the payload `time` — neither affects hydration/validation.\r\n const context = {\r\n cuid: envelope[ENVELOPE.cuid],\r\n timeCreated: time,\r\n routing: [],\r\n originClient: envelope[ENVELOPE.originClient],\r\n };\r\n\r\n return assembleWireJson(routeMeta, payloadType, time, context, envelope[ENVELOPE.payload]);\r\n } catch (e) {\r\n console.error(\"[binary-wire] Failed to unpack binary action frame\", e);\r\n return undefined;\r\n }\r\n },\r\n };\r\n}\r\n"],"mappings":"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"}
|