@nice-code/action 0.24.0 → 0.25.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.
Files changed (36) hide show
  1. package/README.md +54 -6
  2. package/build/{AcceptorHandler-11-QMdx2.d.mts → AcceptorHandler-BizUtq4u.d.mts} +118 -15
  3. package/build/{AcceptorHandler-CxD0c1BE.d.cts → AcceptorHandler-CxPfZtIl.d.cts} +118 -15
  4. package/build/{ActionDevtoolsCore-37JP4bOG.d.cts → ActionDevtoolsCore-D9KBBI2V.d.cts} +2 -2
  5. package/build/{ActionDevtoolsCore-Cgq-go1R.d.mts → ActionDevtoolsCore-xZjAtB4H.d.mts} +2 -2
  6. package/build/advanced/index.cjs +1 -1
  7. package/build/advanced/index.d.cts +1 -96
  8. package/build/advanced/index.d.mts +1 -96
  9. package/build/advanced/index.mjs +1 -1
  10. package/build/{createHibernatableWsServerAdapter-C07RfUTH.mjs → createHibernatableWsServerAdapter-BkjESd01.mjs} +11 -9
  11. package/build/createHibernatableWsServerAdapter-BkjESd01.mjs.map +1 -0
  12. package/build/{createHibernatableWsServerAdapter-BNi4k9j3.cjs → createHibernatableWsServerAdapter-FSDWrxoF.cjs} +11 -9
  13. package/build/createHibernatableWsServerAdapter-FSDWrxoF.cjs.map +1 -0
  14. package/build/devtools/browser/index.d.cts +1 -1
  15. package/build/devtools/browser/index.d.mts +1 -1
  16. package/build/devtools/server/index.d.cts +1 -1
  17. package/build/devtools/server/index.d.mts +1 -1
  18. package/build/{httpAcceptorCarrier-C3S_bDkL.cjs → httpAcceptorCarrier-BQYaXI9j.cjs} +2 -2
  19. package/build/{httpAcceptorCarrier-C3S_bDkL.cjs.map → httpAcceptorCarrier-BQYaXI9j.cjs.map} +1 -1
  20. package/build/{httpAcceptorCarrier-DPBEuewS.mjs → httpAcceptorCarrier-DWqsCz3h.mjs} +2 -2
  21. package/build/{httpAcceptorCarrier-DPBEuewS.mjs.map → httpAcceptorCarrier-DWqsCz3h.mjs.map} +1 -1
  22. package/build/index.cjs +6 -2
  23. package/build/index.d.cts +2 -2
  24. package/build/index.d.mts +2 -2
  25. package/build/index.mjs +3 -3
  26. package/build/platform/cloudflare/index.cjs +45 -1
  27. package/build/platform/cloudflare/index.cjs.map +1 -1
  28. package/build/platform/cloudflare/index.d.cts +40 -2
  29. package/build/platform/cloudflare/index.d.mts +40 -2
  30. package/build/platform/cloudflare/index.mjs +45 -2
  31. package/build/platform/cloudflare/index.mjs.map +1 -1
  32. package/build/react-query/index.d.cts +1 -1
  33. package/build/react-query/index.d.mts +1 -1
  34. package/package.json +4 -4
  35. package/build/createHibernatableWsServerAdapter-BNi4k9j3.cjs.map +0 -1
  36. package/build/createHibernatableWsServerAdapter-C07RfUTH.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createHibernatableWsServerAdapter-FSDWrxoF.cjs","names":["err_nice","runtime","NiceError","v","ClientCryptoKeyLink","textEncoder","textDecoder"],"sources":["../src/nice_action.static.ts","../src/ActionRuntime/utils/runtimeCoordinateToStringIds.ts","../src/ActionRuntime/RuntimeCoordinate.ts","../src/ActionDefinition/Action/ActionBase.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/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/Transport.types.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/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/Transport/codec/actionWireCodec.ts","../src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.ts","../src/ActionRuntime/Transport/Transport.ts","../src/ActionRuntime/Transport/SecureSession/exchangeProtocol.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/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"],"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 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 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 type { NiceError } from \"@nice-code/error\";\r\nimport type { ClientCryptoKeyLink } from \"@nice-code/util\";\r\nimport type {\r\n IActionPayload_Request_JsonObject,\r\n IActionPayload_Result_JsonObject,\r\n TActionPayload_Any_Instance,\r\n TActionPayload_Any_JsonObject,\r\n} from \"../../ActionDefinition/Action/Payload/ActionPayload.types\";\r\nimport type { ActionPayload_Request } from \"../../ActionDefinition/Action/Payload/ActionPayload_Request\";\r\nimport type { ActionPayload_Result } from \"../../ActionDefinition/Action/Payload/ActionPayload_Result\";\r\nimport type { RunningAction } from \"../../ActionDefinition/Action/RunningAction\";\r\nimport type { IRuntimeCoordinate, RuntimeCoordinate } from \"../RuntimeCoordinate\";\r\n// Carrier-neutral handshake (the file keeps its WS-era name until Phase 3 renames it to crypto/actionHandshake).\r\nimport type { ESecurityLevel } from \"./crypto/actionHandshake\";\r\nimport type { TransportConnection } from \"./TransportConnection\";\r\n\r\n/**\r\n * Carrier-shape class identity: the one carrier-invariant trait the selection layer reasons about —\r\n * whether a carrier can push unsolicited frames (`duplex`: WS/WebRTC/BLE/in-memory) or only answers a\r\n * request with a single correlated reply (`exchange`: HTTP). The concrete carrier kind (\"ws\", \"webrtc\",\r\n * \"http\", …) is a free-form {@link ITransportRouteInfo.carrierLabel} for display, not a class tag.\r\n */\r\nexport enum ETransportShape {\r\n duplex = \"duplex\",\r\n exchange = \"exchange\",\r\n}\r\n\r\n/**\r\n * Serializable, display-only description of how an action was routed through a transport. Stored on\r\n * the action's route items and shown in the devtools external-handler chips. Keep this free of\r\n * sensitive data (e.g. auth headers) — route items travel over the wire.\r\n */\r\nexport interface ITransportRouteInfo {\r\n /** Free-form carrier kind for the devtools chip — e.g. \"ws\", \"webrtc\", \"http\". */\r\n carrierLabel: string;\r\n /** Short label for chips, e.g. \"POST /resolve_action\" or \"ws host/resolve_action/ws\". */\r\n summary?: string;\r\n url?: string;\r\n method?: string;\r\n detail?: Record<string, string | number | boolean>;\r\n}\r\n\r\nexport interface IUpdateActionRunConfig_Output {\r\n timeout?: number;\r\n}\r\n\r\nexport type TUpdateActionRunConfig = (\r\n input: ITransportRouteActionParams & { timeout: number },\r\n) => IUpdateActionRunConfig_Output;\r\n\r\nexport interface IActionTransportReadyData_Base {\r\n updateRunConfig?: TUpdateActionRunConfig;\r\n}\r\n\r\n/**\r\n * Client-side secure-channel config for a connector link — carrier-neutral (the secure session never\r\n * cared about the carrier). When present (and `securityLevel !== none`), the connection runs the\r\n * handshake during initialization and, at the `encrypted` level, encrypts every frame. The acceptor\r\n * side adds a negotiable level set + verify-key resolver on top of this (see Phase 3's `ISecureConfig`).\r\n */\r\nexport interface ISecureClientConfig {\r\n /** The level this client requests; the peer must allow it. */\r\n securityLevel: ESecurityLevel;\r\n /** This client's crypto identity (verify + exchange key pairs, optionally persisted). */\r\n link: ClientCryptoKeyLink;\r\n /** This client's runtime coordinate — its authenticated identity to the peer. */\r\n localCoordinate: IRuntimeCoordinate;\r\n /** Wire dictionary version; the peer rejects the handshake on a mismatch. */\r\n dictionaryVersion: string;\r\n}\r\n\r\n/**\r\n *\r\n * TRANSPORT READINESS RESPONSE\r\n *\r\n */\r\nexport enum ETransportStatus {\r\n uninitialized = \"uninitialized\",\r\n unsupported = \"unsupported\",\r\n initializing = \"initializing\",\r\n ready = \"ready\",\r\n failed = \"failed\",\r\n}\r\n\r\nexport interface ITransportStatusInfo_Base<S extends ETransportStatus> {\r\n status: S;\r\n}\r\n\r\nexport interface ITransportStatusInfo_Failed\r\n extends ITransportStatusInfo_Base<ETransportStatus.failed> {\r\n error: NiceError;\r\n timeFailed: number;\r\n}\r\n\r\nexport interface ITransportStatusInfo_Unsupported\r\n extends ITransportStatusInfo_Base<ETransportStatus.unsupported> {}\r\n\r\nexport interface ITransportStatusInfo_Ready<READY extends IActionTransportReadyData_Base>\r\n extends ITransportStatusInfo_Base<ETransportStatus.ready> {\r\n readyData: READY;\r\n}\r\n\r\nexport type TTransportInitializationFinishedInfo<READY extends IActionTransportReadyData_Base> =\r\n | ITransportStatusInfo_Ready<READY>\r\n | ITransportStatusInfo_Failed\r\n | ITransportStatusInfo_Unsupported;\r\n\r\nexport interface ITransportStatusInfo_Initializing<READY extends IActionTransportReadyData_Base>\r\n extends ITransportStatusInfo_Base<ETransportStatus.initializing> {\r\n timeStarted: number;\r\n initializationPromise: Promise<TTransportInitializationFinishedInfo<READY>>;\r\n}\r\n\r\nexport type TTransportStatusInfo<READY extends IActionTransportReadyData_Base> =\r\n | ITransportStatusInfo_Base<ETransportStatus.uninitialized>\r\n | ITransportStatusInfo_Unsupported\r\n | ITransportStatusInfo_Initializing<READY>\r\n | ITransportStatusInfo_Ready<READY>\r\n | ITransportStatusInfo_Failed;\r\n\r\nexport type TTransportStatusInfo_GetTransport_Output<READY extends IActionTransportReadyData_Base> =\r\n | ITransportStatusInfo_Base<ETransportStatus.uninitialized>\r\n | ITransportStatusInfo_Unsupported\r\n | Omit<ITransportStatusInfo_Initializing<READY>, \"timeStarted\">\r\n | ITransportStatusInfo_Ready<READY>\r\n | Omit<ITransportStatusInfo_Failed, \"timeFailed\">;\r\n\r\n/**\r\n *\r\n * TRANSPORT ROUTING\r\n *\r\n */\r\n\r\nexport interface ITransportRouteClientParams {\r\n localClient: RuntimeCoordinate;\r\n externalClient: RuntimeCoordinate;\r\n}\r\n\r\nexport interface ITransportRouteActionParams extends ITransportRouteClientParams {\r\n action: TActionPayload_Any_Instance<any, any>;\r\n}\r\n\r\nexport interface ITransportMethod_SendActionData_Input extends ITransportRouteActionParams {\r\n runningAction: RunningAction<any, any>;\r\n timeout: number;\r\n}\r\n\r\nexport interface ITransportDispatchAction<P> extends ITransportMethod_SendActionData_Input {\r\n params: P;\r\n}\r\n\r\nexport type TSendActionDataMethod = (input: ITransportMethod_SendActionData_Input) => void;\r\n\r\nexport type TSendReturnDataMethod = (\r\n payload: TActionPayload_Any_Instance<any, any>,\r\n /**\r\n * The local/external client pair this payload is being returned over. Bidirectional transports use\r\n * it to build the full route params their outgoing formatter expects (e.g. binary packing). Optional\r\n * so existing return-data implementations keep type-checking.\r\n */\r\n clients?: ITransportRouteClientParams,\r\n) => void;\r\n\r\nexport interface IActionTransportReadyData_Methods extends IActionTransportReadyData_Base {\r\n sendActionData: TSendActionDataMethod;\r\n /**\r\n * Optional — implement on bidirectional transports (WebSocket, Custom) to enable return-path\r\n * routing. When present, the runtime uses this to dispatch results and progress payloads directly\r\n * back to `originClient` without going through the original request transport.\r\n */\r\n sendReturnData?: TSendReturnDataMethod;\r\n addOnDisconnectListener?: (callback: () => void) => void;\r\n /**\r\n * Optional — implement on transports holding a long-lived connection (WebSocket, Custom) to close it\r\n * deliberately. Called by `ConnectorHandler.clearTransportCache()` so a teardown actually\r\n * releases the underlying socket instead of leaving it open until GC.\r\n */\r\n disconnect?: () => void;\r\n}\r\n\r\nexport interface IActionTransportReady {\r\n methods: IActionTransportReadyData_Methods;\r\n transport: TransportConnection;\r\n}\r\n\r\nexport type TTransportCache = Map<string, IActionTransportReady | Promise<IActionTransportReady>>;\r\n\r\nexport type TOnResolveIncomingRequest = (request: ActionPayload_Request<any>) => void;\r\nexport type TOnResolveIncomingRequestJson = (\r\n request: IActionPayload_Request_JsonObject<any>,\r\n) => void;\r\n\r\nexport type TOnResolveIncomingResponse = (response: ActionPayload_Result<any>) => void;\r\nexport type TOnResolveIncomingResponseJson = (\r\n response: IActionPayload_Result_JsonObject<any>,\r\n) => void;\r\n\r\nexport type TOnResolveAnyIncomingActionData = (\r\n actionData: ActionPayload_Request<any> | ActionPayload_Result<any>,\r\n) => void;\r\n\r\nexport type TOnResolveAnyIncomingActionData_Json = (\r\n actionData: TActionPayload_Any_JsonObject<any>,\r\n) => void;\r\n\r\nexport interface IActionTransportResolvers {\r\n onIncomingActionDataJson: TOnResolveAnyIncomingActionData_Json;\r\n}\r\n\r\nexport type TGetTransportFn<\r\n IN extends ITransportRouteActionParams,\r\n READY extends IActionTransportReadyData_Base,\r\n> = (input: IN) => TTransportStatusInfo_GetTransport_Output<READY>;\r\n\r\nexport interface IActionTransportInitialized<\r\n IN extends ITransportRouteActionParams,\r\n READY extends IActionTransportReadyData_Base,\r\n> {\r\n getTransportCacheKey?: (input: IN) => string[];\r\n /**\r\n * Optional availability gate, consulted by {@link ConnectionTransportManager} *before* cache-key\r\n * resolution and `getTransport`. When it returns `false`, this transport is treated as `unsupported`\r\n * for that action and the manager falls through to the next transport in preference order — without\r\n * opening the carrier or computing its cache key. Re-evaluated per action dispatch, so a transport can\r\n * become available later (e.g. once a session/connection precondition is met) with no reconnect. Omit =\r\n * always available.\r\n */\r\n isAvailable?: (input: IN) => boolean;\r\n getTransport: TGetTransportFn<IN, READY>;\r\n}\r\n\r\nexport interface IActionTransportDef<\r\n TYPE extends ETransportShape,\r\n INIT extends IActionTransportInitialized<any, any>,\r\n> {\r\n type: TYPE;\r\n initialize: () => INIT;\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 * @internal Low-level primitive — the public way to open a connection is `connectChannel`, which\r\n * derives routing from a channel and binds the crypto identity for you. This stays as the raw building\r\n * block it sits on (it restates domain lists by hand) and is not part of the supported surface.\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 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, regardless of its\r\n * coordinate score — owning the live socket bound to the origin's exact coordinate (set from the\r\n * handshake) is a strictly more precise match than any env-level `peerClient` score. This lets one\r\n * server accept clients of *several* envs over a single acceptor (a multi-role Durable Object): the\r\n * result/push routes back over the carrier the client actually connected on even when the handler's\r\n * `clientEnv` is unset or names a different env. Only when no handler owns a live connection do we fall\r\n * back to the plain best-coordinate-score pick (the offline-return and connector-only cases).\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 // Track the owning handler regardless of score; among several owners the higher score breaks the\r\n // tie (first-registered on an all-equal tie, since `>` keeps the earlier one).\r\n if (handler.ownsLiveConnectionFor(originClient) && score > bestOwnedScore) {\r\n bestOwnedScore = score;\r\n bestOwnedHandler = handler;\r\n }\r\n }\r\n\r\n if (bestOwnedHandler != null) 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 {\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 * scored against an action's `originClient` to pick this handler when *no* handler holds the client's\r\n * live connection (the offline-return fallback). A handler that currently owns the live socket always\r\n * wins regardless, so this is optional: omit it for a multi-role server that accepts several client envs\r\n * over one acceptor — it then defaults to `RuntimeCoordinate.unknown` (scores 0 against every client).\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 receives\r\n * the primed request plus a per-invocation `context` — whatever the wiring's context mapper produces from\r\n * the originating connection. The low-level handler passes the raw connection (`TConn | undefined`); the\r\n * higher-level `serveChannel` enriches it into an `IConnectionContext` (state + broadcast + pushBack). A\r\n * case may return the action's raw output, a result payload, or nothing (auto-wrapped as an empty\r\n * success) — exactly like a local handler case.\r\n */\r\nexport type TAcceptorCaseFn<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n TCtx,\r\n> = (\r\n action: TDistributeActionPayload_Request<DOM, ID>,\r\n context: TCtx,\r\n) => ReturnType<THandleActionExecutionFn<DOM, ID>> | void;\r\n\r\n/**\r\n * The connection-aware case the bare {@link AcceptorHandler} serves: its `context` is the originating\r\n * client's live connection (resolved from the request's `originClient`, `undefined` if the socket is\r\n * gone). It's {@link TAcceptorCaseFn} fixed to `TConn | undefined` — the un-enriched shape used by\r\n * {@link AcceptorHandler.forConnectionDomainCases} and `acceptChannelConnections`.\r\n */\r\nexport type TAcceptorConnectionCaseFn<\r\n DOM extends IActionDomain,\r\n ID extends keyof DOM[\"actionSchema\"] & string,\r\n TConn,\r\n> = TAcceptorCaseFn<DOM, ID, TConn | undefined>;\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 ?? RuntimeCoordinate.unknown);\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 // Default context = the raw connection (or undefined when the socket is gone). The cast bridges the\r\n // per-id mapped case map to the merged `any`-keyed map the multi form iterates (a known TS variance\r\n // limitation on the contravariant action param — same bridge `acceptChannelConnections` uses).\r\n return this.forConnectionDomainCasesMulti(\r\n [domain],\r\n cases as Record<string, TAcceptorConnectionCaseFn<any, any, TConn> | undefined>,\r\n (connection) => connection,\r\n );\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` / `serveChannel`) where the channel's\r\n * `toAcceptor` domains are served together. Each domain takes only the cases whose ids it owns, so a\r\n * single map can cover several domains and unrelated ids are ignored.\r\n *\r\n * `mapContext` turns the resolved connection into whatever the case's second argument should be: the\r\n * raw connection for the low-level helper, or an enriched `IConnectionContext` for `serveChannel`. It's\r\n * called once per inbound action, after the originating connection is resolved.\r\n */\r\n forConnectionDomainCasesMulti<TCtx>(\r\n domains: readonly ActionDomain<any>[],\r\n cases: Record<string, TAcceptorCaseFn<any, any, TCtx> | undefined>,\r\n mapContext: (\r\n connection: TConn | undefined,\r\n request: ActionPayload_Request<any, any>,\r\n ) => TCtx,\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 const connection = this.getConnectionForClient(request.context.originClient);\r\n return caseFn(request, mapContext(connection, request));\r\n };\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 { IActionChannel } from \"../../../Channel/ActionChannel\";\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: IActionChannel;\r\n /**\r\n * Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env(\"web_app\")`),\r\n * used as the offline-return scoring fallback (a live connection always wins regardless). Optional —\r\n * omit it for a multi-role server accepting several client envs over one acceptor.\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 storage: 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 `storage`.\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 `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\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 * `storage`, 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.storage });\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.storage),\r\n },\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 { 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. Built by the internal `transport({ carrier, secure })` factory (which\r\n * `connectChannel` / `serveChannel` drive) and passed to a `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 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 { 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 { 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 a secure HTTP\r\n * transport (`connectChannel(..., { transports: [{ carrier: httpCarrier(...) }] })`). When omitted, the\r\n * endpoint speaks the 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"],"mappings":"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"}