@nice-code/action 0.23.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.
- package/README.md +71 -26
- package/build/{ActionPayload.types-B-OSg09t.d.mts → AcceptorHandler-BizUtq4u.d.mts} +1267 -1543
- package/build/{ActionPayload.types-DIOeVapm.d.cts → AcceptorHandler-CxPfZtIl.d.cts} +1267 -1543
- package/build/{ActionDevtoolsCore-BjbhFqc0.d.mts → ActionDevtoolsCore-D9KBBI2V.d.cts} +2 -2
- package/build/{ActionDevtoolsCore-kk7oZBv9.d.cts → ActionDevtoolsCore-xZjAtB4H.d.mts} +2 -2
- package/build/advanced/index.cjs +115 -0
- package/build/advanced/index.cjs.map +1 -0
- package/build/advanced/index.d.cts +249 -0
- package/build/advanced/index.d.mts +249 -0
- package/build/advanced/index.mjs +88 -0
- package/build/advanced/index.mjs.map +1 -0
- package/build/{httpAcceptorCarrier-DJVxzDVd.mjs → createHibernatableWsServerAdapter-BkjESd01.mjs} +243 -429
- package/build/createHibernatableWsServerAdapter-BkjESd01.mjs.map +1 -0
- package/build/{httpAcceptorCarrier-hYPuoNuP.cjs → createHibernatableWsServerAdapter-FSDWrxoF.cjs} +268 -478
- package/build/createHibernatableWsServerAdapter-FSDWrxoF.cjs.map +1 -0
- package/build/devtools/browser/index.d.cts +1 -1
- package/build/devtools/browser/index.d.mts +1 -1
- package/build/devtools/server/index.d.cts +1 -1
- package/build/devtools/server/index.d.mts +1 -1
- package/build/httpAcceptorCarrier-BQYaXI9j.cjs +454 -0
- package/build/httpAcceptorCarrier-BQYaXI9j.cjs.map +1 -0
- package/build/httpAcceptorCarrier-DWqsCz3h.mjs +401 -0
- package/build/httpAcceptorCarrier-DWqsCz3h.mjs.map +1 -0
- package/build/index.cjs +73 -449
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +2 -2
- package/build/index.d.mts +2 -2
- package/build/index.mjs +13 -365
- package/build/index.mjs.map +1 -1
- package/build/platform/cloudflare/index.cjs +45 -1
- package/build/platform/cloudflare/index.cjs.map +1 -1
- package/build/platform/cloudflare/index.d.cts +42 -4
- package/build/platform/cloudflare/index.d.mts +42 -4
- package/build/platform/cloudflare/index.mjs +45 -2
- package/build/platform/cloudflare/index.mjs.map +1 -1
- package/build/react-query/index.d.cts +1 -1
- package/build/react-query/index.d.mts +1 -1
- package/package.json +15 -4
- package/build/httpAcceptorCarrier-DJVxzDVd.mjs.map +0 -1
- package/build/httpAcceptorCarrier-hYPuoNuP.cjs.map +0 -1
|
@@ -175,6 +175,28 @@ type TInferOutputFromSchema<SCH extends ActionSchema<any, any, any>> = SCH exten
|
|
|
175
175
|
} : never;
|
|
176
176
|
type TWrappableDomainActionHandler<DOM extends IActionDomain> = { [K in TDomainActionId<DOM>]: (...args: [TInferInputFromSchema<DOM["actionSchema"][K]>["Input"]] extends [never] ? [] : [input: TInferInputFromSchema<DOM["actionSchema"][K]>["Input"]]) => [TInferOutputFromSchema<DOM["actionSchema"][K]>["Output"]] extends [never] ? Promise<void> | void : Promise<TInferOutputFromSchema<DOM["actionSchema"][K]>["Output"]> };
|
|
177
177
|
//#endregion
|
|
178
|
+
//#region src/ActionDefinition/Action/ActionBase.d.ts
|
|
179
|
+
declare abstract class ActionBase<FORM extends EActionForm, DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> implements IActionBase<FORM, DOM, ID> {
|
|
180
|
+
readonly form: FORM;
|
|
181
|
+
readonly _domain: ActionDomain<DOM>;
|
|
182
|
+
readonly id: ID;
|
|
183
|
+
readonly domain: DOM["domain"];
|
|
184
|
+
readonly allDomains: DOM["allDomains"];
|
|
185
|
+
readonly schema: DOM["actionSchema"][ID];
|
|
186
|
+
constructor(form: FORM, _domain: ActionDomain<DOM>, id: ID);
|
|
187
|
+
protected toJsonObject(): IActionBase_JsonObject<FORM, DOM, ID>;
|
|
188
|
+
protected toJsonString(): string;
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/ActionDefinition/Action/Core/ActionCore.types.d.ts
|
|
192
|
+
interface IActionCore<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends IActionBase<EActionForm.core, DOM, ID> {}
|
|
193
|
+
type IActionCore_JsonObject<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = {
|
|
194
|
+
form: EActionForm.core;
|
|
195
|
+
domain: DOM["domain"];
|
|
196
|
+
allDomains: DOM["allDomains"];
|
|
197
|
+
id: ID;
|
|
198
|
+
};
|
|
199
|
+
//#endregion
|
|
178
200
|
//#region src/ActionRuntime/RuntimeCoordinate.d.ts
|
|
179
201
|
interface IRuntimeCoordinateSpecifics {
|
|
180
202
|
/**
|
|
@@ -238,43 +260,6 @@ declare class RuntimeCoordinate implements IRuntimeCoordinate {
|
|
|
238
260
|
toStringIds(): TRuntimeCoordinateStringId[];
|
|
239
261
|
}
|
|
240
262
|
//#endregion
|
|
241
|
-
//#region src/ActionDefinition/Action/ActionBase.types.d.ts
|
|
242
|
-
declare enum EActionForm {
|
|
243
|
-
core = "core",
|
|
244
|
-
context = "context",
|
|
245
|
-
data = "data"
|
|
246
|
-
}
|
|
247
|
-
interface INiceActionIdAndDomain<DOM extends IActionDomain = IActionDomain> {
|
|
248
|
-
domain: DOM["domain"];
|
|
249
|
-
id: keyof DOM["actionSchema"] & string;
|
|
250
|
-
}
|
|
251
|
-
interface IActionBase<FORM extends EActionForm, DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends INiceActionIdAndDomain<DOM> {
|
|
252
|
-
id: ID;
|
|
253
|
-
form: FORM;
|
|
254
|
-
_domain: ActionDomain<DOM>;
|
|
255
|
-
allDomains: DOM["allDomains"];
|
|
256
|
-
schema: DOM["actionSchema"][ID];
|
|
257
|
-
}
|
|
258
|
-
interface IActionBase_JsonObject<FORM extends EActionForm = EActionForm, DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> {
|
|
259
|
-
form: FORM;
|
|
260
|
-
domain: DOM["domain"];
|
|
261
|
-
allDomains: DOM["allDomains"];
|
|
262
|
-
id: ID;
|
|
263
|
-
}
|
|
264
|
-
//#endregion
|
|
265
|
-
//#region src/ActionDefinition/Action/ActionBase.d.ts
|
|
266
|
-
declare abstract class ActionBase<FORM extends EActionForm, DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> implements IActionBase<FORM, DOM, ID> {
|
|
267
|
-
readonly form: FORM;
|
|
268
|
-
readonly _domain: ActionDomain<DOM>;
|
|
269
|
-
readonly id: ID;
|
|
270
|
-
readonly domain: DOM["domain"];
|
|
271
|
-
readonly allDomains: DOM["allDomains"];
|
|
272
|
-
readonly schema: DOM["actionSchema"][ID];
|
|
273
|
-
constructor(form: FORM, _domain: ActionDomain<DOM>, id: ID);
|
|
274
|
-
protected toJsonObject(): IActionBase_JsonObject<FORM, DOM, ID>;
|
|
275
|
-
protected toJsonString(): string;
|
|
276
|
-
}
|
|
277
|
-
//#endregion
|
|
278
263
|
//#region src/ActionDefinition/Action/Context/ActionContext.types.d.ts
|
|
279
264
|
interface IActionRouteItem {
|
|
280
265
|
runtime: RuntimeCoordinate;
|
|
@@ -338,6 +323,17 @@ declare abstract class ActionPayload<DT extends EActionPayloadType, DOM extends
|
|
|
338
323
|
abstract toJsonObject(): IActionPayload_Base_JsonObject<DT, DOM, ID>;
|
|
339
324
|
}
|
|
340
325
|
//#endregion
|
|
326
|
+
//#region src/ActionDefinition/Action/Payload/ActionPayload_Progress.d.ts
|
|
327
|
+
declare class ActionPayload_Progress<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends ActionPayload<EActionPayloadType.progress, DOM, ID> implements IActionPayload_Progress<DOM, ID> {
|
|
328
|
+
readonly progress: TActionProgress;
|
|
329
|
+
constructor(params: {
|
|
330
|
+
context: ActionContext<DOM, ID>;
|
|
331
|
+
} | ActionPayload_Request<DOM, ID>, progress: TActionProgress, data: IActionPayload_Data_Base);
|
|
332
|
+
toJsonObject(): IActionPayload_Progress_JsonObject<DOM, ID>;
|
|
333
|
+
toJsonString(): string;
|
|
334
|
+
toHttpResponse(): Response;
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
341
337
|
//#region src/ActionDefinition/Action/Payload/ActionPayload_Result.d.ts
|
|
342
338
|
declare class ActionPayload_Result<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends ActionPayload<EActionPayloadType.result, DOM, ID> {
|
|
343
339
|
readonly result: TActionResultOutcome<TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"], TInferActionError<DOM["actionSchema"][ID]>>;
|
|
@@ -420,40 +416,79 @@ interface IRunningActionUserMethods<DOM extends IActionDomain, ID extends keyof
|
|
|
420
416
|
abort(reason?: unknown): void;
|
|
421
417
|
}
|
|
422
418
|
//#endregion
|
|
423
|
-
//#region src/ActionDefinition/Action/
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
419
|
+
//#region src/ActionDefinition/Action/RunningAction.d.ts
|
|
420
|
+
declare class RunningAction<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> implements IRunningActionUserMethods<DOM, ID> {
|
|
421
|
+
protected _state: IRunningActionState<DOM, ID>;
|
|
422
|
+
readonly context: ActionContext<DOM, ID>;
|
|
423
|
+
readonly cuid: string;
|
|
424
|
+
readonly id: ID;
|
|
425
|
+
readonly _domain: ActionDomain<DOM>;
|
|
426
|
+
readonly domain: DOM["domain"];
|
|
427
|
+
readonly allDomains: DOM["allDomains"];
|
|
428
|
+
readonly parentCuid?: string;
|
|
429
|
+
readonly callSite?: string;
|
|
430
|
+
private readonly _resultPayloadPromise;
|
|
431
|
+
private _resolveResult;
|
|
432
|
+
private _rejectResult;
|
|
433
|
+
private _isAborted;
|
|
434
|
+
private readonly _updates;
|
|
435
|
+
private readonly _updateListeners;
|
|
436
|
+
constructor(initialState: IRunningActionState_ConstructorParams<DOM, ID>);
|
|
437
|
+
get state(): IRunningActionState<DOM, ID>;
|
|
438
|
+
abort(reason?: unknown): void;
|
|
439
|
+
addUpdateListeners(listeners: TRunningActionUpdateListener<DOM, ID>[]): () => void;
|
|
440
|
+
iterateUpdates(): AsyncIterable<TRunningActionUpdate<DOM, ID>>;
|
|
441
|
+
_sendUpdate(update: TRunningActionUpdate<DOM, ID>): void;
|
|
442
|
+
_completeWithResult(result: ActionPayload_Result<DOM, ID>): boolean;
|
|
443
|
+
_abort(reason?: unknown): boolean;
|
|
444
|
+
_failWithError(error: unknown): boolean;
|
|
445
|
+
_updateProgress(progress: ActionPayload_Progress<DOM, ID>): void;
|
|
446
|
+
waitForResultPayload(): Promise<ActionPayload_Result<DOM, ID>>;
|
|
447
|
+
_resolveFromJson(resultJson: IActionPayload_Result_JsonObject<DOM, ID>): boolean;
|
|
448
|
+
}
|
|
431
449
|
//#endregion
|
|
432
|
-
//#region src/ActionDefinition/
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
450
|
+
//#region src/ActionDefinition/Domain/ActionDomainBase.d.ts
|
|
451
|
+
declare abstract class ActionDomainBase<ACT_DOM extends IActionDomain = IActionDomain> implements IActionDomain<ACT_DOM["allDomains"], ACT_DOM["actionSchema"]> {
|
|
452
|
+
readonly domain: ACT_DOM["domain"];
|
|
453
|
+
readonly allDomains: ACT_DOM["allDomains"];
|
|
454
|
+
readonly actionSchema: ACT_DOM["actionSchema"];
|
|
455
|
+
protected _listeners: TRunningActionUpdateListener<any, any>[];
|
|
456
|
+
constructor(definition: ACT_DOM);
|
|
457
|
+
/**
|
|
458
|
+
* Add an observer that is called after every action dispatched through this domain.
|
|
459
|
+
* Returns an unsubscribe function — call it to remove the listener.
|
|
460
|
+
*/
|
|
461
|
+
addActionListener(listener: TDistributeRunningActionUpdateListener<ACT_DOM, keyof ACT_DOM["actionSchema"] & string>): () => void;
|
|
462
|
+
/**
|
|
463
|
+
* @internal
|
|
464
|
+
* Observers registered directly on this domain via {@link addActionListener}.
|
|
465
|
+
* Used to wire observers (e.g. devtools) onto RunningActions that aren't created
|
|
466
|
+
* through the local-dispatch path — notably inbound actions pushed from a backend
|
|
467
|
+
* or another client over a bidirectional transport.
|
|
468
|
+
*/
|
|
469
|
+
_getActionObservers(): TRunningActionUpdateListener<any, any>[];
|
|
470
|
+
}
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region src/ActionDefinition/Domain/ActionRootDomain.d.ts
|
|
473
|
+
declare class ActionRootDomain<ROOT_DOM extends IActionRootDomain = IActionRootDomain> extends ActionDomainBase<ROOT_DOM> {
|
|
474
|
+
readonly domainDefinition: {
|
|
475
|
+
domain: ROOT_DOM["domain"];
|
|
476
|
+
};
|
|
477
|
+
private _actionRuntimeManager;
|
|
478
|
+
constructor(domainDefinition: {
|
|
479
|
+
domain: ROOT_DOM["domain"];
|
|
480
|
+
});
|
|
481
|
+
createChildDomain<SUB_DOM extends IActionDomainChildOptions>(subDomainDef: SUB_DOM & { [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never }): ActionDomain<TActionDomainChildDef<ROOT_DOM, SUB_DOM>>;
|
|
482
|
+
_registerRuntime(runtime: ActionRuntime): void;
|
|
483
|
+
_hasRuntime(runtime: ActionRuntime): boolean;
|
|
484
|
+
getRuntime(clientSpecifier: IRuntimeCoordinate): ActionRuntime | undefined;
|
|
485
|
+
_runAction<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string, ACT extends ActionPayload_Request<DOM, ID> = ActionPayload_Request<DOM, ID>>(actionPayload: ACT, options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>>;
|
|
486
|
+
}
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/ActionDefinition/Domain/helpers/createRootActionDomain.d.ts
|
|
489
|
+
declare const createActionRootDomain: <ID extends string>(definition: {
|
|
490
|
+
domain: ID;
|
|
491
|
+
}) => ActionRootDomain<IActionRootDomain<ID>>;
|
|
457
492
|
//#endregion
|
|
458
493
|
//#region src/ActionRuntime/ActionDomainManager.d.ts
|
|
459
494
|
declare class ActionDomainManager {
|
|
@@ -532,133 +567,20 @@ declare class ActionRouter<DATA> {
|
|
|
532
567
|
private _push;
|
|
533
568
|
}
|
|
534
569
|
//#endregion
|
|
535
|
-
//#region src/ActionRuntime/Handler/ActionHandler.
|
|
536
|
-
declare
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
interface IActionHandler_Local_Json extends IActionHandler_Json<EActionHandlerType.local> {}
|
|
547
|
-
type TActionHandler_Json = IActionHandler_Local_Json | IActionHandler_Peer_Json;
|
|
548
|
-
interface IHandleActionOptions {
|
|
549
|
-
timeout?: number;
|
|
550
|
-
targetPeer?: RuntimeCoordinate;
|
|
551
|
-
targetLocalRuntime?: ActionRuntime;
|
|
552
|
-
}
|
|
553
|
-
interface IExecuteActionOptions<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends IHandleActionOptions {
|
|
554
|
-
listeners?: TRunningActionUpdateListener<DOM, ID>[];
|
|
555
|
-
}
|
|
556
|
-
interface IActionHandler_Base<T extends EActionHandlerType> {
|
|
557
|
-
cuid: string;
|
|
558
|
-
handlerType: T;
|
|
559
|
-
getActionRouter: () => ActionRouter<any>;
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
*
|
|
563
|
-
* LOCAL ACTION HANDLER
|
|
564
|
-
*
|
|
565
|
-
*/
|
|
566
|
-
interface IHandleActionOptions_Local extends IHandleActionOptions {}
|
|
567
|
-
interface IActionHandler_Local extends IActionHandler_Base<EActionHandlerType.local> {
|
|
568
|
-
handleActionRequest: <DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions_Local) => Promise<RunningAction<DOM, ID>>;
|
|
569
|
-
}
|
|
570
|
-
/**
|
|
571
|
-
*
|
|
572
|
-
* PEER-LINK ACTION HANDLER
|
|
573
|
-
*
|
|
574
|
-
*/
|
|
575
|
-
interface IHandleActionOptions_Peer extends IHandleActionOptions {}
|
|
576
|
-
interface IActionHandler_Peer extends IActionHandler_Base<EActionHandlerType.peer> {
|
|
577
|
-
peerClient: RuntimeCoordinate;
|
|
578
|
-
handleActionRequest: <DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions_Peer) => Promise<RunningAction<DOM, ID>>;
|
|
579
|
-
_setIncomingActionDataListener(listener: (json: TActionPayload_Any_JsonObject<any>) => void): void;
|
|
570
|
+
//#region src/ActionRuntime/Handler/ActionHandler.d.ts
|
|
571
|
+
declare abstract class ActionHandler<T extends EActionHandlerType> implements IActionHandler_Base<T> {
|
|
572
|
+
abstract readonly handlerType: T;
|
|
573
|
+
readonly cuid: string;
|
|
574
|
+
abstract readonly actionRouter: ActionRouter<any>;
|
|
575
|
+
constructor();
|
|
576
|
+
getActionRouter(): ActionRouter<any>;
|
|
577
|
+
abstract handleActionRequest<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions): Promise<RunningAction<DOM, ID>>;
|
|
578
|
+
abstract toJsonObject(): TActionHandler_Json;
|
|
579
|
+
abstract toHandlerRouteItem(...args: any[]): IActionRouteItemHandler;
|
|
580
580
|
}
|
|
581
|
-
/**
|
|
582
|
-
*
|
|
583
|
-
* COMBINED
|
|
584
|
-
*
|
|
585
|
-
*/
|
|
586
|
-
type TActionHandler = IActionHandler_Local | IActionHandler_Peer;
|
|
587
581
|
//#endregion
|
|
588
|
-
//#region src/
|
|
589
|
-
|
|
590
|
-
readonly input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
591
|
-
readonly inputHash: string;
|
|
592
|
-
_callSite?: string;
|
|
593
|
-
constructor(params: {
|
|
594
|
-
context: ActionContext<DOM, ID>;
|
|
595
|
-
}, input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"], data: IActionPayload_Data_Base);
|
|
596
|
-
successResult(...args: [TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]] extends [never] ? [] | [output: TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]] : [output: TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]]): ActionPayload_Result<DOM, ID>;
|
|
597
|
-
errorResult(err: TInferActionError<DOM["actionSchema"][ID]>): ActionPayload_Result<DOM, ID>;
|
|
598
|
-
progress(progress: TActionProgress): ActionPayload_Progress<DOM, ID>;
|
|
599
|
-
toJsonObject(): IActionPayload_Request_JsonObject<DOM, ID>;
|
|
600
|
-
toJsonString(): string;
|
|
601
|
-
runToOutput(options?: IExecuteActionOptions<DOM, ID>): Promise<TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]>;
|
|
602
|
-
runToResultPayload(options?: IExecuteActionOptions<DOM, ID>): Promise<ActionPayload_Result<DOM, ID>>;
|
|
603
|
-
run(options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>>;
|
|
604
|
-
}
|
|
605
|
-
//#endregion
|
|
606
|
-
//#region src/ActionDefinition/Action/Payload/ActionPayload_Progress.d.ts
|
|
607
|
-
declare class ActionPayload_Progress<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends ActionPayload<EActionPayloadType.progress, DOM, ID> implements IActionPayload_Progress<DOM, ID> {
|
|
608
|
-
readonly progress: TActionProgress;
|
|
609
|
-
constructor(params: {
|
|
610
|
-
context: ActionContext<DOM, ID>;
|
|
611
|
-
} | ActionPayload_Request<DOM, ID>, progress: TActionProgress, data: IActionPayload_Data_Base);
|
|
612
|
-
toJsonObject(): IActionPayload_Progress_JsonObject<DOM, ID>;
|
|
613
|
-
toJsonString(): string;
|
|
614
|
-
toHttpResponse(): Response;
|
|
615
|
-
}
|
|
616
|
-
//#endregion
|
|
617
|
-
//#region src/ActionDefinition/Action/RunningAction.d.ts
|
|
618
|
-
declare class RunningAction<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> implements IRunningActionUserMethods<DOM, ID> {
|
|
619
|
-
protected _state: IRunningActionState<DOM, ID>;
|
|
620
|
-
readonly context: ActionContext<DOM, ID>;
|
|
621
|
-
readonly cuid: string;
|
|
622
|
-
readonly id: ID;
|
|
623
|
-
readonly _domain: ActionDomain<DOM>;
|
|
624
|
-
readonly domain: DOM["domain"];
|
|
625
|
-
readonly allDomains: DOM["allDomains"];
|
|
626
|
-
readonly parentCuid?: string;
|
|
627
|
-
readonly callSite?: string;
|
|
628
|
-
private readonly _resultPayloadPromise;
|
|
629
|
-
private _resolveResult;
|
|
630
|
-
private _rejectResult;
|
|
631
|
-
private _isAborted;
|
|
632
|
-
private readonly _updates;
|
|
633
|
-
private readonly _updateListeners;
|
|
634
|
-
constructor(initialState: IRunningActionState_ConstructorParams<DOM, ID>);
|
|
635
|
-
get state(): IRunningActionState<DOM, ID>;
|
|
636
|
-
abort(reason?: unknown): void;
|
|
637
|
-
addUpdateListeners(listeners: TRunningActionUpdateListener<DOM, ID>[]): () => void;
|
|
638
|
-
iterateUpdates(): AsyncIterable<TRunningActionUpdate<DOM, ID>>;
|
|
639
|
-
_sendUpdate(update: TRunningActionUpdate<DOM, ID>): void;
|
|
640
|
-
_completeWithResult(result: ActionPayload_Result<DOM, ID>): boolean;
|
|
641
|
-
_abort(reason?: unknown): boolean;
|
|
642
|
-
_failWithError(error: unknown): boolean;
|
|
643
|
-
_updateProgress(progress: ActionPayload_Progress<DOM, ID>): void;
|
|
644
|
-
waitForResultPayload(): Promise<ActionPayload_Result<DOM, ID>>;
|
|
645
|
-
_resolveFromJson(resultJson: IActionPayload_Result_JsonObject<DOM, ID>): boolean;
|
|
646
|
-
}
|
|
647
|
-
//#endregion
|
|
648
|
-
//#region src/ActionRuntime/Handler/ActionHandler.d.ts
|
|
649
|
-
declare abstract class ActionHandler<T extends EActionHandlerType> implements IActionHandler_Base<T> {
|
|
650
|
-
abstract readonly handlerType: T;
|
|
651
|
-
readonly cuid: string;
|
|
652
|
-
abstract readonly actionRouter: ActionRouter<any>;
|
|
653
|
-
constructor();
|
|
654
|
-
getActionRouter(): ActionRouter<any>;
|
|
655
|
-
abstract handleActionRequest<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions): Promise<RunningAction<DOM, ID>>;
|
|
656
|
-
abstract toJsonObject(): TActionHandler_Json;
|
|
657
|
-
abstract toHandlerRouteItem(...args: any[]): IActionRouteItemHandler;
|
|
658
|
-
}
|
|
659
|
-
//#endregion
|
|
660
|
-
//#region src/utils/typescript/MaybePromise.d.ts
|
|
661
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
582
|
+
//#region src/utils/typescript/MaybePromise.d.ts
|
|
583
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
662
584
|
//#endregion
|
|
663
585
|
//#region src/ActionRuntime/Handler/Local/ActionLocalHandler.types.d.ts
|
|
664
586
|
type THandleActionExecutionFn<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = (action: TDistributeActionPayload_Request<DOM, ID>) => MaybePromise<ActionPayload_Result<DOM, ID> | IActionPayload_Result_JsonObject<DOM, ID> | TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"] | undefined>;
|
|
@@ -708,72 +630,6 @@ declare class ActionLocalHandler extends ActionHandler<EActionHandlerType.local>
|
|
|
708
630
|
}
|
|
709
631
|
declare const createLocalHandler: () => ActionLocalHandler;
|
|
710
632
|
//#endregion
|
|
711
|
-
//#region src/ActionRuntime/Handler/PeerLink/PeerLinkHandler.d.ts
|
|
712
|
-
/**
|
|
713
|
-
* Shared base for every handler that routes a domain set to/from *another runtime* (a "peer") — the
|
|
714
|
-
* unified peer-link concept. Both specializations extend this as siblings, differing only in *who
|
|
715
|
-
* establishes the connection*, which is a transport trait, not a routing one:
|
|
716
|
-
*
|
|
717
|
-
* - {@link ConnectorHandler} — **dial-out**: this runtime opens connection(s) to one peer
|
|
718
|
-
* over a transport stack (with caching + fallback). The classic "client → backend" link.
|
|
719
|
-
* - {@link AcceptorHandler} — **accept-in**: connections are accepted from many peers and fed in
|
|
720
|
-
* via `receive()`; it keeps a per-connection registry and can push to any of them.
|
|
721
|
-
*
|
|
722
|
-
* To the runtime there is no "client" vs "server" — both are peer-link handlers (`handlerType =
|
|
723
|
-
* external`) keyed to a peer coordinate, chosen by the return-path dispatch via {@link sendReturnPayload}.
|
|
724
|
-
*/
|
|
725
|
-
declare abstract class PeerLinkHandler extends ActionHandler<EActionHandlerType.peer> implements IActionHandler_Peer {
|
|
726
|
-
/** The peer runtime this handler links to (an env-only coordinate for an accept-in handler). */
|
|
727
|
-
readonly peerClient: RuntimeCoordinate;
|
|
728
|
-
readonly handlerType = EActionHandlerType.peer;
|
|
729
|
-
/**
|
|
730
|
-
* Whether this link can deliver an *unsolicited* frame to the peer (a result/progress pushed back on
|
|
731
|
-
* the return path, or a `broadcast`). A duplex carrier (WebSocket/WebRTC/…) can; an exchange-only
|
|
732
|
-
* carrier (HTTP) cannot — its reply must ride the response to its own request. The runtime's
|
|
733
|
-
* return-path dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) skips handlers that can't
|
|
734
|
-
* push, so an exchange-only handler is never asked to deliver one.
|
|
735
|
-
*/
|
|
736
|
-
abstract readonly canPush: boolean;
|
|
737
|
-
readonly actionRouter: ActionRouter<true>;
|
|
738
|
-
/** Listeners installed by the runtime (`resolveIncomingActionPayload`) for inbound peer frames. */
|
|
739
|
-
private readonly _incomingActionDataListeners;
|
|
740
|
-
constructor(peerCoordinate: RuntimeCoordinate);
|
|
741
|
-
forDomain<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>): this;
|
|
742
|
-
forAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM["actionSchema"] & string>(action: ActionCore<ACT_DOM, ID>): this;
|
|
743
|
-
forActionIds<ACT_DOM extends IActionDomain, IDS extends ReadonlyArray<keyof ACT_DOM["actionSchema"] & string>>(domain: ActionDomain<ACT_DOM>, ids: IDS): this;
|
|
744
|
-
_setIncomingActionDataListener(listener: (json: TActionPayload_Any_JsonObject<any, any>) => void): void;
|
|
745
|
-
/** Hand a decoded inbound frame to the runtime (called by each specialization's receive path). */
|
|
746
|
-
protected _emitIncoming(json: TActionPayload_Any_JsonObject<any, any>): void;
|
|
747
|
-
/**
|
|
748
|
-
* Dispatch a result/progress payload back to the action's origin peer over this link. The runtime's
|
|
749
|
-
* return-path dispatch calls it on whichever peer-link handler best reaches `originClient`. Returns
|
|
750
|
-
* `true` if it was sent, `false` if no channel was available.
|
|
751
|
-
*/
|
|
752
|
-
abstract sendReturnPayload(payload: TActionPayload_Any_Instance<any, any>, config: {
|
|
753
|
-
targetLocalRuntime: ActionRuntime;
|
|
754
|
-
}): Promise<boolean>;
|
|
755
|
-
/**
|
|
756
|
-
* Whether this handler currently holds a *live* connection bound to `origin`. The runtime's return-path
|
|
757
|
-
* dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) prefers a handler that owns the origin's
|
|
758
|
-
* connection over a mere coordinate match, so with several duplex acceptors a result/push routes back
|
|
759
|
-
* over the carrier the client connected on. Defaults to `false`; an acceptor overrides it from its
|
|
760
|
-
* connection registry.
|
|
761
|
-
*/
|
|
762
|
-
ownsLiveConnectionFor(_origin: RuntimeCoordinate): boolean;
|
|
763
|
-
/** Release any long-lived connections this handler owns (a teardown). No-op by default. */
|
|
764
|
-
clearTransportCache(): void;
|
|
765
|
-
}
|
|
766
|
-
//#endregion
|
|
767
|
-
//#region src/ActionRuntime/ActionRuntime.types.d.ts
|
|
768
|
-
interface IRuntimeMeta {
|
|
769
|
-
assumed: boolean;
|
|
770
|
-
runtimeName: RuntimeName;
|
|
771
|
-
}
|
|
772
|
-
interface IActionRuntimeManagerContext {
|
|
773
|
-
domain?: string;
|
|
774
|
-
}
|
|
775
|
-
type TActionRuntimeHandler = ActionLocalHandler | PeerLinkHandler;
|
|
776
|
-
//#endregion
|
|
777
633
|
//#region src/ActionRuntime/Transport/crypto/actionHandshake.d.ts
|
|
778
634
|
/** How much the channel protects after the handshake — chosen by the consumer (perf vs security). */
|
|
779
635
|
declare enum ESecurityLevel {
|
|
@@ -958,6 +814,51 @@ declare function createServerHandshake(config: IServerHandshakeConfig): {
|
|
|
958
814
|
getResult(): IHandshakeResult | undefined;
|
|
959
815
|
};
|
|
960
816
|
//#endregion
|
|
817
|
+
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/createSecureActionServer.d.ts
|
|
818
|
+
interface ISecureAcceptorHandlerOptions<TConn> {
|
|
819
|
+
/** The shared channel identity (codec + dictionary version) — same one the clients use. */
|
|
820
|
+
channel: IActionChannel;
|
|
821
|
+
/**
|
|
822
|
+
* Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env("web_app")`),
|
|
823
|
+
* used as the offline-return scoring fallback (a live connection always wins regardless). Optional —
|
|
824
|
+
* omit it for a multi-role server accepting several client envs over one acceptor.
|
|
825
|
+
*/
|
|
826
|
+
clientEnv?: RuntimeCoordinate;
|
|
827
|
+
/** This server's runtime — its coordinate is the server identity presented in the handshake. */
|
|
828
|
+
runtime: ActionRuntime;
|
|
829
|
+
/**
|
|
830
|
+
* One backing store for the server's crypto identity *and* its trust-on-first-use verify-key pins.
|
|
831
|
+
* Their keys don't collide, so a single adapter is enough; back it with persistent storage (e.g. a
|
|
832
|
+
* Durable Object's storage) so identity and pins survive eviction.
|
|
833
|
+
*/
|
|
834
|
+
storage: StorageAdapter;
|
|
835
|
+
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
836
|
+
send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;
|
|
837
|
+
/**
|
|
838
|
+
* The server's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storage`.
|
|
839
|
+
* Pass an existing link to share one identity across several acceptors on the same server (e.g. a
|
|
840
|
+
* WebSocket acceptor and a secure-HTTP {@link createActionFetchHandler}), so they present the same
|
|
841
|
+
* verify/exchange keys — avoiding a divergent-key race when two fresh links initialize concurrently.
|
|
842
|
+
*/
|
|
843
|
+
link?: ClientCryptoKeyLink;
|
|
844
|
+
/** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */
|
|
845
|
+
securityLevel?: ESecurityLevel | readonly ESecurityLevel[];
|
|
846
|
+
/** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storage`. */
|
|
847
|
+
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
848
|
+
/** Timeout (ms) applied to server-initiated actions awaiting a client response. */
|
|
849
|
+
defaultTimeout?: number;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Build an {@link AcceptorHandler} for the secure binary channel with the boilerplate folded in:
|
|
853
|
+
* it creates the {@link ClientCryptoKeyLink} and the storage-backed TOFU resolver from a single
|
|
854
|
+
* `storage`, installs the channel's per-connection codec, and assembles the `security` block
|
|
855
|
+
* from the runtime coordinate + channel version (accepting all three levels by default).
|
|
856
|
+
*
|
|
857
|
+
* For a hibernatable transport (e.g. a Durable Object), pair it with
|
|
858
|
+
* {@link createHibernatableWsServerAdapter} to wire persistence + replay.
|
|
859
|
+
*/
|
|
860
|
+
declare function createSecureAcceptorHandler<TConn = unknown>(options: ISecureAcceptorHandlerOptions<TConn>): AcceptorHandler<TConn>;
|
|
861
|
+
//#endregion
|
|
961
862
|
//#region src/ActionRuntime/Transport/Transport.d.ts
|
|
962
863
|
/**
|
|
963
864
|
* Context handed to a {@link Transport} definition when a handler builds a live connection from it.
|
|
@@ -967,9 +868,8 @@ interface ITransportConnectionContext {
|
|
|
967
868
|
resolvers?: IActionTransportResolvers;
|
|
968
869
|
}
|
|
969
870
|
/**
|
|
970
|
-
* Reusable transport definition.
|
|
971
|
-
* `
|
|
972
|
-
* `ConnectorHandler`. A single
|
|
871
|
+
* Reusable transport definition. Built by the internal `transport({ carrier, secure })` factory (which
|
|
872
|
+
* `connectChannel` / `serveChannel` drive) and passed to a `ConnectorHandler`. A single
|
|
973
873
|
* definition can be shared across multiple handlers — each handler builds its own live
|
|
974
874
|
* {@link TransportConnection} via {@link TransportConnection._createConnection}.
|
|
975
875
|
*/
|
|
@@ -1197,6 +1097,62 @@ interface IActionTransportDef<TYPE extends ETransportShape, INIT extends IAction
|
|
|
1197
1097
|
initialize: () => INIT;
|
|
1198
1098
|
}
|
|
1199
1099
|
//#endregion
|
|
1100
|
+
//#region src/ActionRuntime/Handler/PeerLink/PeerLinkHandler.d.ts
|
|
1101
|
+
/**
|
|
1102
|
+
* Shared base for every handler that routes a domain set to/from *another runtime* (a "peer") — the
|
|
1103
|
+
* unified peer-link concept. Both specializations extend this as siblings, differing only in *who
|
|
1104
|
+
* establishes the connection*, which is a transport trait, not a routing one:
|
|
1105
|
+
*
|
|
1106
|
+
* - {@link ConnectorHandler} — **dial-out**: this runtime opens connection(s) to one peer
|
|
1107
|
+
* over a transport stack (with caching + fallback). The classic "client → backend" link.
|
|
1108
|
+
* - {@link AcceptorHandler} — **accept-in**: connections are accepted from many peers and fed in
|
|
1109
|
+
* via `receive()`; it keeps a per-connection registry and can push to any of them.
|
|
1110
|
+
*
|
|
1111
|
+
* To the runtime there is no "client" vs "server" — both are peer-link handlers (`handlerType =
|
|
1112
|
+
* external`) keyed to a peer coordinate, chosen by the return-path dispatch via {@link sendReturnPayload}.
|
|
1113
|
+
*/
|
|
1114
|
+
declare abstract class PeerLinkHandler extends ActionHandler<EActionHandlerType.peer> implements IActionHandler_Peer {
|
|
1115
|
+
/** The peer runtime this handler links to (an env-only coordinate for an accept-in handler). */
|
|
1116
|
+
readonly peerClient: RuntimeCoordinate;
|
|
1117
|
+
readonly handlerType = EActionHandlerType.peer;
|
|
1118
|
+
/**
|
|
1119
|
+
* Whether this link can deliver an *unsolicited* frame to the peer (a result/progress pushed back on
|
|
1120
|
+
* the return path, or a `broadcast`). A duplex carrier (WebSocket/WebRTC/…) can; an exchange-only
|
|
1121
|
+
* carrier (HTTP) cannot — its reply must ride the response to its own request. The runtime's
|
|
1122
|
+
* return-path dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) skips handlers that can't
|
|
1123
|
+
* push, so an exchange-only handler is never asked to deliver one.
|
|
1124
|
+
*/
|
|
1125
|
+
abstract readonly canPush: boolean;
|
|
1126
|
+
readonly actionRouter: ActionRouter<true>;
|
|
1127
|
+
/** Listeners installed by the runtime (`resolveIncomingActionPayload`) for inbound peer frames. */
|
|
1128
|
+
private readonly _incomingActionDataListeners;
|
|
1129
|
+
constructor(peerCoordinate: RuntimeCoordinate);
|
|
1130
|
+
forDomain<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>): this;
|
|
1131
|
+
forAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM["actionSchema"] & string>(action: ActionCore<ACT_DOM, ID>): this;
|
|
1132
|
+
forActionIds<ACT_DOM extends IActionDomain, IDS extends ReadonlyArray<keyof ACT_DOM["actionSchema"] & string>>(domain: ActionDomain<ACT_DOM>, ids: IDS): this;
|
|
1133
|
+
_setIncomingActionDataListener(listener: (json: TActionPayload_Any_JsonObject<any, any>) => void): void;
|
|
1134
|
+
/** Hand a decoded inbound frame to the runtime (called by each specialization's receive path). */
|
|
1135
|
+
protected _emitIncoming(json: TActionPayload_Any_JsonObject<any, any>): void;
|
|
1136
|
+
/**
|
|
1137
|
+
* Dispatch a result/progress payload back to the action's origin peer over this link. The runtime's
|
|
1138
|
+
* return-path dispatch calls it on whichever peer-link handler best reaches `originClient`. Returns
|
|
1139
|
+
* `true` if it was sent, `false` if no channel was available.
|
|
1140
|
+
*/
|
|
1141
|
+
abstract sendReturnPayload(payload: TActionPayload_Any_Instance<any, any>, config: {
|
|
1142
|
+
targetLocalRuntime: ActionRuntime;
|
|
1143
|
+
}): Promise<boolean>;
|
|
1144
|
+
/**
|
|
1145
|
+
* Whether this handler currently holds a *live* connection bound to `origin`. The runtime's return-path
|
|
1146
|
+
* dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) prefers a handler that owns the origin's
|
|
1147
|
+
* connection over a mere coordinate match, so with several duplex acceptors a result/push routes back
|
|
1148
|
+
* over the carrier the client connected on. Defaults to `false`; an acceptor overrides it from its
|
|
1149
|
+
* connection registry.
|
|
1150
|
+
*/
|
|
1151
|
+
ownsLiveConnectionFor(_origin: RuntimeCoordinate): boolean;
|
|
1152
|
+
/** Release any long-lived connections this handler owns (a teardown). No-op by default. */
|
|
1153
|
+
clearTransportCache(): void;
|
|
1154
|
+
}
|
|
1155
|
+
//#endregion
|
|
1200
1156
|
//#region src/ActionRuntime/Handler/PeerLink/Connector/ConnectorHandler.types.d.ts
|
|
1201
1157
|
interface IConnectorHandlerConfig {
|
|
1202
1158
|
defaultTimeout?: number;
|
|
@@ -1242,180 +1198,98 @@ declare class ConnectorHandler extends PeerLinkHandler {
|
|
|
1242
1198
|
}
|
|
1243
1199
|
declare const createConnectorHandler: (config: IConnectorHandlerConfig) => ConnectorHandler;
|
|
1244
1200
|
//#endregion
|
|
1245
|
-
//#region src/ActionRuntime/
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
* Return the first handler registered for the given action, or `undefined`
|
|
1274
|
-
* if none has been registered (action-ID-specific beats domain-wildcard).
|
|
1275
|
-
*/
|
|
1276
|
-
_getHandlerForAction<ACT extends TActionPayload_Any_Instance<any, any>>(action: ACT, options?: Omit<IHandleActionOptions, "targetLocalRuntime">): TActionHandler | undefined;
|
|
1277
|
-
getHandlerForActionOrThrow<ACT extends TActionPayload_Any_Instance<any, any>>(action: ACT, options?: Omit<IHandleActionOptions, "localRuntime">): TActionHandler;
|
|
1278
|
-
/**
|
|
1279
|
-
* Register one or more handlers. Each handler's own `actionRouter` defines
|
|
1280
|
-
* which domains/actions it handles — those routing keys are mirrored into
|
|
1281
|
-
* this runtime's router so the same action can be served by multiple handlers.
|
|
1282
|
-
* Duplicate registrations (same handler cuid for the same key) are skipped.
|
|
1283
|
-
*/
|
|
1284
|
-
addHandlers(handlers: TActionRuntimeHandler[]): this;
|
|
1285
|
-
/**
|
|
1286
|
-
* @internal Low-level primitive — the public way to open a connection is `connectChannel`, which
|
|
1287
|
-
* derives routing from a channel and binds the crypto identity for you. This stays as the raw building
|
|
1288
|
-
* block it sits on (it restates domain lists by hand) and is not part of the supported surface.
|
|
1289
|
-
*
|
|
1290
|
-
* Declare an external "backend client" in one call: build an
|
|
1291
|
-
* {@link ConnectorHandler} for `externalCoordinate` carrying the given
|
|
1292
|
-
* `transports`, route the listed `domains`/`actions` to it, register it (plus any
|
|
1293
|
-
* `localHandlers` — e.g. server→client push handlers that share the same channel)
|
|
1294
|
-
* on this runtime, and `apply()`. Returns the external handler so the caller can
|
|
1295
|
-
* later `clearTransportCache()` it.
|
|
1296
|
-
*/
|
|
1297
|
-
connectTo(externalCoordinate: RuntimeCoordinate, options: {
|
|
1298
|
-
transports: Transport[];
|
|
1299
|
-
domains?: ActionDomain<any>[];
|
|
1300
|
-
actions?: ActionCore<any, any>[];
|
|
1301
|
-
localHandlers?: TActionRuntimeHandler[];
|
|
1302
|
-
defaultTimeout?: number;
|
|
1303
|
-
}): ConnectorHandler;
|
|
1304
|
-
private applyRuntimeForDomain;
|
|
1305
|
-
/**
|
|
1306
|
-
* Register this runtime with all root domains covered by its currently-added handlers,
|
|
1307
|
-
* making it eligible to execute actions dispatched from those domains.
|
|
1308
|
-
* After apply() is called, any subsequent addHandlers() calls also auto-register.
|
|
1309
|
-
*/
|
|
1310
|
-
apply(): this;
|
|
1311
|
-
/**
|
|
1312
|
-
* Find the best registered external handler that can reach `originClient` directly.
|
|
1313
|
-
* Used to locate the return-path channel for dispatching results back to the action origin.
|
|
1314
|
-
* Returns `undefined` if no handler matches (score > 0 required, i.e. at least id must match).
|
|
1315
|
-
*
|
|
1316
|
-
* A handler that currently holds the origin's *live* connection always wins over a mere coordinate
|
|
1317
|
-
* match — so with several duplex acceptors (e.g. WS + WebRTC) a result/push routes back over the carrier
|
|
1318
|
-
* the client actually connected on, never a same-coordinate sibling that lacks the socket. Only when no
|
|
1319
|
-
* handler owns a live connection do we fall back to the plain best-coordinate-score pick (the
|
|
1320
|
-
* single-acceptor and connector-only cases, unchanged).
|
|
1321
|
-
*/
|
|
1322
|
-
getReturnHandlerForOrigin(originClient: RuntimeCoordinate): PeerLinkHandler | undefined;
|
|
1323
|
-
resetRuntime(): void;
|
|
1324
|
-
private _trySetupReturnDispatch;
|
|
1325
|
-
}
|
|
1326
|
-
//#endregion
|
|
1327
|
-
//#region src/ActionDefinition/Domain/ActionDomainBase.d.ts
|
|
1328
|
-
declare abstract class ActionDomainBase<ACT_DOM extends IActionDomain = IActionDomain> implements IActionDomain<ACT_DOM["allDomains"], ACT_DOM["actionSchema"]> {
|
|
1329
|
-
readonly domain: ACT_DOM["domain"];
|
|
1330
|
-
readonly allDomains: ACT_DOM["allDomains"];
|
|
1331
|
-
readonly actionSchema: ACT_DOM["actionSchema"];
|
|
1332
|
-
protected _listeners: TRunningActionUpdateListener<any, any>[];
|
|
1333
|
-
constructor(definition: ACT_DOM);
|
|
1334
|
-
/**
|
|
1335
|
-
* Add an observer that is called after every action dispatched through this domain.
|
|
1336
|
-
* Returns an unsubscribe function — call it to remove the listener.
|
|
1337
|
-
*/
|
|
1338
|
-
addActionListener(listener: TDistributeRunningActionUpdateListener<ACT_DOM, keyof ACT_DOM["actionSchema"] & string>): () => void;
|
|
1201
|
+
//#region src/ActionRuntime/Transport/Carrier/Carrier.types.d.ts
|
|
1202
|
+
/**
|
|
1203
|
+
* Carrier shapes — the only transport-specific surface a new protocol must implement. The secure
|
|
1204
|
+
* session (handshake + frame crypto + codec) and the action routing on top of it are carrier-agnostic;
|
|
1205
|
+
* a carrier just moves frames. Two shapes capture every carrier:
|
|
1206
|
+
*
|
|
1207
|
+
* - {@link IDuplexCarrier} — a persistent, push-capable byte stream (WebSocket, WebRTC `RTCDataChannel`,
|
|
1208
|
+
* Bluetooth GATT, an in-memory pipe). Either side can send at any time, so it supports server→client
|
|
1209
|
+
* pushes (the return path + broadcast).
|
|
1210
|
+
* - {@link IExchangeCarrier} — a request → single-correlated-reply carrier with no unsolicited push
|
|
1211
|
+
* (HTTP, and anything request/response-shaped). The reply rides the response to its own request.
|
|
1212
|
+
*
|
|
1213
|
+
* Frames are `string` (text — handshake control messages and JSON action frames) or binary
|
|
1214
|
+
* (`Uint8Array`/`ArrayBuffer` — the optimized binary wire / encrypted frames).
|
|
1215
|
+
*/
|
|
1216
|
+
type TFrame$1 = string | Uint8Array | ArrayBuffer;
|
|
1217
|
+
/**
|
|
1218
|
+
* A bidirectional, push-capable byte stream. Reduces every duplex carrier to "open, send bytes, receive
|
|
1219
|
+
* bytes, close" — a WebSocket, a WebRTC data channel, a Bluetooth characteristic, or an in-memory pipe
|
|
1220
|
+
* all satisfy this, so the identical secure session runs over each.
|
|
1221
|
+
*/
|
|
1222
|
+
interface IDuplexCarrier {
|
|
1223
|
+
/** Resolves once the carrier is open and ready to send; rejects if it closes/errors before opening. */
|
|
1224
|
+
readonly ready: Promise<void>;
|
|
1225
|
+
/** Whether the carrier is currently open (a synchronous guard before `send`). */
|
|
1226
|
+
isOpen(): boolean;
|
|
1227
|
+
/** Write one frame to the peer. */
|
|
1228
|
+
send(frame: TFrame$1): void;
|
|
1339
1229
|
/**
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1342
|
-
* Used to wire observers (e.g. devtools) onto RunningActions that aren't created
|
|
1343
|
-
* through the local-dispatch path — notably inbound actions pushed from a backend
|
|
1344
|
-
* or another client over a bidirectional transport.
|
|
1230
|
+
* Register the carrier's handlers. Called exactly once by the session after `ready`. `onMessage`
|
|
1231
|
+
* receives every inbound frame; `onClose` fires when the carrier goes away.
|
|
1345
1232
|
*/
|
|
1346
|
-
|
|
1233
|
+
attach(handlers: {
|
|
1234
|
+
onMessage: (frame: TFrame$1) => void;
|
|
1235
|
+
onClose: () => void;
|
|
1236
|
+
onError?: (error: unknown) => void;
|
|
1237
|
+
}): void;
|
|
1238
|
+
/** Close the carrier deliberately (a teardown). */
|
|
1239
|
+
close(): void;
|
|
1240
|
+
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1241
|
+
readonly label?: string;
|
|
1347
1242
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
})
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
_hasRuntime(runtime: ActionRuntime): boolean;
|
|
1361
|
-
getRuntime(clientSpecifier: IRuntimeCoordinate): ActionRuntime | undefined;
|
|
1362
|
-
_runAction<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string, ACT extends ActionPayload_Request<DOM, ID> = ActionPayload_Request<DOM, ID>>(actionPayload: ACT, options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>>;
|
|
1243
|
+
/**
|
|
1244
|
+
* A request → single-correlated-reply carrier with no unsolicited push (HTTP). One `exchange` sends a
|
|
1245
|
+
* frame and resolves with exactly the one reply frame for it; the carrier itself correlates them (the
|
|
1246
|
+
* HTTP transaction), so no correlation id is needed on the wire.
|
|
1247
|
+
*/
|
|
1248
|
+
interface IExchangeCarrier {
|
|
1249
|
+
/** Send one frame, await the single correlated reply frame. */
|
|
1250
|
+
exchange(frame: TFrame$1, opts?: {
|
|
1251
|
+
signal?: AbortSignal;
|
|
1252
|
+
}): Promise<TFrame$1>;
|
|
1253
|
+
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1254
|
+
readonly label?: string;
|
|
1363
1255
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
/**
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
* path assembles in `runAction`/`_runAction`, so inbound actions (pushed from a
|
|
1381
|
-
* backend or another client) can be wired up identically and surface in devtools.
|
|
1382
|
-
*/
|
|
1383
|
-
_collectActionObservers(): TRunningActionUpdateListener<any, any>[];
|
|
1384
|
-
_registerRuntime(runtime: ActionRuntime): void;
|
|
1385
|
-
createChildDomain<SUB_DOM extends IActionDomainChildOptions>(subDomainDef: SUB_DOM & { [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never }): ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>>;
|
|
1386
|
-
get action(): TActionMap<ACT_DOM>;
|
|
1387
|
-
actionsMap(): TActionMap<ACT_DOM>;
|
|
1388
|
-
actionForId<ID extends keyof ACT_DOM["actionSchema"] & string>(id: ID): ActionCore<ACT_DOM, ID>;
|
|
1389
|
-
wrapAsPartialLocalHandler(wrappedActionExecutor: Partial<TWrappableDomainActionHandler<ACT_DOM>>): ActionLocalHandler;
|
|
1390
|
-
wrapAsLocalHandler(wrappedActionExecutor: TWrappableDomainActionHandler<ACT_DOM>): ActionLocalHandler;
|
|
1391
|
-
hydrateContext<ID extends keyof ACT_DOM["actionSchema"] & string>(id: ID, contextData: IActionContext_Data_JsonObject): ActionContext<ACT_DOM, ID>;
|
|
1392
|
-
isDomainAction<ACT extends IActionBase<any, ACT_DOM, any>>(action: ACT | unknown | null | undefined): action is TDistributedDomainActions<ACT_DOM, ACT>;
|
|
1393
|
-
hydrateRequestPayload<ID extends keyof ACT_DOM["actionSchema"] & string, P extends IActionPayload_Request_JsonObject<ACT_DOM, ID>>(serialized: P): TDistributeActionPayload_Request<ACT_DOM, ID>;
|
|
1394
|
-
hydrateResultPayload<ID extends keyof ACT_DOM["actionSchema"] & string, R extends IActionPayload_Result_JsonObject<ACT_DOM, ID>>(serialized: R): TDistributeActionPayload_Result<ACT_DOM, ID>;
|
|
1395
|
-
hydrateAnyAction<ID extends keyof ACT_DOM["actionSchema"] & string, AJ extends TAction_Any_JsonObject<ACT_DOM, ID>>(actionJson: AJ): TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;
|
|
1396
|
-
runAction<ID extends keyof ACT_DOM["actionSchema"] & string, ACT extends ActionPayload_Request<ACT_DOM, ID>>(request: ACT, options?: IExecuteActionOptions<ACT_DOM, ID>): Promise<RunningAction<ACT_DOM, ID>>;
|
|
1397
|
-
private createActionMap;
|
|
1256
|
+
type TCarrier = IDuplexCarrier | IExchangeCarrier;
|
|
1257
|
+
/**
|
|
1258
|
+
* A reusable opener for a {@link IDuplexCarrier} plus the per-action metadata a duplex transport needs.
|
|
1259
|
+
* Built by the small carrier factories (`wsCarrier`, `rtcCarrier`, `inMemoryCarrier`) and passed as a
|
|
1260
|
+
* `carrier` to `connectChannel`'s transports (the internal `transport()` factory drives it) — so adding a
|
|
1261
|
+
* new carrier is "write one of these", nothing else.
|
|
1262
|
+
*/
|
|
1263
|
+
interface IDuplexCarrierSource {
|
|
1264
|
+
/** Open (or reuse) the carrier for an action. */
|
|
1265
|
+
open: (input: ITransportRouteActionParams) => IDuplexCarrier;
|
|
1266
|
+
/** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */
|
|
1267
|
+
getCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
1268
|
+
/** Devtools route info for an action routed over this carrier. */
|
|
1269
|
+
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
1270
|
+
/** Short carrier-kind label for the devtools chip (e.g. `"ws"`, `"webrtc"`, `"memory"`). */
|
|
1271
|
+
readonly carrierLabel: string;
|
|
1398
1272
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1273
|
+
/**
|
|
1274
|
+
* The exchange-shape counterpart to {@link IDuplexCarrierSource}: a reusable opener for an
|
|
1275
|
+
* {@link IExchangeCarrier} plus the per-action metadata an exchange transport needs. Built by
|
|
1276
|
+
* `httpCarrier` and passed as a `carrier` to `connectChannel`'s transports — adding a new request/reply
|
|
1277
|
+
* protocol is "write one of these". The `shape` tag lets the internal `transport()` factory pick the
|
|
1278
|
+
* duplex vs exchange transport.
|
|
1279
|
+
*/
|
|
1280
|
+
interface IExchangeCarrierSource {
|
|
1281
|
+
/** Discriminant so a generic factory can tell an exchange source from a duplex one. */
|
|
1282
|
+
readonly shape: "exchange";
|
|
1283
|
+
/** Open (or reuse) the carrier for an action. */
|
|
1284
|
+
open: (input: ITransportRouteActionParams) => IExchangeCarrier;
|
|
1285
|
+
/** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */
|
|
1286
|
+
getCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
1287
|
+
/** Devtools route info for an action routed over this carrier. */
|
|
1288
|
+
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
1289
|
+
/** Short carrier-kind label for the devtools chip (e.g. `"http"`). */
|
|
1290
|
+
readonly carrierLabel: string;
|
|
1412
1291
|
}
|
|
1413
1292
|
//#endregion
|
|
1414
|
-
//#region src/ActionDefinition/Domain/helpers/createRootActionDomain.d.ts
|
|
1415
|
-
declare const createActionRootDomain: <ID extends string>(definition: {
|
|
1416
|
-
domain: ID;
|
|
1417
|
-
}) => ActionRootDomain<IActionRootDomain<ID>>;
|
|
1418
|
-
//#endregion
|
|
1419
1293
|
//#region src/ActionRuntime/Transport/codec/actionWireCodec.d.ts
|
|
1420
1294
|
/**
|
|
1421
1295
|
* Shared building blocks for the binary action codecs (the stateless {@link createBinaryWireAdapter} and
|
|
@@ -1441,841 +1315,468 @@ interface IActionWireFormat {
|
|
|
1441
1315
|
incoming?: (input: string | ArrayBuffer | Uint8Array | Blob) => TActionPayload_Any_JsonObject<any, any> | undefined;
|
|
1442
1316
|
}
|
|
1443
1317
|
//#endregion
|
|
1444
|
-
//#region src/ActionRuntime/
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
/**
|
|
1448
|
-
|
|
1449
|
-
/** A connection's restorable identity — what to persist so a binding survives transport eviction. */
|
|
1450
|
-
interface IAcceptorConnectionBinding {
|
|
1451
|
-
/** Full client coordinate, so `originClient` can be re-injected into frames that omit it. */
|
|
1452
|
-
client: IRuntimeCoordinate;
|
|
1453
|
-
encoding: TActionConnectionEncoding;
|
|
1454
|
-
/**
|
|
1455
|
-
* Secure-session state (set once a connection's handshake completes). Persist it alongside the
|
|
1456
|
-
* binding so an authenticated/encrypted connection resumes after eviction without re-handshaking —
|
|
1457
|
-
* the `keyMaterial` lets the server re-derive the shared key from its own persisted identity.
|
|
1458
|
-
*/
|
|
1459
|
-
secure?: {
|
|
1460
|
-
securityLevel: ESecurityLevel;
|
|
1461
|
-
linkedClientId: TTypeAndId;
|
|
1462
|
-
keyMaterial?: IHandshakeEncryptionKeyMaterial;
|
|
1463
|
-
};
|
|
1318
|
+
//#region src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.d.ts
|
|
1319
|
+
type TFormatMessage = IActionWireFormat;
|
|
1320
|
+
interface IBinaryWireSessionOptions {
|
|
1321
|
+
/** Override how long an unresolved correlation is retained before being swept (ms). */
|
|
1322
|
+
correlationTtlMs?: number;
|
|
1464
1323
|
}
|
|
1465
1324
|
/**
|
|
1466
|
-
*
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1325
|
+
* Builds a factory of *stateful, per-connection* codecs for {@link LinkTransport} /
|
|
1326
|
+
* `AcceptorHandler` — the maximally compact binary wire. Call the returned factory once per live
|
|
1327
|
+
* connection (each socket on the client, each accepted connection on the server) so every channel
|
|
1328
|
+
* gets its own correlation + identity state.
|
|
1329
|
+
*
|
|
1330
|
+
* On top of everything {@link createBinaryWireAdapter} drops, a session also drops:
|
|
1331
|
+
* - **`cuid`** — replaced by a per-connection integer correlation id. The initiator maps it to its
|
|
1332
|
+
* real cuid; the responder echoes it; each side reconstructs the cuid from its own map. Correlation
|
|
1333
|
+
* only needs to be unique per socket, so a counter suffices.
|
|
1334
|
+
* - **`originClient` after the first request** — the first request each side sends carries its
|
|
1335
|
+
* identity; the peer remembers it and injects it into later frames. Replies omit it entirely (a
|
|
1336
|
+
* reply carries the initiator's own origin, which the initiator already knows).
|
|
1337
|
+
*
|
|
1338
|
+
* Both ends MUST build the factory from the same domains in the same order (positional dictionary).
|
|
1339
|
+
* Text frames still return `undefined` from `incoming`, so JSON clients remain interoperable.
|
|
1340
|
+
*
|
|
1341
|
+
* Hibernation note: after a server connection is evicted its session resets, so a still-connected
|
|
1342
|
+
* client (whose session persists) will keep omitting `originClient`. The server must therefore restore
|
|
1343
|
+
* the connection→client binding from its own store (see `AcceptorHandler.rehydrateConnection`) and
|
|
1344
|
+
* inject `originClient` from there — the session alone can't recover it.
|
|
1471
1345
|
*/
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1346
|
+
declare function createBinaryWireSessionFactory(domains: ActionDomain<any>[], options?: IBinaryWireSessionOptions): () => TFormatMessage;
|
|
1347
|
+
//#endregion
|
|
1348
|
+
//#region src/ActionRuntime/Channel/ActionChannel.d.ts
|
|
1349
|
+
/**
|
|
1350
|
+
* A transport-agnostic routing contract between two runtimes, declared *by role* rather than by
|
|
1351
|
+
* "client"/"server". The two ends are named for the only asymmetry that survives every carrier (WS,
|
|
1352
|
+
* WebRTC, BLE, raw TCP): which side dials and which side accepts.
|
|
1353
|
+
*
|
|
1354
|
+
* - The **connector** dials out and opens the link ({@link connectChannel}).
|
|
1355
|
+
* - The **acceptor** accepts incoming links and can push back ({@link acceptChannelConnections}).
|
|
1356
|
+
*
|
|
1357
|
+
* `toAcceptor` domains flow connector→acceptor (the classic "request"); `toConnector` domains flow
|
|
1358
|
+
* acceptor→connector (the classic "push"). Both ends derive their routing from the same channel instead
|
|
1359
|
+
* of restating domain lists — and because the contract is independent of how bytes move, the very same
|
|
1360
|
+
* channel can be carried over HTTP, secure WebSockets, or a mix (WS preferred, HTTP fallback).
|
|
1361
|
+
*
|
|
1362
|
+
* Beyond the routing, a channel also carries its *wire identity* — the per-connection binary codec both
|
|
1363
|
+
* ends build from the same domain list, plus the `dictionaryVersion` the handshake checks for drift.
|
|
1364
|
+
* Whether a given transport runs encrypted is a per-transport choice (see {@link IConnectTransport.secure}
|
|
1365
|
+
* and the acceptor's `securityLevel`), not a property of the channel — so one `defineChannel` definition
|
|
1366
|
+
* serves both plain and secure transports.
|
|
1367
|
+
*/
|
|
1368
|
+
interface IActionChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[]> {
|
|
1369
|
+
/**
|
|
1370
|
+
* Domains the connector *sends to the acceptor* (connector→acceptor requests). The connector forwards
|
|
1371
|
+
* them over its transport(s); the acceptor executes them.
|
|
1477
1372
|
*/
|
|
1478
|
-
|
|
1479
|
-
/**
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1373
|
+
toAcceptorDomains: TO_ACCEPTOR;
|
|
1374
|
+
/**
|
|
1375
|
+
* Domains the acceptor *pushes to the connector* (acceptor→connector). The connector registers local
|
|
1376
|
+
* handlers for them ({@link connectChannel}'s `onPush`); the acceptor broadcasts them. Pushes need a
|
|
1377
|
+
* bidirectional transport (e.g. a WebSocket) — over a request-only transport like HTTP they simply
|
|
1378
|
+
* never flow.
|
|
1379
|
+
*/
|
|
1380
|
+
toConnectorDomains: TO_CONNECTOR;
|
|
1381
|
+
/** Wire dictionary version — derived from the domains by default; the handshake rejects a mismatch. */
|
|
1484
1382
|
dictionaryVersion: string;
|
|
1485
|
-
/**
|
|
1486
|
-
|
|
1383
|
+
/** Per-connection session codec factory (call once per live connection). */
|
|
1384
|
+
createCodec: () => IActionWireFormat;
|
|
1487
1385
|
}
|
|
1488
|
-
|
|
1386
|
+
/**
|
|
1387
|
+
* Declare a transport-agnostic channel by role — the single source of truth both peers share. Each end
|
|
1388
|
+
* MUST call this with the same domains in the same order (the binary wire dictionary is positional); the
|
|
1389
|
+
* `dictionaryVersion` is derived from those domains unless you pin an explicit one. The wire dictionary
|
|
1390
|
+
* spans `[...toAcceptor, ...toConnector]` in that order, so add new domains to the end of their list to
|
|
1391
|
+
* keep older peers compatible.
|
|
1392
|
+
*
|
|
1393
|
+
* Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`
|
|
1394
|
+
* (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see
|
|
1395
|
+
* {@link connectChannel} and {@link serveChannel}) instead of being restated at each end. Security is a
|
|
1396
|
+
* per-transport concern, not a channel one, so this same definition is used whether a transport runs
|
|
1397
|
+
* plain or encrypted.
|
|
1398
|
+
*/
|
|
1399
|
+
declare function defineChannel<const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [], const TO_CONNECTOR extends readonly ActionDomain<any>[] = []>(options: {
|
|
1400
|
+
/** Domains the connector sends to the acceptor (connector→acceptor requests), in a stable order. */toAcceptor: TO_ACCEPTOR; /** Domains the acceptor pushes to the connector (acceptor→connector), in a stable order. */
|
|
1401
|
+
toConnector: TO_CONNECTOR; /** Pin a human-readable version instead of the derived hash (must match on both ends). */
|
|
1402
|
+
dictionaryVersion?: string; /** Tuning for the per-connection binary session (e.g. correlation TTL). */
|
|
1403
|
+
sessionOptions?: IBinaryWireSessionOptions;
|
|
1404
|
+
}): IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>;
|
|
1405
|
+
type TUnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
1406
|
+
type TDomainPushHandlers<D> = D extends ActionDomain<infer DEF> ? Partial<TWrappableDomainActionHandler<DEF>> : never;
|
|
1407
|
+
/**
|
|
1408
|
+
* The `onPush` map for a channel: the merged set of every acceptor→connector (`toConnector`) action
|
|
1409
|
+
* handler, each receiving the pushed action's input. Derived from the channel's `toConnectorDomains`, so
|
|
1410
|
+
* the keys and input types follow the channel definition.
|
|
1411
|
+
*/
|
|
1412
|
+
type TChannelPushHandlers<TO_CONNECTOR extends readonly ActionDomain<any>[]> = TUnionToIntersection<TDomainPushHandlers<TO_CONNECTOR[number]>>;
|
|
1413
|
+
/**
|
|
1414
|
+
* One transport to the peer, declared by *carrier* — the dial-out dual of `serveChannel`'s acceptor
|
|
1415
|
+
* carriers. {@link connectChannel} binds the shared facts (channel codec/version, runtime, crypto
|
|
1416
|
+
* identity) into each one, so a descriptor only carries what differs between transports: the carrier and
|
|
1417
|
+
* whether it runs the secure handshake.
|
|
1418
|
+
*
|
|
1419
|
+
* A duplex carrier (`wsCarrier(() => ({ url }))`, `rtcCarrier(dc)`) builds a push-capable link; an exchange carrier
|
|
1420
|
+
* (`httpCarrier(...)`) builds a request/reply transport. List them in preference order — the connection
|
|
1421
|
+
* prefers the first that's ready and falls through on failure (e.g. secure WS preferred, HTTP fallback).
|
|
1422
|
+
*/
|
|
1423
|
+
interface IConnectTransport {
|
|
1424
|
+
/** How to reach the peer — a duplex carrier (push-capable) or an exchange carrier (request/reply). */
|
|
1425
|
+
carrier: IDuplexCarrierSource | IExchangeCarrierSource;
|
|
1489
1426
|
/**
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1492
|
-
*
|
|
1427
|
+
* Run the authenticated/encrypted handshake over this carrier. Defaults to `true`. A secure transport
|
|
1428
|
+
* draws its identity from the connection's shared `link`/`storage`; set `false` for a plain transport
|
|
1429
|
+
* (e.g. a bare HTTP fallback beside a secure WS), which then needs no `storage`.
|
|
1493
1430
|
*/
|
|
1494
|
-
|
|
1495
|
-
/**
|
|
1496
|
-
|
|
1431
|
+
secure?: boolean;
|
|
1432
|
+
/** Security level for this secure transport; defaults to the connection-level `securityLevel`. */
|
|
1433
|
+
securityLevel?: ESecurityLevel;
|
|
1497
1434
|
/**
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1435
|
+
* Optional availability gate — when it returns `false` this transport is skipped and the connection
|
|
1436
|
+
* falls through to the next in preference order, re-evaluated per dispatch. Omit = always available.
|
|
1500
1437
|
*/
|
|
1501
|
-
|
|
1502
|
-
/**
|
|
1503
|
-
|
|
1438
|
+
available?: (input: ITransportRouteActionParams) => boolean;
|
|
1439
|
+
/** Override the devtools chip label (defaults to the carrier's own label). */
|
|
1440
|
+
label?: string;
|
|
1441
|
+
}
|
|
1442
|
+
interface IConnectChannelOptions<TO_CONNECTOR extends readonly ActionDomain<any>[]> {
|
|
1443
|
+
/** The peer's runtime coordinate — the acceptor this connection dials. */
|
|
1444
|
+
peer: RuntimeCoordinate;
|
|
1504
1445
|
/**
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
1508
|
-
*
|
|
1446
|
+
* The transports to the peer, by carrier, in preference order (e.g. secure WS preferred, HTTP fallback).
|
|
1447
|
+
* They all carry the channel's `toAcceptor` domains; the connection prefers the first that's ready and
|
|
1448
|
+
* falls through on failure. {@link connectChannel} binds the channel + runtime + crypto identity into
|
|
1449
|
+
* each — the dial-out dual of `serveChannel`'s `carriers`.
|
|
1509
1450
|
*/
|
|
1510
|
-
|
|
1451
|
+
transports: readonly IConnectTransport[];
|
|
1511
1452
|
/**
|
|
1512
|
-
*
|
|
1513
|
-
*
|
|
1453
|
+
* One backing store for this connection's crypto identity, fanned across every *secure* transport so
|
|
1454
|
+
* they present the same verify/exchange keys. Required when any transport is secure (the default); a
|
|
1455
|
+
* fully-plain connection (every transport `secure: false`) may omit it. Pass `link` instead to share an
|
|
1456
|
+
* existing identity.
|
|
1514
1457
|
*/
|
|
1515
|
-
|
|
1458
|
+
storage?: StorageAdapter;
|
|
1459
|
+
/** The connection's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storage`. */
|
|
1460
|
+
link?: ClientCryptoKeyLink;
|
|
1461
|
+
/** Default security level for secure transports; defaults to `authenticated`. */
|
|
1462
|
+
securityLevel?: ESecurityLevel;
|
|
1463
|
+
/** Handlers for the channel's acceptor→connector pushes. Optional — omit for a send-only connection. */
|
|
1464
|
+
onPush?: TChannelPushHandlers<TO_CONNECTOR>;
|
|
1465
|
+
/** Default per-action timeout for this connection. */
|
|
1466
|
+
defaultTimeout?: number;
|
|
1516
1467
|
}
|
|
1517
1468
|
/**
|
|
1518
|
-
*
|
|
1519
|
-
*
|
|
1520
|
-
*
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
1469
|
+
* Open a connection to a peer from a single call — the dial-out dual of `serveChannel`. The channel is
|
|
1470
|
+
* the single source of truth for *what* is routed (`toAcceptor` domains forwarded to the peer,
|
|
1471
|
+
* `toConnector` pushes handled locally from `onPush`); the call binds the shared facts — the channel's
|
|
1472
|
+
* codec/dictionary version, the runtime, and one crypto identity (a {@link ClientCryptoKeyLink} over
|
|
1473
|
+
* `storage`) — into every transport in `transports`, so none of them restate the channel or runtime.
|
|
1474
|
+
* List several transports to make the path transport-agnostic (secure WS preferred, HTTP fallback):
|
|
1475
|
+
* ```ts
|
|
1476
|
+
* const handler = connectChannel(runtime, lobbyChannel, {
|
|
1477
|
+
* peer: runtime_coordinate_lobby_do,
|
|
1478
|
+
* storage,
|
|
1479
|
+
* transports: [{ carrier: wsCarrier(() => ({ url })) }, { carrier: httpCarrier(...), secure: false }],
|
|
1480
|
+
* onPush: { player_joined: (p) => { … } },
|
|
1481
|
+
* });
|
|
1482
|
+
* ```
|
|
1483
|
+
* Returns the {@link ConnectorHandler} so the caller can later `clearTransportCache()` it.
|
|
1523
1484
|
*/
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
createFormatMessage?: never;
|
|
1527
|
-
} | {
|
|
1528
|
-
createFormatMessage: () => TActionChannelFormatMessage;
|
|
1529
|
-
formatMessage?: never;
|
|
1530
|
-
});
|
|
1485
|
+
declare function connectChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[]>(runtime: ActionRuntime, channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>, options: IConnectChannelOptions<TO_CONNECTOR>): ConnectorHandler;
|
|
1486
|
+
type TDomainAcceptorCases<D, TCtx> = D extends ActionDomain<infer DEF> ? { [ID in keyof DEF["actionSchema"] & string]?: TAcceptorCaseFn<DEF, ID, TCtx> } : never;
|
|
1531
1487
|
/**
|
|
1532
|
-
*
|
|
1533
|
-
* the primed request plus a per-
|
|
1534
|
-
* the
|
|
1535
|
-
*
|
|
1536
|
-
*
|
|
1537
|
-
*
|
|
1488
|
+
* The connection-aware case map for a channel's acceptor side: the merged set of every
|
|
1489
|
+
* connector→acceptor (`toAcceptor`) action handler, each receiving the primed request plus a per-action
|
|
1490
|
+
* `context`. `TCtx` is whatever the wiring supplies as that second argument — the raw connection
|
|
1491
|
+
* (`TConn | undefined`) for the low-level `acceptChannelConnections`, or an enriched `IConnectionContext`
|
|
1492
|
+
* for `serveChannel`'s `channelCases`. Derived from the channel's `toAcceptorDomains`, so the keys and
|
|
1493
|
+
* input/output types follow the channel.
|
|
1538
1494
|
*/
|
|
1539
|
-
type
|
|
1495
|
+
type TChannelAcceptorCases<TO_ACCEPTOR extends readonly ActionDomain<any>[], TCtx> = TUnionToIntersection<TDomainAcceptorCases<TO_ACCEPTOR[number], TCtx>>;
|
|
1540
1496
|
/**
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
* {@link AcceptorHandler.forConnectionDomainCases}
|
|
1497
|
+
* Register an acceptor handler's execution for a channel straight from its definition: the channel's
|
|
1498
|
+
* `toAcceptor` domains are served together with one merged, connection-aware case map (each case gets
|
|
1499
|
+
* the primed request + the originating connection, as with
|
|
1500
|
+
* {@link AcceptorHandler.forConnectionDomainCases}). The domain list is taken from the channel,
|
|
1501
|
+
* never restated. Add the returned handler to the runtime alongside the acceptor handler:
|
|
1502
|
+
* ```ts
|
|
1503
|
+
* runtime.addHandlers([acceptChannelConnections(serverHandler, channel, { … }), serverHandler]);
|
|
1504
|
+
* ```
|
|
1505
|
+
*
|
|
1506
|
+
* The case's second argument is the raw connection (`TConn | undefined`). For the richer state +
|
|
1507
|
+
* broadcast + pushBack context, serve the channel through `serveChannel`'s `channelCases` instead.
|
|
1545
1508
|
*/
|
|
1546
|
-
|
|
1509
|
+
declare function acceptChannelConnections<TO_ACCEPTOR extends readonly ActionDomain<any>[], TConn>(serverHandler: AcceptorHandler<TConn>, channel: IActionChannel<TO_ACCEPTOR, any>, cases: TChannelAcceptorCases<TO_ACCEPTOR, TConn | undefined>): ActionLocalHandler;
|
|
1547
1510
|
/**
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1511
|
+
* {@link acceptChannel}'s options — the secure-acceptor builder options minus the `channel` and `runtime`
|
|
1512
|
+
* it already takes positionally. One option bag, shared with the underlying {@link createSecureAcceptorHandler}.
|
|
1513
|
+
*/
|
|
1514
|
+
type IAcceptChannelOptions<TConn> = Omit<ISecureAcceptorHandlerOptions<TConn>, "channel" | "runtime">;
|
|
1515
|
+
/**
|
|
1516
|
+
* Build the secure {@link AcceptorHandler} for a channel — the accept-in counterpart to
|
|
1517
|
+
* {@link connectChannel}. It folds in the boilerplate of {@link createSecureAcceptorHandler} (the
|
|
1518
|
+
* `ClientCryptoKeyLink` + storage-backed TOFU resolver from one `storage`, the channel's codec +
|
|
1519
|
+
* dictionary version, the `security` block from the runtime coordinate) but takes the `(runtime, channel,
|
|
1520
|
+
* options)` shape of the channel family. Pair it with {@link acceptChannelConnections} for execution:
|
|
1553
1521
|
* ```ts
|
|
1554
|
-
* const
|
|
1555
|
-
* runtime.addHandlers([
|
|
1556
|
-
* // per inbound message (e.g. a Durable Object's webSocketMessage):
|
|
1557
|
-
* serverHandler.receive(ws, message);
|
|
1522
|
+
* const acceptor = acceptChannel(runtime, gameChannel, { clientEnv, storage, send });
|
|
1523
|
+
* runtime.addHandlers([acceptChannelConnections(acceptor, gameChannel, { … }), acceptor]);
|
|
1558
1524
|
* ```
|
|
1559
|
-
*
|
|
1560
|
-
* Inbound requests route to your local handler; the runtime's return dispatch then calls this
|
|
1561
|
-
* handler back (it is an external handler keyed to `clientEnv`) to send the result to the originating
|
|
1562
|
-
* connection. The handler keeps a per-connection identity registry so each result lands on the right
|
|
1563
|
-
* socket, and remembers each connection's encoding so binary and JSON clients can share the channel.
|
|
1564
|
-
*
|
|
1565
|
-
* It registers an empty action router, so it is never chosen to *execute* an inbound request — only
|
|
1566
|
-
* to ferry results/pushes back out.
|
|
1567
1525
|
*/
|
|
1568
|
-
declare
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1526
|
+
declare function acceptChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn = unknown>(runtime: ActionRuntime, channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>, options: IAcceptChannelOptions<TConn>): AcceptorHandler<TConn>;
|
|
1527
|
+
//#endregion
|
|
1528
|
+
//#region src/ActionRuntime/ActionRuntime.types.d.ts
|
|
1529
|
+
interface IRuntimeMeta {
|
|
1530
|
+
assumed: boolean;
|
|
1531
|
+
runtimeName: RuntimeName;
|
|
1532
|
+
}
|
|
1533
|
+
interface IActionRuntimeManagerContext {
|
|
1534
|
+
domain?: string;
|
|
1535
|
+
}
|
|
1536
|
+
type TActionRuntimeHandler = ActionLocalHandler | PeerLinkHandler;
|
|
1537
|
+
//#endregion
|
|
1538
|
+
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/ConnectionStateStore.d.ts
|
|
1539
|
+
/**
|
|
1540
|
+
* The composite value persisted to a connection's attachment: the consumer's own app state plus the
|
|
1541
|
+
* {@link AcceptorHandler} routing binding. Co-storing them in one slot means a transport whose
|
|
1542
|
+
* sockets outlive process eviction (e.g. a Durable Object's hibernatable WebSocket) recovers both the
|
|
1543
|
+
* application identity *and* the action routing from a single attachment after a wake — no storage reads.
|
|
1544
|
+
*/
|
|
1545
|
+
interface IConnectionAttachment<TApp> {
|
|
1546
|
+
app?: TApp;
|
|
1547
|
+
binding?: IAcceptorConnectionBinding;
|
|
1548
|
+
}
|
|
1549
|
+
interface IConnectionStateStoreOptions<TConn, TApp> {
|
|
1550
|
+
/** Read a connection's raw attachment (e.g. `(ws) => ws.deserializeAttachment()`). */
|
|
1551
|
+
read: (connection: TConn) => unknown;
|
|
1552
|
+
/** Persist a connection's attachment (e.g. `(ws, value) => ws.serializeAttachment(value)`). */
|
|
1553
|
+
write: (connection: TConn, value: IConnectionAttachment<TApp>) => void;
|
|
1588
1554
|
/**
|
|
1589
|
-
*
|
|
1590
|
-
*
|
|
1555
|
+
* All currently-live connections (e.g. `() => ctx.getWebSockets()`). Used to replay routing bindings
|
|
1556
|
+
* after a wake (via {@link createConnectionStateStore}) and to enumerate app state in
|
|
1557
|
+
* {@link ConnectionStateStore.entries}.
|
|
1591
1558
|
*/
|
|
1592
|
-
|
|
1559
|
+
getConnections: () => TConn[];
|
|
1593
1560
|
/**
|
|
1594
|
-
*
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1597
|
-
*/
|
|
1598
|
-
setOnConnectionBound(onConnectionBound: (connection: TConn, binding: IAcceptorConnectionBinding) => void): void;
|
|
1599
|
-
/**
|
|
1600
|
-
* Feed one inbound frame from a connection into the runtime. Decodes text or binary, binds the
|
|
1601
|
-
* connection to the requesting client's identity, then routes it (requests execute locally;
|
|
1602
|
-
* results/progress resolve pending server-initiated actions).
|
|
1603
|
-
*/
|
|
1604
|
-
receive(connection: TConn, frame: string | ArrayBuffer | Uint8Array): void;
|
|
1605
|
-
private _receivePlain;
|
|
1606
|
-
/**
|
|
1607
|
-
* The secure session for a connection (built lazily on its first secure-mode frame), with the
|
|
1608
|
-
* handler-owned effects — raw send, identity binding + persistence, and inbound routing — wired in as
|
|
1609
|
-
* callbacks. The session owns all crypto/handshake/chain state; the handler keeps only the registry.
|
|
1610
|
-
*/
|
|
1611
|
-
private _sessionFor;
|
|
1612
|
-
/** Bind + persist a connection's authenticated identity once its handshake completes. */
|
|
1613
|
-
private _onConnectionAuthenticated;
|
|
1614
|
-
/** Decode a decrypted authenticated frame, inject the *authenticated* identity, and route it. */
|
|
1615
|
-
private _routeAuthedActionBytes;
|
|
1616
|
-
/**
|
|
1617
|
-
* Ensure an inbound request carries the client's identity and that this connection is bound to it,
|
|
1618
|
-
* so its result can be routed back. A session codec omits `originClient` after the first request, so
|
|
1619
|
-
* when it's missing we restore it from the (possibly rehydrated) binding instead. (Plain mode only;
|
|
1620
|
-
* secure mode binds the authenticated coordinate at handshake time.)
|
|
1621
|
-
*/
|
|
1622
|
-
private _resolveRequestIdentity;
|
|
1623
|
-
/**
|
|
1624
|
-
* Restore a connection→client binding without an inbound frame — for transports that resume after
|
|
1625
|
-
* eviction. Pair it with the {@link IAcceptorHandlerOptions.onConnectionBound} hook: persist
|
|
1626
|
-
* the binding there, then replay each live connection here when the channel comes back (e.g. a
|
|
1627
|
-
* Durable Object iterating `ctx.getWebSockets()` as it wakes from hibernation).
|
|
1628
|
-
*/
|
|
1629
|
-
rehydrateConnection(connection: TConn, binding: IAcceptorConnectionBinding): void;
|
|
1630
|
-
toJsonObject(): IActionHandler_Peer_Json;
|
|
1631
|
-
toHandlerRouteItem(): IActionRouteItemHandler;
|
|
1632
|
-
/** Forget a connection (call on socket close) so stale entries don't misroute later results. */
|
|
1633
|
-
dropConnection(connection: TConn): void;
|
|
1634
|
-
/** Live connection for a client coordinate, if currently registered. */
|
|
1635
|
-
getConnectionForClient(client: RuntimeCoordinate): TConn | undefined;
|
|
1636
|
-
/** This acceptor owns the origin's return path when it currently holds a live connection bound to it. */
|
|
1637
|
-
ownsLiveConnectionFor(origin: RuntimeCoordinate): boolean;
|
|
1638
|
-
/** Whether this acceptor currently tracks `connection` — used to pick the owning handler among several. */
|
|
1639
|
-
hasConnection(connection: TConn): boolean;
|
|
1640
|
-
/**
|
|
1641
|
-
* Send (and optionally await) a server-initiated action to a specific connected client. Pass the
|
|
1642
|
-
* connection token directly (e.g. the `ws`) or a client `RuntimeCoordinate` to look one up.
|
|
1643
|
-
*/
|
|
1644
|
-
pushToClient<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(runtime: ActionRuntime, target: TConn | RuntimeCoordinate, request: ActionPayload_Request<DOM, ID>, options?: {
|
|
1645
|
-
timeout?: number;
|
|
1646
|
-
}): RunningAction<DOM, ID>;
|
|
1647
|
-
/**
|
|
1648
|
-
* Build a local handler whose cases are connection-aware: each case receives the primed request and
|
|
1649
|
-
* the originating client's live connection (resolved from `originClient`), so handlers don't repeat
|
|
1650
|
-
* the `getConnectionForClient(action.context.originClient)` lookup. Cases may return raw output or
|
|
1651
|
-
* nothing, just like {@link ActionLocalHandler.forDomainActionCases}. Add the returned handler to the
|
|
1652
|
-
* runtime alongside this server handler:
|
|
1653
|
-
* ```ts
|
|
1654
|
-
* runtime.addHandlers([serverHandler.forConnectionDomainCases(domain, { … }), serverHandler]);
|
|
1655
|
-
* ```
|
|
1656
|
-
*/
|
|
1657
|
-
forConnectionDomainCases<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>, cases: { [ID in keyof FOR_DOM["actionSchema"] & string]?: TAcceptorConnectionCaseFn<FOR_DOM, ID, TConn> }): ActionLocalHandler;
|
|
1658
|
-
/**
|
|
1659
|
-
* Like {@link forConnectionDomainCases} but spanning several domains with one merged case map — used
|
|
1660
|
-
* by channel-derived wiring (`acceptChannelConnections` / `serveChannel`) where the channel's
|
|
1661
|
-
* `toAcceptor` domains are served together. Each domain takes only the cases whose ids it owns, so a
|
|
1662
|
-
* single map can cover several domains and unrelated ids are ignored.
|
|
1663
|
-
*
|
|
1664
|
-
* `mapContext` turns the resolved connection into whatever the case's second argument should be: the
|
|
1665
|
-
* raw connection for the low-level helper, or an enriched `IConnectionContext` for `serveChannel`. It's
|
|
1666
|
-
* called once per inbound action, after the originating connection is resolved.
|
|
1667
|
-
*/
|
|
1668
|
-
forConnectionDomainCasesMulti<TCtx>(domains: readonly ActionDomain<any>[], cases: Record<string, TAcceptorCaseFn<any, any, TCtx> | undefined>, mapContext: (connection: TConn | undefined, request: ActionPayload_Request<any, any>) => TCtx): ActionLocalHandler;
|
|
1669
|
-
/**
|
|
1670
|
-
* Fan a server-initiated request out to every currently-bound connection. A fresh request is built
|
|
1671
|
-
* per connection (each push mutates its own action context) and dispatched fire-and-forget. Pass
|
|
1672
|
-
* `except` to skip the originating socket and `where` to filter by connection (e.g. read its
|
|
1673
|
-
* attachment for a role). Iterating bound connections (rather than every accepted socket) skips
|
|
1674
|
-
* sockets that are still mid-handshake and so can't yet receive a frame.
|
|
1561
|
+
* Optional Standard Schema (valibot, zod, …) validating the *app* portion on read. A value that
|
|
1562
|
+
* fails validation reads back as `null` — the same lenient behavior as a hand-written safeParse
|
|
1563
|
+
* helper. The binding is the library's own shape and is never validated.
|
|
1675
1564
|
*/
|
|
1676
|
-
|
|
1677
|
-
runtime?: ActionRuntime;
|
|
1678
|
-
except?: TConn | null;
|
|
1679
|
-
where?: (connection: TConn) => boolean;
|
|
1680
|
-
timeout?: number;
|
|
1681
|
-
onError?: (error: unknown, connection: TConn) => void;
|
|
1682
|
-
}): void;
|
|
1683
|
-
sendReturnPayload(payload: TActionPayload_Any_Instance<any, any>, config: {
|
|
1684
|
-
targetLocalRuntime: ActionRuntime;
|
|
1685
|
-
}): Promise<boolean>;
|
|
1686
|
-
handleActionRequest<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions): Promise<RunningAction<DOM, ID>>;
|
|
1687
|
-
private _dispatch;
|
|
1688
|
-
private _sendPayload;
|
|
1689
|
-
private _bindConnection;
|
|
1690
|
-
private _resolveConnection;
|
|
1691
|
-
private _resolveSingleConnection;
|
|
1565
|
+
schema?: StandardSchemaV1<unknown, TApp>;
|
|
1692
1566
|
}
|
|
1693
|
-
declare const createAcceptorHandler: <TConn = unknown>(options: IAcceptorHandlerOptions<TConn>) => AcceptorHandler<TConn>;
|
|
1694
|
-
//#endregion
|
|
1695
|
-
//#region src/ActionRuntime/Transport/Carrier/Carrier.types.d.ts
|
|
1696
1567
|
/**
|
|
1697
|
-
*
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1568
|
+
* A typed per-connection state store that co-owns the app state and the acceptor handler's routing
|
|
1569
|
+
* binding in one attachment, so neither the consumer nor the handler has to hand-merge the two. Create
|
|
1570
|
+
* it through {@link createConnectionStateStore} (which also wires binding persistence and replays
|
|
1571
|
+
* surviving connections after a wake), then `get`/`set`/`clearApp` the app state directly.
|
|
1700
1572
|
*
|
|
1701
|
-
*
|
|
1702
|
-
*
|
|
1703
|
-
*
|
|
1704
|
-
* - {@link IExchangeCarrier} — a request → single-correlated-reply carrier with no unsolicited push
|
|
1705
|
-
* (HTTP, and anything request/response-shaped). The reply rides the response to its own request.
|
|
1573
|
+
* The mechanism is carrier-neutral — it only needs read/write/enumerate callbacks for the connection's
|
|
1574
|
+
* attachment — but it pays off on transports whose connections outlive process eviction (e.g. a
|
|
1575
|
+
* Durable Object's hibernatable WebSockets), which is why it lives beside the hibernation adapter.
|
|
1706
1576
|
*
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
*
|
|
1713
|
-
*
|
|
1714
|
-
*
|
|
1577
|
+
* ```ts
|
|
1578
|
+
* const players = createConnectionStateStore(serverHandler, {
|
|
1579
|
+
* schema: vs_player,
|
|
1580
|
+
* read: (ws) => ws.deserializeAttachment(),
|
|
1581
|
+
* write: (ws, v) => ws.serializeAttachment(v),
|
|
1582
|
+
* getConnections: () => ctx.getWebSockets(),
|
|
1583
|
+
* });
|
|
1584
|
+
* players.set(ws, player); // binding is preserved automatically
|
|
1585
|
+
* const player = players.get(ws);
|
|
1586
|
+
* ```
|
|
1715
1587
|
*/
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
/**
|
|
1720
|
-
|
|
1721
|
-
/**
|
|
1722
|
-
|
|
1723
|
-
/**
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
close(): void;
|
|
1734
|
-
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1735
|
-
readonly label?: string;
|
|
1588
|
+
declare class ConnectionStateStore<TConn, TApp> {
|
|
1589
|
+
private readonly options;
|
|
1590
|
+
constructor(options: IConnectionStateStoreOptions<TConn, TApp>);
|
|
1591
|
+
/** The validated app state for a connection, or `null` if unset / invalid. */
|
|
1592
|
+
get(connection: TConn): TApp | null;
|
|
1593
|
+
/** Set the app state, preserving the runtime binding already pinned to the connection. */
|
|
1594
|
+
set(connection: TConn, app: TApp): void;
|
|
1595
|
+
/** Clear the app state but keep the binding (e.g. a spectator that stopped watching). */
|
|
1596
|
+
clearApp(connection: TConn): void;
|
|
1597
|
+
/** Every live connection paired with its (validated) app state — for rebuilding in-memory state after a wake. */
|
|
1598
|
+
entries(): [TConn, TApp | null][];
|
|
1599
|
+
/** @internal Persist a freshly-bound connection's binding, preserving any app state already stored. */
|
|
1600
|
+
_persistBinding(connection: TConn, binding: IAcceptorConnectionBinding): void;
|
|
1601
|
+
/** @internal The persisted binding for a connection, if any (used to replay routing after a wake). */
|
|
1602
|
+
_readBinding(connection: TConn): IAcceptorConnectionBinding | undefined;
|
|
1603
|
+
private _readAttachment;
|
|
1604
|
+
private _validateApp;
|
|
1736
1605
|
}
|
|
1737
1606
|
/**
|
|
1738
|
-
*
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1607
|
+
* Build a per-connection {@link ConnectionStateStore} bound to an {@link AcceptorHandler}: it registers
|
|
1608
|
+
* itself as the handler's connection-bound persistence callback (so bindings are written without
|
|
1609
|
+
* overwriting app state) and immediately replays every live connection's stored binding via
|
|
1610
|
+
* {@link AcceptorHandler.rehydrateConnection} — so on a transport that resumes after eviction (e.g. a
|
|
1611
|
+
* Durable Object waking from hibernation) both the app identity and the action routing come back from a
|
|
1612
|
+
* single attachment, with no storage reads and no hand-rolled merge.
|
|
1613
|
+
*
|
|
1614
|
+
* Lives outside the handler so the generic {@link AcceptorHandler} stays free of any attachment/
|
|
1615
|
+
* hibernation concern — it exposes only the neutral `setOnConnectionBound` + `rehydrateConnection`
|
|
1616
|
+
* hooks this builder drives.
|
|
1741
1617
|
*/
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1618
|
+
declare function createConnectionStateStore<TConn, TApp>(handler: AcceptorHandler<TConn>, options: IConnectionStateStoreOptions<TConn, TApp>): ConnectionStateStore<TConn, TApp>;
|
|
1619
|
+
//#endregion
|
|
1620
|
+
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/createHibernatableWsServerAdapter.d.ts
|
|
1621
|
+
interface IHibernatableWsServerAdapterOptions<TConn> {
|
|
1622
|
+
/** The handler to drive (from `createSecureAcceptorHandler` or `createAcceptorHandler`). */
|
|
1623
|
+
handler: AcceptorHandler<TConn>;
|
|
1624
|
+
/** All currently-live connections — replayed on construction to rebuild bindings after a wake. */
|
|
1625
|
+
getConnections: () => TConn[];
|
|
1626
|
+
/** Read a connection's persisted binding (e.g. `(ws) => ws.deserializeAttachment()`). */
|
|
1627
|
+
getAttachment: (connection: TConn) => IAcceptorConnectionBinding | undefined;
|
|
1628
|
+
/** Persist a connection's binding when it is bound (e.g. `(ws, b) => ws.serializeAttachment(b)`). */
|
|
1629
|
+
setAttachment: (connection: TConn, binding: IAcceptorConnectionBinding) => void;
|
|
1749
1630
|
}
|
|
1750
|
-
type TCarrier = IDuplexCarrier | IExchangeCarrier;
|
|
1751
1631
|
/**
|
|
1752
|
-
*
|
|
1753
|
-
*
|
|
1754
|
-
*
|
|
1755
|
-
* else.
|
|
1632
|
+
* The neutral lifecycle surface for a duplex (push-capable) acceptor: feed it each inbound frame and tell
|
|
1633
|
+
* it when a connection goes away. Carrier-agnostic — a WebSocket, a WebRTC data channel, or any other
|
|
1634
|
+
* duplex connection drives the same two methods.
|
|
1756
1635
|
*/
|
|
1757
|
-
interface
|
|
1758
|
-
/**
|
|
1759
|
-
|
|
1760
|
-
/**
|
|
1761
|
-
|
|
1762
|
-
/** Devtools route info for an action routed over this carrier. */
|
|
1763
|
-
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
1764
|
-
/** Short carrier-kind label for the devtools chip (e.g. `"ws"`, `"webrtc"`, `"memory"`). */
|
|
1765
|
-
readonly carrierLabel: string;
|
|
1636
|
+
interface IDuplexConnectionRouter<TConn> {
|
|
1637
|
+
/** Feed one inbound frame from a connection into the handler. */
|
|
1638
|
+
receive: (connection: TConn, frame: string | ArrayBuffer | Uint8Array) => void;
|
|
1639
|
+
/** Forget a connection (call on socket close/error). */
|
|
1640
|
+
drop: (connection: TConn) => void;
|
|
1766
1641
|
}
|
|
1767
1642
|
/**
|
|
1768
|
-
*
|
|
1769
|
-
*
|
|
1770
|
-
* `
|
|
1771
|
-
*
|
|
1643
|
+
* Wire the hibernation lifecycle for an acceptor handler on a transport whose connections outlive process
|
|
1644
|
+
* eviction (e.g. a Durable Object's hibernatable WebSockets). It owns persistence end to end:
|
|
1645
|
+
* registers `setAttachment` as the handler's connection-bound callback and immediately replays every
|
|
1646
|
+
* live connection's stored binding via `getAttachment`, so results/pushes still route after a wake.
|
|
1647
|
+
*
|
|
1648
|
+
* Layered on top of the generic {@link AcceptorHandler} — it touches only the handler's neutral
|
|
1649
|
+
* `setOnConnectionBound` / `rehydrateConnection` / `receive` / `dropConnection` surface, so no
|
|
1650
|
+
* hibernation concern leaks into the handler itself.
|
|
1651
|
+
*
|
|
1652
|
+
* Construct it once when the handler is built, then forward connection events:
|
|
1653
|
+
* ```ts
|
|
1654
|
+
* const duplex = createHibernatableWsServerAdapter({ handler, getConnections, getAttachment, setAttachment });
|
|
1655
|
+
* // webSocketMessage(ws, msg) => duplex.receive(ws, msg);
|
|
1656
|
+
* // webSocketClose/Error(ws) => duplex.drop(ws);
|
|
1657
|
+
* ```
|
|
1772
1658
|
*/
|
|
1773
|
-
|
|
1774
|
-
/** Discriminant so a generic factory can tell an exchange source from a duplex one. */
|
|
1775
|
-
readonly shape: "exchange";
|
|
1776
|
-
/** Open (or reuse) the carrier for an action. */
|
|
1777
|
-
open: (input: ITransportRouteActionParams) => IExchangeCarrier;
|
|
1778
|
-
/** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */
|
|
1779
|
-
getCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
1780
|
-
/** Devtools route info for an action routed over this carrier. */
|
|
1781
|
-
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
1782
|
-
/** Short carrier-kind label for the devtools chip (e.g. `"http"`). */
|
|
1783
|
-
readonly carrierLabel: string;
|
|
1784
|
-
}
|
|
1659
|
+
declare function createHibernatableWsServerAdapter<TConn>(options: IHibernatableWsServerAdapterOptions<TConn>): IDuplexConnectionRouter<TConn>;
|
|
1785
1660
|
//#endregion
|
|
1786
|
-
//#region src/ActionRuntime/Transport/
|
|
1787
|
-
type TFormatMessage = IActionWireFormat;
|
|
1788
|
-
interface IBinaryWireSessionOptions {
|
|
1789
|
-
/** Override how long an unresolved correlation is retained before being swept (ms). */
|
|
1790
|
-
correlationTtlMs?: number;
|
|
1791
|
-
}
|
|
1661
|
+
//#region src/ActionRuntime/Transport/Carrier/AcceptorCarrier.types.d.ts
|
|
1792
1662
|
/**
|
|
1793
|
-
*
|
|
1794
|
-
*
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
* - **`cuid`** — replaced by a per-connection integer correlation id. The initiator maps it to its
|
|
1800
|
-
* real cuid; the responder echoes it; each side reconstructs the cuid from its own map. Correlation
|
|
1801
|
-
* only needs to be unique per socket, so a counter suffices.
|
|
1802
|
-
* - **`originClient` after the first request** — the first request each side sends carries its
|
|
1803
|
-
* identity; the peer remembers it and injects it into later frames. Replies omit it entirely (a
|
|
1804
|
-
* reply carries the initiator's own origin, which the initiator already knows).
|
|
1805
|
-
*
|
|
1806
|
-
* Both ends MUST build the factory from the same domains in the same order (positional dictionary).
|
|
1807
|
-
* Text frames still return `undefined` from `incoming`, so JSON clients remain interoperable.
|
|
1663
|
+
* Acceptor-side carrier descriptors — the accept-in dual of the connector's {@link IDuplexCarrierSource}
|
|
1664
|
+
* / {@link IExchangeCarrierSource}. Where a connector source knows how to *open* a carrier to a peer, an
|
|
1665
|
+
* acceptor carrier knows how to *serve* one peer's traffic on this server. Both shapes are carrier-neutral
|
|
1666
|
+
* about security: `serveChannel` builds the crypto identity (link + TOFU resolver) and the security block
|
|
1667
|
+
* once from `(runtime, channel)` and fans it across every carrier, so a carrier descriptor never restates
|
|
1668
|
+
* it.
|
|
1808
1669
|
*
|
|
1809
|
-
*
|
|
1810
|
-
* client (whose session persists) will keep omitting `originClient`. The server must therefore restore
|
|
1811
|
-
* the connection→client binding from its own store (see `AcceptorHandler.rehydrateConnection`) and
|
|
1812
|
-
* inject `originClient` from there — the session alone can't recover it.
|
|
1813
|
-
*/
|
|
1814
|
-
declare function createBinaryWireSessionFactory(domains: ActionDomain<any>[], options?: IBinaryWireSessionOptions): () => TFormatMessage;
|
|
1815
|
-
//#endregion
|
|
1816
|
-
//#region src/ActionRuntime/Channel/secureChannel.d.ts
|
|
1817
|
-
/** The per-connection binary session codec — built once per socket from the channel's domains. */
|
|
1818
|
-
type TChannelCodec = IActionWireFormat;
|
|
1819
|
-
/**
|
|
1820
|
-
* The shared identity of a secure channel (carrier-agnostic — WS, WebRTC, HTTP, …): the wire
|
|
1821
|
-
* dictionary version both ends check during the handshake, plus the per-connection codec factory both
|
|
1822
|
-
* ends build from the *same* domain list. Define it once (typically in code shared by both peers) and
|
|
1823
|
-
* hand it to `secureTransport` on the connector and `serveChannel` (or the lower-level `acceptChannel` /
|
|
1824
|
-
* `createSecureAcceptorHandler`) on the acceptor, so the codec and version can never drift apart.
|
|
1825
|
-
*/
|
|
1826
|
-
interface ISecureChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[]> extends IActionChannel<TO_ACCEPTOR, TO_CONNECTOR> {
|
|
1827
|
-
/** Wire dictionary version — derived from the domains by default; the handshake rejects a mismatch. */
|
|
1828
|
-
dictionaryVersion: string;
|
|
1829
|
-
/** Per-connection session codec factory (call once per live connection). */
|
|
1830
|
-
createCodec: () => TChannelCodec;
|
|
1831
|
-
}
|
|
1832
|
-
/**
|
|
1833
|
-
* Bundle a secure channel's shared identity from its transported domains. Both ends MUST call this
|
|
1834
|
-
* with the same domains in the same order (the binary wire dictionary is positional). The
|
|
1835
|
-
* `dictionaryVersion` is derived from those domains unless you pin an explicit one.
|
|
1670
|
+
* Two shapes mirror the connector side:
|
|
1836
1671
|
*
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1839
|
-
*
|
|
1840
|
-
*
|
|
1841
|
-
*
|
|
1842
|
-
*
|
|
1672
|
+
* - {@link IDuplexAcceptorCarrier} — a persistent, push-capable byte stream (WebSocket, WebRTC, …). It can
|
|
1673
|
+
* push acceptor→connector, so it carries the return path and broadcasts, and it may need an upgrade step
|
|
1674
|
+
* (e.g. a Durable Object's `WebSocketPair`) and optional hibernation persistence.
|
|
1675
|
+
* - {@link IExchangeAcceptorCarrier} — a request → single-correlated-reply carrier with no unsolicited push
|
|
1676
|
+
* (HTTP). The reply rides the response to its own request; there is nothing to push and nothing to
|
|
1677
|
+
* upgrade.
|
|
1843
1678
|
*/
|
|
1844
|
-
declare function defineSecureChannel<const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [], const TO_CONNECTOR extends readonly ActionDomain<any>[] = []>(options: {
|
|
1845
|
-
/** Domains the connector sends to the acceptor (connector→acceptor requests), in a stable order. */toAcceptor: TO_ACCEPTOR; /** Domains the acceptor pushes to the connector (acceptor→connector), in a stable order. */
|
|
1846
|
-
toConnector: TO_CONNECTOR; /** Pin a human-readable version instead of the derived hash (must match on both ends). */
|
|
1847
|
-
dictionaryVersion?: string; /** Tuning for the per-connection binary session (e.g. correlation TTL). */
|
|
1848
|
-
sessionOptions?: IBinaryWireSessionOptions;
|
|
1849
|
-
}): ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR>;
|
|
1850
|
-
//#endregion
|
|
1851
|
-
//#region src/ActionRuntime/Channel/ActionChannel.d.ts
|
|
1852
1679
|
/**
|
|
1853
|
-
*
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
1857
|
-
* - The **connector** dials out and opens the link ({@link connectChannel}).
|
|
1858
|
-
* - The **acceptor** accepts incoming links and can push back ({@link acceptChannelConnections}).
|
|
1859
|
-
*
|
|
1860
|
-
* `toAcceptor` domains flow connector→acceptor (the classic "request"); `toConnector` domains flow
|
|
1861
|
-
* acceptor→connector (the classic "push"). Both ends derive their routing from the same channel instead
|
|
1862
|
-
* of restating domain lists — and because the contract is independent of how bytes move, the very same
|
|
1863
|
-
* channel can be carried over HTTP, secure WebSockets, or a mix (WS preferred, HTTP fallback).
|
|
1680
|
+
* Raw read/write access to a connection's persisted attachment, for a duplex carrier whose connections
|
|
1681
|
+
* outlive process eviction (e.g. a Durable Object's hibernatable WebSockets). Optional — omit for a
|
|
1682
|
+
* transport that never hibernates (per-connection state is then in-memory only).
|
|
1864
1683
|
*
|
|
1865
|
-
*
|
|
1866
|
-
* `
|
|
1867
|
-
*
|
|
1684
|
+
* `serveChannel` owns the attachment *layout*: it co-stores the routing binding and (when
|
|
1685
|
+
* `connectionState` is requested) per-connection app state as one composite in this single slot, so both
|
|
1686
|
+
* survive a wake. The carrier only has to say how to read/write the slot and enumerate live connections.
|
|
1868
1687
|
*/
|
|
1869
|
-
interface
|
|
1870
|
-
/**
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
* Domains the acceptor *pushes to the connector* (acceptor→connector). The connector registers local
|
|
1877
|
-
* handlers for them ({@link connectChannel}'s `onPush`); the acceptor broadcasts them. Pushes need a
|
|
1878
|
-
* bidirectional transport (e.g. a WebSocket) — over a request-only transport like HTTP they simply
|
|
1879
|
-
* never flow.
|
|
1880
|
-
*/
|
|
1881
|
-
toConnectorDomains: TO_CONNECTOR;
|
|
1688
|
+
interface IAcceptorAttachmentStore<TConn> {
|
|
1689
|
+
/** All currently-live connections — enumerated on build to replay binding + app state after a wake. */
|
|
1690
|
+
getConnections: () => TConn[];
|
|
1691
|
+
/** Read a connection's persisted attachment (e.g. `(ws) => ws.deserializeAttachment()`). */
|
|
1692
|
+
read: (connection: TConn) => unknown;
|
|
1693
|
+
/** Persist a connection's attachment (e.g. `(ws, value) => ws.serializeAttachment(value)`). */
|
|
1694
|
+
write: (connection: TConn, value: unknown) => void;
|
|
1882
1695
|
}
|
|
1883
1696
|
/**
|
|
1884
|
-
*
|
|
1885
|
-
*
|
|
1886
|
-
*
|
|
1887
|
-
*
|
|
1888
|
-
|
|
1889
|
-
declare function defineChannel<const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [], const TO_CONNECTOR extends readonly ActionDomain<any>[] = []>(options: {
|
|
1890
|
-
toAcceptor: TO_ACCEPTOR;
|
|
1891
|
-
toConnector: TO_CONNECTOR;
|
|
1892
|
-
}): IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>;
|
|
1893
|
-
type TUnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
1894
|
-
type TDomainPushHandlers<D> = D extends ActionDomain<infer DEF> ? Partial<TWrappableDomainActionHandler<DEF>> : never;
|
|
1895
|
-
/**
|
|
1896
|
-
* The `onPush` map for a channel: the merged set of every acceptor→connector (`toConnector`) action
|
|
1897
|
-
* handler, each receiving the pushed action's input. Derived from the channel's `toConnectorDomains`, so
|
|
1898
|
-
* the keys and input types follow the channel definition.
|
|
1697
|
+
* A duplex carrier is also its own lifecycle handle: once it has been passed to `serveChannel`, feed each
|
|
1698
|
+
* inbound frame to {@link receive} and forget a connection on close/error with {@link drop}. This is how a
|
|
1699
|
+
* server with *several* duplex carriers routes each connection's traffic to the right one — you hold the
|
|
1700
|
+
* carrier you created and feed it directly, so no per-carrier router lookup is needed. The methods throw if
|
|
1701
|
+
* called before the carrier is served. (`serveChannel` binds the live router via {@link _activate}.)
|
|
1899
1702
|
*/
|
|
1900
|
-
|
|
1703
|
+
interface IDuplexCarrierLifecycle<TConn> {
|
|
1704
|
+
/** Feed one inbound frame from a live connection into the server. Throws until the carrier is served. */
|
|
1705
|
+
receive(connection: TConn, frame: TFrame$1): void;
|
|
1706
|
+
/** Forget a connection on close/error. No-op until the carrier is served. */
|
|
1707
|
+
drop(connection: TConn): void;
|
|
1708
|
+
/** @internal `serveChannel` binds this carrier's live connection router here. */
|
|
1709
|
+
_activate(router: IDuplexConnectionRouter<TConn>): void;
|
|
1710
|
+
}
|
|
1901
1711
|
/**
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1906
|
-
*
|
|
1907
|
-
* A duplex carrier (`wsCarrier(() => ({ url }))`, `rtcCarrier(dc)`) builds a push-capable link; an exchange carrier
|
|
1908
|
-
* (`httpCarrier(...)`) builds a request/reply transport. List them in preference order — the connection
|
|
1909
|
-
* prefers the first that's ready and falls through on failure (e.g. secure WS preferred, HTTP fallback).
|
|
1712
|
+
* A duplex (push-capable) carrier on the acceptor side. Describes how to write a frame back to a live
|
|
1713
|
+
* connection, how to perform the transport-specific upgrade that admits one, which requests are such
|
|
1714
|
+
* upgrades, and (optionally) how to persist bindings across hibernation. Built by `wsAcceptorCarrier` and
|
|
1715
|
+
* handed to `serveChannel`'s `carriers` list — the returned carrier is also its own lifecycle handle (see
|
|
1716
|
+
* {@link IDuplexCarrierLifecycle}).
|
|
1910
1717
|
*/
|
|
1911
|
-
interface
|
|
1912
|
-
/**
|
|
1913
|
-
|
|
1718
|
+
interface IDuplexAcceptorCarrier<TConn = unknown> extends IDuplexCarrierLifecycle<TConn> {
|
|
1719
|
+
/** Discriminant so `serveChannel` can tell a duplex carrier from an exchange one. */
|
|
1720
|
+
readonly shape: ETransportShape.duplex;
|
|
1914
1721
|
/**
|
|
1915
|
-
*
|
|
1916
|
-
*
|
|
1917
|
-
*
|
|
1722
|
+
* Whether each connection runs the secure handshake (default `true`). `false` makes it a plain duplex
|
|
1723
|
+
* carrier: connections speak the channel's wire codec directly with a self-asserted identity — no
|
|
1724
|
+
* handshake, pins, or encryption (the duplex dual of `httpAcceptorCarrier({ secure: false })`). A plain
|
|
1725
|
+
* carrier ignores the central crypto identity, so it needs no `storage` on `serveChannel`.
|
|
1918
1726
|
*/
|
|
1919
1727
|
secure?: boolean;
|
|
1920
|
-
/**
|
|
1921
|
-
|
|
1728
|
+
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
1729
|
+
send: (connection: TConn, frame: TFrame$1) => void;
|
|
1922
1730
|
/**
|
|
1923
|
-
*
|
|
1924
|
-
*
|
|
1731
|
+
* Perform the transport-specific upgrade for an inbound request, returning its raw response (e.g. a
|
|
1732
|
+
* Durable Object's `new WebSocketPair()` + `ctx.acceptWebSocket()` → a `101`). Omit for a carrier that
|
|
1733
|
+
* is fed connections out of band (the server then only routes frames via {@link receive}/{@link drop}).
|
|
1925
1734
|
*/
|
|
1926
|
-
|
|
1927
|
-
/** Override the devtools chip label (defaults to the carrier's own label). */
|
|
1928
|
-
label?: string;
|
|
1929
|
-
}
|
|
1930
|
-
interface IConnectChannelOptions<TO_CONNECTOR extends readonly ActionDomain<any>[]> {
|
|
1931
|
-
/** The peer's runtime coordinate — the acceptor this connection dials. */
|
|
1932
|
-
peer: RuntimeCoordinate;
|
|
1735
|
+
upgrade?: (request: Request, url: URL) => Response | Promise<Response>;
|
|
1933
1736
|
/**
|
|
1934
|
-
*
|
|
1935
|
-
*
|
|
1936
|
-
* falls through on failure. {@link connectChannel} binds the channel + runtime + crypto identity into
|
|
1937
|
-
* each — the dial-out dual of `serveChannel`'s `carriers`.
|
|
1737
|
+
* Whether an inbound request is an upgrade for this carrier. Defaults to an `Upgrade: websocket` header.
|
|
1738
|
+
* Only consulted when {@link upgrade} is present.
|
|
1938
1739
|
*/
|
|
1939
|
-
|
|
1740
|
+
isUpgrade?: (request: Request, url: URL) => boolean;
|
|
1940
1741
|
/**
|
|
1941
|
-
*
|
|
1942
|
-
*
|
|
1943
|
-
*
|
|
1944
|
-
* existing identity.
|
|
1742
|
+
* Optional attachment read/write for connections that survive eviction (Durable Object hibernation).
|
|
1743
|
+
* Present → `serveChannel` persists the routing binding (and any `connectionState`) here and replays it
|
|
1744
|
+
* on wake. Absent → per-connection state is in-memory only.
|
|
1945
1745
|
*/
|
|
1946
|
-
|
|
1947
|
-
/**
|
|
1948
|
-
|
|
1949
|
-
/** Default security level for secure transports; defaults to `authenticated`. */
|
|
1950
|
-
securityLevel?: ESecurityLevel;
|
|
1951
|
-
/** Handlers for the channel's acceptor→connector pushes. Optional — omit for a send-only connection. */
|
|
1952
|
-
onPush?: TChannelPushHandlers<TO_CONNECTOR>;
|
|
1953
|
-
/** Default per-action timeout for this connection. */
|
|
1954
|
-
defaultTimeout?: number;
|
|
1746
|
+
attachmentStore?: IAcceptorAttachmentStore<TConn>;
|
|
1747
|
+
/** Short carrier-kind label for the devtools chip (e.g. `"ws"`, `"webrtc"`). */
|
|
1748
|
+
readonly carrierLabel: string;
|
|
1955
1749
|
}
|
|
1956
1750
|
/**
|
|
1957
|
-
*
|
|
1958
|
-
*
|
|
1959
|
-
*
|
|
1960
|
-
*
|
|
1961
|
-
*
|
|
1962
|
-
*
|
|
1963
|
-
* ```ts
|
|
1964
|
-
* const handler = connectChannel(runtime, lobbyChannel, {
|
|
1965
|
-
* peer: runtime_coordinate_lobby_do,
|
|
1966
|
-
* storage,
|
|
1967
|
-
* transports: [{ carrier: wsCarrier(() => ({ url })) }, { carrier: httpCarrier(...), secure: false }],
|
|
1968
|
-
* onPush: { player_joined: (p) => { … } },
|
|
1969
|
-
* });
|
|
1970
|
-
* ```
|
|
1971
|
-
* Returns the {@link ConnectorHandler} so the caller can later `clearTransportCache()` it.
|
|
1972
|
-
*/
|
|
1973
|
-
declare function connectChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[]>(runtime: ActionRuntime, channel: ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR>, options: IConnectChannelOptions<TO_CONNECTOR>): ConnectorHandler;
|
|
1974
|
-
type TDomainAcceptorCases<D, TCtx> = D extends ActionDomain<infer DEF> ? { [ID in keyof DEF["actionSchema"] & string]?: TAcceptorCaseFn<DEF, ID, TCtx> } : never;
|
|
1975
|
-
/**
|
|
1976
|
-
* The connection-aware case map for a channel's acceptor side: the merged set of every
|
|
1977
|
-
* connector→acceptor (`toAcceptor`) action handler, each receiving the primed request plus a per-action
|
|
1978
|
-
* `context`. `TCtx` is whatever the wiring supplies as that second argument — the raw connection
|
|
1979
|
-
* (`TConn | undefined`) for the low-level `acceptChannelConnections`, or an enriched `IConnectionContext`
|
|
1980
|
-
* for `serveChannel`'s `channelCases`. Derived from the channel's `toAcceptorDomains`, so the keys and
|
|
1981
|
-
* input/output types follow the channel.
|
|
1982
|
-
*/
|
|
1983
|
-
type TChannelAcceptorCases<TO_ACCEPTOR extends readonly ActionDomain<any>[], TCtx> = TUnionToIntersection<TDomainAcceptorCases<TO_ACCEPTOR[number], TCtx>>;
|
|
1984
|
-
/**
|
|
1985
|
-
* Register an acceptor handler's execution for a channel straight from its definition: the channel's
|
|
1986
|
-
* `toAcceptor` domains are served together with one merged, connection-aware case map (each case gets
|
|
1987
|
-
* the primed request + the originating connection, as with
|
|
1988
|
-
* {@link AcceptorHandler.forConnectionDomainCases}). The domain list is taken from the channel,
|
|
1989
|
-
* never restated. Add the returned handler to the runtime alongside the acceptor handler:
|
|
1990
|
-
* ```ts
|
|
1991
|
-
* runtime.addHandlers([acceptChannelConnections(serverHandler, channel, { … }), serverHandler]);
|
|
1992
|
-
* ```
|
|
1993
|
-
*
|
|
1994
|
-
* The case's second argument is the raw connection (`TConn | undefined`). For the richer state +
|
|
1995
|
-
* broadcast + pushBack context, serve the channel through `serveChannel`'s `channelCases` instead.
|
|
1751
|
+
* An exchange (request/reply) carrier on the acceptor side, over web-standard `Request`/`Response`. By
|
|
1752
|
+
* default it speaks the *secure* exchange protocol (handshake → token session → encrypted frames), whose
|
|
1753
|
+
* identity is supplied centrally by `serveChannel`. Set {@link secure} to `false` for a plain endpoint
|
|
1754
|
+
* that POSTs the raw action wire and returns the result inline — the request/reply dual of the connector's
|
|
1755
|
+
* plain HTTP transport (`{ carrier: httpCarrier(...), secure: false }`). So a server can pair a secure
|
|
1756
|
+
* duplex (WebSocket) with a plain HTTP fallback on the same runtime. Built by `httpAcceptorCarrier`.
|
|
1996
1757
|
*/
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
* Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env("web_app")`),
|
|
2001
|
-
* used to score return-path dispatch back to the right connection.
|
|
2002
|
-
*/
|
|
2003
|
-
clientEnv: RuntimeCoordinate;
|
|
1758
|
+
interface IExchangeAcceptorCarrier {
|
|
1759
|
+
/** Discriminant so `serveChannel` can tell an exchange carrier from a duplex one. */
|
|
1760
|
+
readonly shape: ETransportShape.exchange;
|
|
2004
1761
|
/**
|
|
2005
|
-
*
|
|
2006
|
-
*
|
|
1762
|
+
* Whether this endpoint runs the secure exchange protocol (default `true`). `false` makes it a plain
|
|
1763
|
+
* endpoint: the body is the raw action wire and the result is the response body — no handshake, token,
|
|
1764
|
+
* or encryption. A plain endpoint ignores the central crypto identity entirely.
|
|
2007
1765
|
*/
|
|
2008
|
-
|
|
2009
|
-
/**
|
|
2010
|
-
|
|
1766
|
+
secure?: boolean;
|
|
1767
|
+
/** Which requests carry an action exchange envelope on `POST`. Defaults to `serveChannel`'s path match. */
|
|
1768
|
+
isActionPath?: (url: URL) => boolean;
|
|
2011
1769
|
/**
|
|
2012
|
-
*
|
|
2013
|
-
*
|
|
2014
|
-
* WebSocket acceptor and a secure-HTTP `createActionFetchHandler`), so they present the same keys.
|
|
1770
|
+
* CORS headers merged onto every response (a preflight `OPTIONS` is answered `204`). Defaults to the
|
|
1771
|
+
* permissive `*` set; pass `false` to attach no CORS headers at all.
|
|
2015
1772
|
*/
|
|
2016
|
-
|
|
2017
|
-
/**
|
|
2018
|
-
|
|
2019
|
-
/**
|
|
2020
|
-
|
|
2021
|
-
/** Timeout (ms) applied to acceptor-initiated actions awaiting a client response. */
|
|
2022
|
-
defaultTimeout?: number;
|
|
1773
|
+
cors?: Record<string, string> | false;
|
|
1774
|
+
/** Plain mode only: use the error's HTTP status for failures (default `true`). Ignored when secure. */
|
|
1775
|
+
useErrorStatus?: boolean;
|
|
1776
|
+
/** Short carrier-kind label for the devtools chip (e.g. `"http"`). */
|
|
1777
|
+
readonly carrierLabel: string;
|
|
2023
1778
|
}
|
|
2024
|
-
|
|
2025
|
-
* Build the secure {@link AcceptorHandler} for a channel — the accept-in counterpart to
|
|
2026
|
-
* {@link connectChannel}. It folds in the same boilerplate as {@link createSecureAcceptorHandler} (the
|
|
2027
|
-
* `ClientCryptoKeyLink` + storage-backed TOFU resolver from one `storageAdapter`, the channel's codec +
|
|
2028
|
-
* dictionary version, the `security` block from the runtime coordinate) but takes the `(runtime, channel,
|
|
2029
|
-
* options)` shape of the channel family. Pair it with {@link acceptChannelConnections} for execution:
|
|
2030
|
-
* ```ts
|
|
2031
|
-
* const acceptor = acceptChannel(runtime, gameChannel, { clientEnv, storageAdapter, send });
|
|
2032
|
-
* runtime.addHandlers([acceptChannelConnections(acceptor, gameChannel, { … }), acceptor]);
|
|
2033
|
-
* ```
|
|
2034
|
-
*/
|
|
2035
|
-
declare function acceptChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn = unknown>(runtime: ActionRuntime, channel: ISecureChannel<TO_ACCEPTOR, TO_CONNECTOR>, options: IAcceptChannelOptions<TConn>): AcceptorHandler<TConn>;
|
|
2036
|
-
//#endregion
|
|
2037
|
-
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/ConnectionStateStore.d.ts
|
|
2038
|
-
/**
|
|
2039
|
-
* The composite value persisted to a connection's attachment: the consumer's own app state plus the
|
|
2040
|
-
* {@link AcceptorHandler} routing binding. Co-storing them in one slot means a transport whose
|
|
2041
|
-
* sockets outlive process eviction (e.g. a Durable Object's hibernatable WebSocket) recovers both the
|
|
2042
|
-
* application identity *and* the action routing from a single attachment after a wake — no storage reads.
|
|
2043
|
-
*/
|
|
2044
|
-
interface IConnectionAttachment<TApp> {
|
|
2045
|
-
app?: TApp;
|
|
2046
|
-
binding?: IAcceptorConnectionBinding;
|
|
2047
|
-
}
|
|
2048
|
-
interface IConnectionStateStoreOptions<TConn, TApp> {
|
|
2049
|
-
/** Read a connection's raw attachment (e.g. `(ws) => ws.deserializeAttachment()`). */
|
|
2050
|
-
read: (connection: TConn) => unknown;
|
|
2051
|
-
/** Persist a connection's attachment (e.g. `(ws, value) => ws.serializeAttachment(value)`). */
|
|
2052
|
-
write: (connection: TConn, value: IConnectionAttachment<TApp>) => void;
|
|
2053
|
-
/**
|
|
2054
|
-
* All currently-live connections (e.g. `() => ctx.getWebSockets()`). Used to replay routing bindings
|
|
2055
|
-
* after a wake (via {@link createConnectionStateStore}) and to enumerate app state in
|
|
2056
|
-
* {@link ConnectionStateStore.entries}.
|
|
2057
|
-
*/
|
|
2058
|
-
getConnections: () => TConn[];
|
|
2059
|
-
/**
|
|
2060
|
-
* Optional Standard Schema (valibot, zod, …) validating the *app* portion on read. A value that
|
|
2061
|
-
* fails validation reads back as `null` — the same lenient behavior as a hand-written safeParse
|
|
2062
|
-
* helper. The binding is the library's own shape and is never validated.
|
|
2063
|
-
*/
|
|
2064
|
-
schema?: StandardSchemaV1<unknown, TApp>;
|
|
2065
|
-
}
|
|
2066
|
-
/**
|
|
2067
|
-
* A typed per-connection state store that co-owns the app state and the acceptor handler's routing
|
|
2068
|
-
* binding in one attachment, so neither the consumer nor the handler has to hand-merge the two. Create
|
|
2069
|
-
* it through {@link createConnectionStateStore} (which also wires binding persistence and replays
|
|
2070
|
-
* surviving connections after a wake), then `get`/`set`/`clearApp` the app state directly.
|
|
2071
|
-
*
|
|
2072
|
-
* The mechanism is carrier-neutral — it only needs read/write/enumerate callbacks for the connection's
|
|
2073
|
-
* attachment — but it pays off on transports whose connections outlive process eviction (e.g. a
|
|
2074
|
-
* Durable Object's hibernatable WebSockets), which is why it lives beside the hibernation adapter.
|
|
2075
|
-
*
|
|
2076
|
-
* ```ts
|
|
2077
|
-
* const players = createConnectionStateStore(serverHandler, {
|
|
2078
|
-
* schema: vs_player,
|
|
2079
|
-
* read: (ws) => ws.deserializeAttachment(),
|
|
2080
|
-
* write: (ws, v) => ws.serializeAttachment(v),
|
|
2081
|
-
* getConnections: () => ctx.getWebSockets(),
|
|
2082
|
-
* });
|
|
2083
|
-
* players.set(ws, player); // binding is preserved automatically
|
|
2084
|
-
* const player = players.get(ws);
|
|
2085
|
-
* ```
|
|
2086
|
-
*/
|
|
2087
|
-
declare class ConnectionStateStore<TConn, TApp> {
|
|
2088
|
-
private readonly options;
|
|
2089
|
-
constructor(options: IConnectionStateStoreOptions<TConn, TApp>);
|
|
2090
|
-
/** The validated app state for a connection, or `null` if unset / invalid. */
|
|
2091
|
-
get(connection: TConn): TApp | null;
|
|
2092
|
-
/** Set the app state, preserving the runtime binding already pinned to the connection. */
|
|
2093
|
-
set(connection: TConn, app: TApp): void;
|
|
2094
|
-
/** Clear the app state but keep the binding (e.g. a spectator that stopped watching). */
|
|
2095
|
-
clearApp(connection: TConn): void;
|
|
2096
|
-
/** Every live connection paired with its (validated) app state — for rebuilding in-memory state after a wake. */
|
|
2097
|
-
entries(): [TConn, TApp | null][];
|
|
2098
|
-
/** @internal Persist a freshly-bound connection's binding, preserving any app state already stored. */
|
|
2099
|
-
_persistBinding(connection: TConn, binding: IAcceptorConnectionBinding): void;
|
|
2100
|
-
/** @internal The persisted binding for a connection, if any (used to replay routing after a wake). */
|
|
2101
|
-
_readBinding(connection: TConn): IAcceptorConnectionBinding | undefined;
|
|
2102
|
-
private _readAttachment;
|
|
2103
|
-
private _validateApp;
|
|
2104
|
-
}
|
|
2105
|
-
/**
|
|
2106
|
-
* Build a per-connection {@link ConnectionStateStore} bound to an {@link AcceptorHandler}: it registers
|
|
2107
|
-
* itself as the handler's connection-bound persistence callback (so bindings are written without
|
|
2108
|
-
* overwriting app state) and immediately replays every live connection's stored binding via
|
|
2109
|
-
* {@link AcceptorHandler.rehydrateConnection} — so on a transport that resumes after eviction (e.g. a
|
|
2110
|
-
* Durable Object waking from hibernation) both the app identity and the action routing come back from a
|
|
2111
|
-
* single attachment, with no storage reads and no hand-rolled merge.
|
|
2112
|
-
*
|
|
2113
|
-
* Lives outside the handler so the generic {@link AcceptorHandler} stays free of any attachment/
|
|
2114
|
-
* hibernation concern — it exposes only the neutral `setOnConnectionBound` + `rehydrateConnection`
|
|
2115
|
-
* hooks this builder drives.
|
|
2116
|
-
*/
|
|
2117
|
-
declare function createConnectionStateStore<TConn, TApp>(handler: AcceptorHandler<TConn>, options: IConnectionStateStoreOptions<TConn, TApp>): ConnectionStateStore<TConn, TApp>;
|
|
2118
|
-
//#endregion
|
|
2119
|
-
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/createHibernatableWsServerAdapter.d.ts
|
|
2120
|
-
interface IHibernatableWsServerAdapterOptions<TConn> {
|
|
2121
|
-
/** The handler to drive (from `createSecureAcceptorHandler` or `createAcceptorHandler`). */
|
|
2122
|
-
handler: AcceptorHandler<TConn>;
|
|
2123
|
-
/** All currently-live connections — replayed on construction to rebuild bindings after a wake. */
|
|
2124
|
-
getConnections: () => TConn[];
|
|
2125
|
-
/** Read a connection's persisted binding (e.g. `(ws) => ws.deserializeAttachment()`). */
|
|
2126
|
-
getAttachment: (connection: TConn) => IAcceptorConnectionBinding | undefined;
|
|
2127
|
-
/** Persist a connection's binding when it is bound (e.g. `(ws, b) => ws.serializeAttachment(b)`). */
|
|
2128
|
-
setAttachment: (connection: TConn, binding: IAcceptorConnectionBinding) => void;
|
|
2129
|
-
}
|
|
2130
|
-
/**
|
|
2131
|
-
* The neutral lifecycle surface for a duplex (push-capable) acceptor: feed it each inbound frame and tell
|
|
2132
|
-
* it when a connection goes away. Carrier-agnostic — a WebSocket, a WebRTC data channel, or any other
|
|
2133
|
-
* duplex connection drives the same two methods.
|
|
2134
|
-
*/
|
|
2135
|
-
interface IDuplexConnectionRouter<TConn> {
|
|
2136
|
-
/** Feed one inbound frame from a connection into the handler. */
|
|
2137
|
-
receive: (connection: TConn, frame: string | ArrayBuffer | Uint8Array) => void;
|
|
2138
|
-
/** Forget a connection (call on socket close/error). */
|
|
2139
|
-
drop: (connection: TConn) => void;
|
|
2140
|
-
}
|
|
2141
|
-
/**
|
|
2142
|
-
* Wire the hibernation lifecycle for an acceptor handler on a transport whose connections outlive process
|
|
2143
|
-
* eviction (e.g. a Durable Object's hibernatable WebSockets). It owns persistence end to end:
|
|
2144
|
-
* registers `setAttachment` as the handler's connection-bound callback and immediately replays every
|
|
2145
|
-
* live connection's stored binding via `getAttachment`, so results/pushes still route after a wake.
|
|
2146
|
-
*
|
|
2147
|
-
* Layered on top of the generic {@link AcceptorHandler} — it touches only the handler's neutral
|
|
2148
|
-
* `setOnConnectionBound` / `rehydrateConnection` / `receive` / `dropConnection` surface, so no
|
|
2149
|
-
* hibernation concern leaks into the handler itself.
|
|
2150
|
-
*
|
|
2151
|
-
* Construct it once when the handler is built, then forward connection events:
|
|
2152
|
-
* ```ts
|
|
2153
|
-
* const duplex = createHibernatableWsServerAdapter({ handler, getConnections, getAttachment, setAttachment });
|
|
2154
|
-
* // webSocketMessage(ws, msg) => duplex.receive(ws, msg);
|
|
2155
|
-
* // webSocketClose/Error(ws) => duplex.drop(ws);
|
|
2156
|
-
* ```
|
|
2157
|
-
*/
|
|
2158
|
-
declare function createHibernatableWsServerAdapter<TConn>(options: IHibernatableWsServerAdapterOptions<TConn>): IDuplexConnectionRouter<TConn>;
|
|
2159
|
-
//#endregion
|
|
2160
|
-
//#region src/ActionRuntime/Transport/Carrier/AcceptorCarrier.types.d.ts
|
|
2161
|
-
/**
|
|
2162
|
-
* Acceptor-side carrier descriptors — the accept-in dual of the connector's {@link IDuplexCarrierSource}
|
|
2163
|
-
* / {@link IExchangeCarrierSource}. Where a connector source knows how to *open* a carrier to a peer, an
|
|
2164
|
-
* acceptor carrier knows how to *serve* one peer's traffic on this server. Both shapes are carrier-neutral
|
|
2165
|
-
* about security: `serveChannel` builds the crypto identity (link + TOFU resolver) and the security block
|
|
2166
|
-
* once from `(runtime, channel)` and fans it across every carrier, so a carrier descriptor never restates
|
|
2167
|
-
* it.
|
|
2168
|
-
*
|
|
2169
|
-
* Two shapes mirror the connector side:
|
|
2170
|
-
*
|
|
2171
|
-
* - {@link IDuplexAcceptorCarrier} — a persistent, push-capable byte stream (WebSocket, WebRTC, …). It can
|
|
2172
|
-
* push acceptor→connector, so it carries the return path and broadcasts, and it may need an upgrade step
|
|
2173
|
-
* (e.g. a Durable Object's `WebSocketPair`) and optional hibernation persistence.
|
|
2174
|
-
* - {@link IExchangeAcceptorCarrier} — a request → single-correlated-reply carrier with no unsolicited push
|
|
2175
|
-
* (HTTP). The reply rides the response to its own request; there is nothing to push and nothing to
|
|
2176
|
-
* upgrade.
|
|
2177
|
-
*/
|
|
2178
|
-
/**
|
|
2179
|
-
* Raw read/write access to a connection's persisted attachment, for a duplex carrier whose connections
|
|
2180
|
-
* outlive process eviction (e.g. a Durable Object's hibernatable WebSockets). Optional — omit for a
|
|
2181
|
-
* transport that never hibernates (per-connection state is then in-memory only).
|
|
2182
|
-
*
|
|
2183
|
-
* `serveChannel` owns the attachment *layout*: it co-stores the routing binding and (when
|
|
2184
|
-
* `connectionState` is requested) per-connection app state as one composite in this single slot, so both
|
|
2185
|
-
* survive a wake. The carrier only has to say how to read/write the slot and enumerate live connections.
|
|
2186
|
-
*/
|
|
2187
|
-
interface IAcceptorAttachmentStore<TConn> {
|
|
2188
|
-
/** All currently-live connections — enumerated on build to replay binding + app state after a wake. */
|
|
2189
|
-
getConnections: () => TConn[];
|
|
2190
|
-
/** Read a connection's persisted attachment (e.g. `(ws) => ws.deserializeAttachment()`). */
|
|
2191
|
-
read: (connection: TConn) => unknown;
|
|
2192
|
-
/** Persist a connection's attachment (e.g. `(ws, value) => ws.serializeAttachment(value)`). */
|
|
2193
|
-
write: (connection: TConn, value: unknown) => void;
|
|
2194
|
-
}
|
|
2195
|
-
/**
|
|
2196
|
-
* A duplex carrier is also its own lifecycle handle: once it has been passed to `serveChannel`, feed each
|
|
2197
|
-
* inbound frame to {@link receive} and forget a connection on close/error with {@link drop}. This is how a
|
|
2198
|
-
* server with *several* duplex carriers routes each connection's traffic to the right one — you hold the
|
|
2199
|
-
* carrier you created and feed it directly, so no per-carrier router lookup is needed. The methods throw if
|
|
2200
|
-
* called before the carrier is served. (`serveChannel` binds the live router via {@link _activate}.)
|
|
2201
|
-
*/
|
|
2202
|
-
interface IDuplexCarrierLifecycle<TConn> {
|
|
2203
|
-
/** Feed one inbound frame from a live connection into the server. Throws until the carrier is served. */
|
|
2204
|
-
receive(connection: TConn, frame: TFrame$1): void;
|
|
2205
|
-
/** Forget a connection on close/error. No-op until the carrier is served. */
|
|
2206
|
-
drop(connection: TConn): void;
|
|
2207
|
-
/** @internal `serveChannel` binds this carrier's live connection router here. */
|
|
2208
|
-
_activate(router: IDuplexConnectionRouter<TConn>): void;
|
|
2209
|
-
}
|
|
2210
|
-
/**
|
|
2211
|
-
* A duplex (push-capable) carrier on the acceptor side. Describes how to write a frame back to a live
|
|
2212
|
-
* connection, how to perform the transport-specific upgrade that admits one, which requests are such
|
|
2213
|
-
* upgrades, and (optionally) how to persist bindings across hibernation. Built by `wsAcceptorCarrier` and
|
|
2214
|
-
* handed to `serveChannel`'s `carriers` list — the returned carrier is also its own lifecycle handle (see
|
|
2215
|
-
* {@link IDuplexCarrierLifecycle}).
|
|
2216
|
-
*/
|
|
2217
|
-
interface IDuplexAcceptorCarrier<TConn = unknown> extends IDuplexCarrierLifecycle<TConn> {
|
|
2218
|
-
/** Discriminant so `serveChannel` can tell a duplex carrier from an exchange one. */
|
|
2219
|
-
readonly shape: ETransportShape.duplex;
|
|
2220
|
-
/**
|
|
2221
|
-
* Whether each connection runs the secure handshake (default `true`). `false` makes it a plain duplex
|
|
2222
|
-
* carrier: connections speak the channel's wire codec directly with a self-asserted identity — no
|
|
2223
|
-
* handshake, pins, or encryption (the duplex dual of `httpAcceptorCarrier({ secure: false })`). A plain
|
|
2224
|
-
* carrier ignores the central crypto identity, so it needs no `storage` on `serveChannel`.
|
|
2225
|
-
*/
|
|
2226
|
-
secure?: boolean;
|
|
2227
|
-
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
2228
|
-
send: (connection: TConn, frame: TFrame$1) => void;
|
|
2229
|
-
/**
|
|
2230
|
-
* Perform the transport-specific upgrade for an inbound request, returning its raw response (e.g. a
|
|
2231
|
-
* Durable Object's `new WebSocketPair()` + `ctx.acceptWebSocket()` → a `101`). Omit for a carrier that
|
|
2232
|
-
* is fed connections out of band (the server then only routes frames via {@link receive}/{@link drop}).
|
|
2233
|
-
*/
|
|
2234
|
-
upgrade?: (request: Request, url: URL) => Response | Promise<Response>;
|
|
2235
|
-
/**
|
|
2236
|
-
* Whether an inbound request is an upgrade for this carrier. Defaults to an `Upgrade: websocket` header.
|
|
2237
|
-
* Only consulted when {@link upgrade} is present.
|
|
2238
|
-
*/
|
|
2239
|
-
isUpgrade?: (request: Request, url: URL) => boolean;
|
|
2240
|
-
/**
|
|
2241
|
-
* Optional attachment read/write for connections that survive eviction (Durable Object hibernation).
|
|
2242
|
-
* Present → `serveChannel` persists the routing binding (and any `connectionState`) here and replays it
|
|
2243
|
-
* on wake. Absent → per-connection state is in-memory only.
|
|
2244
|
-
*/
|
|
2245
|
-
attachmentStore?: IAcceptorAttachmentStore<TConn>;
|
|
2246
|
-
/** Short carrier-kind label for the devtools chip (e.g. `"ws"`, `"webrtc"`). */
|
|
2247
|
-
readonly carrierLabel: string;
|
|
2248
|
-
}
|
|
2249
|
-
/**
|
|
2250
|
-
* An exchange (request/reply) carrier on the acceptor side, over web-standard `Request`/`Response`. By
|
|
2251
|
-
* default it speaks the *secure* exchange protocol (handshake → token session → encrypted frames), whose
|
|
2252
|
-
* identity is supplied centrally by `serveChannel`. Set {@link secure} to `false` for a plain endpoint
|
|
2253
|
-
* that POSTs the raw action wire and returns the result inline — the request/reply dual of the connector's
|
|
2254
|
-
* `plainTransport({ carrier: httpCarrier(...) })`. So a server can pair a secure duplex (WebSocket) with a
|
|
2255
|
-
* plain HTTP fallback on the same runtime. Built by `httpAcceptorCarrier`.
|
|
2256
|
-
*/
|
|
2257
|
-
interface IExchangeAcceptorCarrier {
|
|
2258
|
-
/** Discriminant so `serveChannel` can tell an exchange carrier from a duplex one. */
|
|
2259
|
-
readonly shape: ETransportShape.exchange;
|
|
2260
|
-
/**
|
|
2261
|
-
* Whether this endpoint runs the secure exchange protocol (default `true`). `false` makes it a plain
|
|
2262
|
-
* endpoint: the body is the raw action wire and the result is the response body — no handshake, token,
|
|
2263
|
-
* or encryption. A plain endpoint ignores the central crypto identity entirely.
|
|
2264
|
-
*/
|
|
2265
|
-
secure?: boolean;
|
|
2266
|
-
/** Which requests carry an action exchange envelope on `POST`. Defaults to `serveChannel`'s path match. */
|
|
2267
|
-
isActionPath?: (url: URL) => boolean;
|
|
2268
|
-
/**
|
|
2269
|
-
* CORS headers merged onto every response (a preflight `OPTIONS` is answered `204`). Defaults to the
|
|
2270
|
-
* permissive `*` set; pass `false` to attach no CORS headers at all.
|
|
2271
|
-
*/
|
|
2272
|
-
cors?: Record<string, string> | false;
|
|
2273
|
-
/** Plain mode only: use the error's HTTP status for failures (default `true`). Ignored when secure. */
|
|
2274
|
-
useErrorStatus?: boolean;
|
|
2275
|
-
/** Short carrier-kind label for the devtools chip (e.g. `"http"`). */
|
|
2276
|
-
readonly carrierLabel: string;
|
|
2277
|
-
}
|
|
2278
|
-
type TAcceptorCarrier<TConn = unknown> = IDuplexAcceptorCarrier<TConn> | IExchangeAcceptorCarrier;
|
|
1779
|
+
type TAcceptorCarrier<TConn = unknown> = IDuplexAcceptorCarrier<TConn> | IExchangeAcceptorCarrier;
|
|
2279
1780
|
/**
|
|
2280
1781
|
* Narrow an acceptor carrier to the exchange shape via its `shape` discriminant — the one branch
|
|
2281
1782
|
* `serveChannel` uses to pick the duplex (push-capable) vs exchange (request/reply) wiring. A duplex
|
|
@@ -2332,9 +1833,12 @@ interface IConnectionContext<TConn, TApp = unknown> {
|
|
|
2332
1833
|
interface IServeChannelOptions<TO_ACCEPTOR extends readonly ActionDomain<any>[], TConn, TApp = unknown> {
|
|
2333
1834
|
/**
|
|
2334
1835
|
* Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env("web_app")`),
|
|
2335
|
-
* used
|
|
1836
|
+
* used only as the offline-return scoring fallback — a result/push to a live client always routes over
|
|
1837
|
+
* the carrier it connected on regardless of this. Optional: omit it for a multi-role server that accepts
|
|
1838
|
+
* clients of several envs over one acceptor (it then scores 0 against every client, so the live
|
|
1839
|
+
* connection always decides).
|
|
2336
1840
|
*/
|
|
2337
|
-
clientEnv
|
|
1841
|
+
clientEnv?: RuntimeCoordinate;
|
|
2338
1842
|
/**
|
|
2339
1843
|
* One backing store for the server's crypto identity *and* its trust-on-first-use verify-key pins
|
|
2340
1844
|
* (their keys don't collide). It is built once and shared across every carrier, so the WebSocket and the
|
|
@@ -2465,12 +1969,12 @@ interface IChannelServer<TConn, TApp = unknown> {
|
|
|
2465
1969
|
* carrier, and so on — so it stays carrier-agnostic. Passing `connectionState` narrows the return so
|
|
2466
1970
|
* `server.connections` is non-optional.
|
|
2467
1971
|
*/
|
|
2468
|
-
declare function serveChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn, TApp>(runtime: ActionRuntime, channel:
|
|
1972
|
+
declare function serveChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn, TApp>(runtime: ActionRuntime, channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>, options: IServeChannelOptions<TO_ACCEPTOR, TConn, TApp> & {
|
|
2469
1973
|
connectionState: IServeConnectionStateOptions<TApp>;
|
|
2470
1974
|
}): IChannelServer<TConn, TApp> & {
|
|
2471
1975
|
connections: ConnectionStateStore<TConn, TApp>;
|
|
2472
1976
|
};
|
|
2473
|
-
declare function serveChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TConn = unknown, TApp = unknown>(runtime: ActionRuntime, channel:
|
|
1977
|
+
declare function serveChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TConn = unknown, TApp = unknown>(runtime: ActionRuntime, channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>, options: IServeChannelOptions<TO_ACCEPTOR, TConn, TApp>): IChannelServer<TConn, TApp>;
|
|
2474
1978
|
//#endregion
|
|
2475
1979
|
//#region src/ActionRuntime/Channel/serveHost.d.ts
|
|
2476
1980
|
/**
|
|
@@ -2503,157 +2007,12 @@ type TServeHostOptions<TO_ACCEPTOR extends readonly ActionDomain<any>[], TConn,
|
|
|
2503
2007
|
* the host adapter and nothing else. Passing `connectionState` narrows the return so `server.connections`
|
|
2504
2008
|
* is non-optional, exactly as with `serveChannel`.
|
|
2505
2009
|
*/
|
|
2506
|
-
declare function serveHost<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn, TApp>(runtime: ActionRuntime, channel:
|
|
2010
|
+
declare function serveHost<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn, TApp>(runtime: ActionRuntime, channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>, host: IChannelHostAdapter<TConn>, options: TServeHostOptions<TO_ACCEPTOR, TConn, TApp> & {
|
|
2507
2011
|
connectionState: IServeConnectionStateOptions<TApp>;
|
|
2508
2012
|
}): IChannelServer<TConn, TApp> & {
|
|
2509
2013
|
connections: ConnectionStateStore<TConn, TApp>;
|
|
2510
2014
|
};
|
|
2511
|
-
declare function serveHost<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TConn = unknown, TApp = unknown>(runtime: ActionRuntime, channel:
|
|
2512
|
-
//#endregion
|
|
2513
|
-
//#region src/ActionRuntime/Transport/SecureSession/exchangeAcceptor.d.ts
|
|
2514
|
-
/** Acceptor secure config for the exchange (HTTP) endpoint — same identity an `AcceptorHandler` uses. */
|
|
2515
|
-
interface IExchangeAcceptorSecurity {
|
|
2516
|
-
/** This acceptor's crypto identity (verify + exchange key pairs, optionally persisted). */
|
|
2517
|
-
link: ClientCryptoKeyLink;
|
|
2518
|
-
/** This acceptor's coordinate — its identity to clients during the handshake. */
|
|
2519
|
-
localCoordinate: IRuntimeCoordinate;
|
|
2520
|
-
/** Wire dictionary version; the handshake rejects a client on a mismatch. */
|
|
2521
|
-
dictionaryVersion: string;
|
|
2522
|
-
/** Accepted level(s) — a single level is strict, an array is a negotiable allowed set. */
|
|
2523
|
-
securityLevel: ESecurityLevel | readonly ESecurityLevel[];
|
|
2524
|
-
/** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */
|
|
2525
|
-
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
2526
|
-
}
|
|
2527
|
-
interface IExchangeAcceptorConfig {
|
|
2528
|
-
security: IExchangeAcceptorSecurity;
|
|
2529
|
-
/** The runtime that executes an inbound action wire and produces its result. */
|
|
2530
|
-
runtime: ActionRuntime;
|
|
2531
|
-
}
|
|
2532
|
-
/**
|
|
2533
|
-
* Acceptor (accept-in) side of the secure exchange protocol — the HTTP counterpart to
|
|
2534
|
-
* {@link AcceptorSecureSession}. Each POST body is one {@link decodeExchangeRequest} envelope; the
|
|
2535
|
-
* acceptor drives the server handshake over the two `hs` POSTs (correlated by `hsid`, since stateless
|
|
2536
|
-
* requests can't rely on channel ordering), mints a session **token** on accept, and on every later `act`
|
|
2537
|
-
* POST resolves the session by token, decrypts the body (at `encrypted`), routes it through the runtime,
|
|
2538
|
-
* and returns the (encrypted) result inline as the reply.
|
|
2539
|
-
*
|
|
2540
|
-
* Sessions and in-flight handshakes are held in memory — fine for a single-instance server. (Surviving a
|
|
2541
|
-
* Durable-Object eviction would persist each token's `keyMaterial` and re-derive the key on a miss, the
|
|
2542
|
-
* same primitive `AcceptorSecureSession.rehydrate` uses; left as a follow-up.)
|
|
2543
|
-
*/
|
|
2544
|
-
declare class ExchangeAcceptor {
|
|
2545
|
-
private readonly _security;
|
|
2546
|
-
private readonly _runtime;
|
|
2547
|
-
private readonly _allowedLevels;
|
|
2548
|
-
private readonly _noneAllowed;
|
|
2549
|
-
private readonly _pendingHandshakes;
|
|
2550
|
-
private readonly _sessions;
|
|
2551
|
-
constructor(config: IExchangeAcceptorConfig);
|
|
2552
|
-
/** Process one POST body (an exchange envelope), returning the reply body to send back. */
|
|
2553
|
-
handlePost(body: string): Promise<string>;
|
|
2554
|
-
private _handleHandshake;
|
|
2555
|
-
private _handleAction;
|
|
2556
|
-
private _err;
|
|
2557
|
-
}
|
|
2558
|
-
//#endregion
|
|
2559
|
-
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/createActionFetchHandler.d.ts
|
|
2560
|
-
interface IActionFetchHandlerOptions {
|
|
2561
|
-
/**
|
|
2562
|
-
* CORS headers merged onto every response (a preflight `OPTIONS` is answered `204` with them).
|
|
2563
|
-
* Defaults to permissive `*`; pass `false` to attach no CORS headers at all.
|
|
2564
|
-
*/
|
|
2565
|
-
cors?: Record<string, string> | false;
|
|
2566
|
-
/** Which requests carry an action wire on `POST`. Default: pathname ends with `/action`. */
|
|
2567
|
-
isActionPath?: (url: URL) => boolean;
|
|
2568
|
-
/** Which requests are WebSocket upgrades. Default: pathname ends with `/ws`. */
|
|
2569
|
-
isWebSocketPath?: (url: URL) => boolean;
|
|
2570
|
-
/**
|
|
2571
|
-
* Whether a request is a WebSocket upgrade for this endpoint, given the whole request (not just the
|
|
2572
|
-
* URL). When set it *replaces* the default gate (an `Upgrade: websocket` header on an
|
|
2573
|
-
* {@link isWebSocketPath} match) — use it when the discriminant needs a header or method, not only the
|
|
2574
|
-
* path. Only consulted when {@link onWebSocketUpgrade} is present.
|
|
2575
|
-
*/
|
|
2576
|
-
isWebSocketUpgrade?: (request: Request, url: URL) => boolean;
|
|
2577
|
-
/**
|
|
2578
|
-
* Perform the transport-specific WebSocket upgrade (e.g. a Durable Object's
|
|
2579
|
-
* `new WebSocketPair()` + `ctx.acceptWebSocket()` returning a `101`). Omit for HTTP-only endpoints.
|
|
2580
|
-
* Its response is returned as-is — a `101` upgrade carries no CORS headers.
|
|
2581
|
-
*/
|
|
2582
|
-
onWebSocketUpgrade?: (request: Request, url: URL) => Response | Promise<Response>;
|
|
2583
|
-
/** Forwarded to `ActionPayload_Result.toHttpResponse` — use the error's HTTP status (default true). */
|
|
2584
|
-
useErrorStatus?: boolean;
|
|
2585
|
-
/**
|
|
2586
|
-
* Enable the secure exchange protocol (handshake + token sessions + body encryption) on the `/action`
|
|
2587
|
-
* endpoint, mirroring an `AcceptorHandler`'s `security`. The matching connector is
|
|
2588
|
-
* `secureTransport({ carrier: httpCarrier(...), securityLevel })`. When omitted, the endpoint speaks
|
|
2589
|
-
* today's plain protocol (the raw action wire is POSTed and the result is the response body).
|
|
2590
|
-
*/
|
|
2591
|
-
security?: IExchangeAcceptorSecurity;
|
|
2592
|
-
}
|
|
2593
|
-
/**
|
|
2594
|
-
* Build the `fetch` handler a server/Durable-Object exposes for action traffic, folding in the
|
|
2595
|
-
* boilerplate every endpoint repeats: CORS (incl. the `OPTIONS` preflight), routing the `/action`
|
|
2596
|
-
* `POST` body through the runtime (`handleActionPayloadWire` → `waitForResultPayload` →
|
|
2597
|
-
* `toHttpResponse`), an optional WebSocket-upgrade hook, and a `404` fallback.
|
|
2598
|
-
*
|
|
2599
|
-
* It only touches web-standard `Request`/`Response`, so it stays transport-agnostic — the one
|
|
2600
|
-
* environment-specific bit (the WS upgrade) is injected via {@link IActionFetchHandlerOptions.onWebSocketUpgrade}:
|
|
2601
|
-
* ```ts
|
|
2602
|
-
* this.fetchHandler = createActionFetchHandler(this.runtime, {
|
|
2603
|
-
* onWebSocketUpgrade: () => {
|
|
2604
|
-
* const pair = new WebSocketPair();
|
|
2605
|
-
* this.ctx.acceptWebSocket(pair[1]);
|
|
2606
|
-
* return new Response(null, { status: 101, webSocket: pair[0] });
|
|
2607
|
-
* },
|
|
2608
|
-
* });
|
|
2609
|
-
* // async fetch(request) { return this.fetchHandler(request); }
|
|
2610
|
-
* ```
|
|
2611
|
-
*/
|
|
2612
|
-
declare function createActionFetchHandler(runtime: ActionRuntime, options?: IActionFetchHandlerOptions): (request: Request) => Promise<Response>;
|
|
2613
|
-
//#endregion
|
|
2614
|
-
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/createSecureActionServer.d.ts
|
|
2615
|
-
interface ISecureAcceptorHandlerOptions<TConn> {
|
|
2616
|
-
/** The shared channel identity (codec + dictionary version) — same one the clients use. */
|
|
2617
|
-
channel: ISecureChannel;
|
|
2618
|
-
/**
|
|
2619
|
-
* Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env("web_app")`),
|
|
2620
|
-
* used to route results/pushes back over this handler.
|
|
2621
|
-
*/
|
|
2622
|
-
clientEnv: RuntimeCoordinate;
|
|
2623
|
-
/** This server's runtime — its coordinate is the server identity presented in the handshake. */
|
|
2624
|
-
runtime: ActionRuntime;
|
|
2625
|
-
/**
|
|
2626
|
-
* One backing store for the server's crypto identity *and* its trust-on-first-use verify-key pins.
|
|
2627
|
-
* Their keys don't collide, so a single adapter is enough; back it with persistent storage (e.g. a
|
|
2628
|
-
* Durable Object's storage) so identity and pins survive eviction.
|
|
2629
|
-
*/
|
|
2630
|
-
storageAdapter: StorageAdapter;
|
|
2631
|
-
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
2632
|
-
send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;
|
|
2633
|
-
/**
|
|
2634
|
-
* The server's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storageAdapter`.
|
|
2635
|
-
* Pass an existing link to share one identity across several acceptors on the same server (e.g. a
|
|
2636
|
-
* WebSocket acceptor and a secure-HTTP {@link createActionFetchHandler}), so they present the same
|
|
2637
|
-
* verify/exchange keys — avoiding a divergent-key race when two fresh links initialize concurrently.
|
|
2638
|
-
*/
|
|
2639
|
-
link?: ClientCryptoKeyLink;
|
|
2640
|
-
/** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */
|
|
2641
|
-
securityLevel?: ESecurityLevel | readonly ESecurityLevel[];
|
|
2642
|
-
/** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storageAdapter`. */
|
|
2643
|
-
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
2644
|
-
/** Timeout (ms) applied to server-initiated actions awaiting a client response. */
|
|
2645
|
-
defaultTimeout?: number;
|
|
2646
|
-
}
|
|
2647
|
-
/**
|
|
2648
|
-
* Build an {@link AcceptorHandler} for the secure binary channel with the boilerplate folded in:
|
|
2649
|
-
* it creates the {@link ClientCryptoKeyLink} and the storage-backed TOFU resolver from a single
|
|
2650
|
-
* `storageAdapter`, installs the channel's per-connection codec, and assembles the `security` block
|
|
2651
|
-
* from the runtime coordinate + channel version (accepting all three levels by default).
|
|
2652
|
-
*
|
|
2653
|
-
* For a hibernatable transport (e.g. a Durable Object), pair it with
|
|
2654
|
-
* {@link createHibernatableWsServerAdapter} to wire persistence + replay.
|
|
2655
|
-
*/
|
|
2656
|
-
declare function createSecureAcceptorHandler<TConn = unknown>(options: ISecureAcceptorHandlerOptions<TConn>): AcceptorHandler<TConn>;
|
|
2015
|
+
declare function serveHost<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TConn = unknown, TApp = unknown>(runtime: ActionRuntime, channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>, host: IChannelHostAdapter<TConn>, options: TServeHostOptions<TO_ACCEPTOR, TConn, TApp>): IChannelServer<TConn, TApp>;
|
|
2657
2016
|
//#endregion
|
|
2658
2017
|
//#region src/ActionRuntime/Handler/PeerLink/Connector/err_nice_external_client.d.ts
|
|
2659
2018
|
declare const err_nice_external_client: import("@nice-code/error").NiceErrorDomain<{
|
|
@@ -2693,16 +2052,15 @@ declare function createInMemoryChannelPair(): IInMemoryChannelPair;
|
|
|
2693
2052
|
//#endregion
|
|
2694
2053
|
//#region src/ActionRuntime/Transport/Carrier/duplex/inMemory/inMemoryCarrier.d.ts
|
|
2695
2054
|
interface IInMemoryCarrier {
|
|
2696
|
-
/** The connector end — pass as the `carrier` to
|
|
2055
|
+
/** The connector end — pass as the `carrier` to one of `connectChannel`'s transports. */
|
|
2697
2056
|
carrier: IDuplexCarrierSource;
|
|
2698
2057
|
/** The acceptor end — wire into an `AcceptorHandler` (`send` + `receive`). */
|
|
2699
2058
|
serverEndpoint: IInMemoryServerEndpoint;
|
|
2700
2059
|
}
|
|
2701
2060
|
/**
|
|
2702
2061
|
* A loopback duplex carrier with no socket — two cross-wired in-process ends. The connector end is an
|
|
2703
|
-
* {@link IDuplexCarrierSource} for
|
|
2704
|
-
*
|
|
2705
|
-
* non-WS carrier end to end.
|
|
2062
|
+
* {@link IDuplexCarrierSource} for `connectChannel`; the acceptor end plugs into an `AcceptorHandler`.
|
|
2063
|
+
* Ideal for tests and for running two runtimes in one process, or proving a non-WS carrier end to end.
|
|
2706
2064
|
*/
|
|
2707
2065
|
declare function inMemoryCarrier(): IInMemoryCarrier;
|
|
2708
2066
|
//#endregion
|
|
@@ -2738,8 +2096,8 @@ interface IRtcCarrierOptions {
|
|
|
2738
2096
|
}
|
|
2739
2097
|
/**
|
|
2740
2098
|
* A WebRTC {@link IDuplexCarrierSource} over an already-negotiated `RTCDataChannel` (signaling is the
|
|
2741
|
-
* app's concern).
|
|
2742
|
-
* identical secure session as a WebSocket.
|
|
2099
|
+
* app's concern). Pass it as a `carrier` to `connectChannel` so two browsers/apps linked peer-to-peer run
|
|
2100
|
+
* the identical secure session as a WebSocket.
|
|
2743
2101
|
*/
|
|
2744
2102
|
declare function rtcCarrier(dataChannel: IRtcDataChannelLike, options?: IRtcCarrierOptions): IDuplexCarrierSource;
|
|
2745
2103
|
//#endregion
|
|
@@ -2806,8 +2164,8 @@ interface IWsCarrierOptions {
|
|
|
2806
2164
|
}
|
|
2807
2165
|
/**
|
|
2808
2166
|
* A WebSocket {@link IDuplexCarrierSource}: opens an `arraybuffer` socket (cached per endpoint) and adapts
|
|
2809
|
-
* it to a carrier.
|
|
2810
|
-
*
|
|
2167
|
+
* it to a carrier. Pass it as a `carrier` to `connectChannel` — the WebSocket is now "just another
|
|
2168
|
+
* carrier" under the shared secure session, with no WS-specific transport class.
|
|
2811
2169
|
*
|
|
2812
2170
|
* `createRequest` derives the socket URL per action (keep it simple with `() => ({ url })`), so dynamic
|
|
2813
2171
|
* endpoints (e.g. a per-run query param) need no `createWebSocket` escape hatch.
|
|
@@ -2819,8 +2177,9 @@ interface IHttpAcceptorCarrierOptions {
|
|
|
2819
2177
|
/**
|
|
2820
2178
|
* Whether this endpoint runs the secure exchange protocol (default `true`). Pass `false` for a plain
|
|
2821
2179
|
* endpoint — the body is the raw action wire and the result is the response body, the request/reply dual
|
|
2822
|
-
* of `
|
|
2823
|
-
* can sit alongside a secure WebSocket on the same server
|
|
2180
|
+
* of a connector's plain HTTP transport (`{ carrier: httpCarrier(...), secure: false }`). A plain
|
|
2181
|
+
* endpoint ignores the crypto identity, so it can sit alongside a secure WebSocket on the same server
|
|
2182
|
+
* (e.g. a secure WS preferred, plain HTTP fallback).
|
|
2824
2183
|
*/
|
|
2825
2184
|
secure?: boolean;
|
|
2826
2185
|
/** Which requests carry an action exchange envelope on `POST`. Defaults to `serveChannel`'s path match. */
|
|
@@ -2863,129 +2222,16 @@ interface IHttpCarrierOptions {
|
|
|
2863
2222
|
}
|
|
2864
2223
|
/**
|
|
2865
2224
|
* An HTTP {@link IExchangeCarrierSource}: each `exchange` POSTs one frame body to the action endpoint and
|
|
2866
|
-
* resolves with the response body as the single correlated reply.
|
|
2867
|
-
* HTTP then runs the *same* secure session as a duplex carrier
|
|
2868
|
-
* the request/reply correlation provided for free by the HTTP
|
|
2225
|
+
* resolves with the response body as the single correlated reply. Pass it as a `carrier` to
|
|
2226
|
+
* `connectChannel` — a secure HTTP transport then runs the *same* secure session as a duplex carrier
|
|
2227
|
+
* (handshake → token → encrypted frames), the request/reply correlation provided for free by the HTTP
|
|
2228
|
+
* transaction.
|
|
2869
2229
|
*
|
|
2870
2230
|
* `createRequest` derives the URL/headers per action (keep it simple with `() => ({ url })`). The body is
|
|
2871
2231
|
* the session's responsibility, so it is never built here.
|
|
2872
2232
|
*/
|
|
2873
2233
|
declare function httpCarrier(createRequest: (input: ITransportRouteActionParams) => IHttpCarrierRequest, options?: IHttpCarrierOptions): IExchangeCarrierSource;
|
|
2874
2234
|
//#endregion
|
|
2875
|
-
//#region src/ActionRuntime/Transport/codec/createBinaryWireAdapter.d.ts
|
|
2876
|
-
/**
|
|
2877
|
-
* Builds a *stateless* `formatMessage` pipeline for {@link LinkTransport}, packing action
|
|
2878
|
-
* payloads into a compact msgpackr binary frame instead of JSON. The `domain`/`id` route collapses to
|
|
2879
|
-
* a single integer drawn from a shared dictionary; `form`/`type`, the recomputable
|
|
2880
|
-
* `inputHash`/`outputHash`, and the per-frame `context.routing`/`context.timeCreated` are all dropped
|
|
2881
|
-
* (see {@link ENVELOPE}).
|
|
2882
|
-
*
|
|
2883
|
-
* No validation runs here: `incoming` blindly reconstructs the wire JSON shape and hands it back to
|
|
2884
|
-
* the connection, which flows into `ActionRuntime` → `domain.hydrateAnyAction()` where the Valibot
|
|
2885
|
-
* schemas validate it exactly as they would for a JSON frame.
|
|
2886
|
-
*
|
|
2887
|
-
* Both ends of the socket MUST construct the adapter with the same domains in the same order — the
|
|
2888
|
-
* integer dictionary is positional. Mismatched dictionaries will route to the wrong action.
|
|
2889
|
-
*
|
|
2890
|
-
* Because `incoming` returns `undefined` for text frames, a binary server can still serve plain-JSON
|
|
2891
|
-
* clients on the same runtime (the connection falls back to its built-in JSON parser).
|
|
2892
|
-
*/
|
|
2893
|
-
declare function createBinaryWireAdapter(domains: ActionDomain<any>[]): IActionWireFormat;
|
|
2894
|
-
//#endregion
|
|
2895
|
-
//#region src/ActionRuntime/Transport/crypto/actionFrameCrypto.d.ts
|
|
2896
|
-
/**
|
|
2897
|
-
* Async AES-GCM transform for the `encrypted` security level. It wraps the opaque binary frame a
|
|
2898
|
-
* session codec produces (it does NOT look inside it), encrypting on the way out and decrypting on the
|
|
2899
|
-
* way in with the shared key established by the handshake.
|
|
2900
|
-
*
|
|
2901
|
-
* It is deliberately separate from the (synchronous) session `formatMessage`: WebCrypto is always
|
|
2902
|
-
* Promise-based, so encryption has to happen at the transport's async I/O boundary — the connection
|
|
2903
|
-
* encrypts after `session.outgoing()` and decrypts before `session.incoming()`. The `authenticated`
|
|
2904
|
-
* and `none` levels use no crypto transform at all (frames go out as the session produced them).
|
|
2905
|
-
*
|
|
2906
|
-
* Wire shape of an encrypted frame: `pack([nonceBytes, ciphertextBytes])` — msgpack carries the two
|
|
2907
|
-
* binary fields with a couple of bytes of overhead, no base64 inflation.
|
|
2908
|
-
*/
|
|
2909
|
-
interface IActionFrameCrypto {
|
|
2910
|
-
/** Encrypt one session frame for sending. */
|
|
2911
|
-
encryptFrame(frame: Uint8Array): Promise<Uint8Array>;
|
|
2912
|
-
/** Decrypt one received frame back to the session frame. Throws on a non-binary / malformed /
|
|
2913
|
-
* tampered frame — the caller (transport) decides how to react (drop / close). */
|
|
2914
|
-
decryptFrame(frame: string | ArrayBuffer | Uint8Array): Promise<Uint8Array>;
|
|
2915
|
-
}
|
|
2916
|
-
interface IActionFrameCryptoConfig {
|
|
2917
|
-
link: ClientCryptoKeyLink;
|
|
2918
|
-
/** The handshake-established link id for the remote (key + connection-registry id). */
|
|
2919
|
-
linkedClientId: TTypeAndId;
|
|
2920
|
-
}
|
|
2921
|
-
/**
|
|
2922
|
-
* Build the encrypt/decrypt transform for a connection whose handshake settled on the `encrypted`
|
|
2923
|
-
* level. Keyed by the link + `linkedClientId`, so it reuses the cached shared AES-GCM key.
|
|
2924
|
-
*/
|
|
2925
|
-
declare function createActionFrameCrypto({
|
|
2926
|
-
link,
|
|
2927
|
-
linkedClientId
|
|
2928
|
-
}: IActionFrameCryptoConfig): IActionFrameCrypto;
|
|
2929
|
-
//#endregion
|
|
2930
|
-
//#region src/ActionRuntime/Transport/Exchange/TransportExchange.types.d.ts
|
|
2931
|
-
interface IActionTransportReadyData_Exchange extends IActionTransportReadyData_Base {
|
|
2932
|
-
/** The live request/reply carrier this connection drives its session over. */
|
|
2933
|
-
carrier: IExchangeCarrier;
|
|
2934
|
-
/** Optional authenticated/encrypted config; the handshake runs once at bring-up when set. */
|
|
2935
|
-
secureChannel?: ISecureClientConfig;
|
|
2936
|
-
}
|
|
2937
|
-
interface IActionTransportInitialized_Exchange extends IActionTransportInitialized<ITransportRouteActionParams, IActionTransportReadyData_Exchange> {}
|
|
2938
|
-
interface IActionTransportDef_Exchange extends IActionTransportDef<ETransportShape.exchange, IActionTransportInitialized_Exchange> {}
|
|
2939
|
-
//#endregion
|
|
2940
|
-
//#region src/ActionRuntime/Transport/Exchange/ExchangeConnection.d.ts
|
|
2941
|
-
/**
|
|
2942
|
-
* Carrier-agnostic live connection for the exchange (request → single reply) shape — the HTTP
|
|
2943
|
-
* counterpart to {@link LinkConnection}. It owns only the bring-up (run the secure handshake on first
|
|
2944
|
-
* use); the request/reply lifecycle + crypto live in the shared `establishExchangeSession`.
|
|
2945
|
-
*/
|
|
2946
|
-
declare class ExchangeConnection extends TransportConnection<ETransportShape.exchange, ITransportRouteActionParams, IActionTransportReadyData_Exchange, IActionTransportInitialized_Exchange, IActionTransportDef_Exchange> {
|
|
2947
|
-
constructor(def: Omit<IActionTransportDef_Exchange, "type">);
|
|
2948
|
-
protected _getCacheKey(input: ITransportRouteActionParams): string;
|
|
2949
|
-
protected _needsAsyncBringUp(data: IActionTransportReadyData_Exchange): boolean;
|
|
2950
|
-
protected _finalizeReady(data: IActionTransportReadyData_Exchange): IActionTransportReadyData_Methods | Promise<IActionTransportReadyData_Methods>;
|
|
2951
|
-
_finalizeTransportMethods(data: IActionTransportReadyData_Exchange): IActionTransportReadyData_Methods;
|
|
2952
|
-
private _sessionContext;
|
|
2953
|
-
}
|
|
2954
|
-
//#endregion
|
|
2955
|
-
//#region src/ActionRuntime/Transport/Exchange/ExchangeTransport.d.ts
|
|
2956
|
-
interface IExchangeTransportOptions {
|
|
2957
|
-
/** Open (or reuse) the exchange carrier for an action — e.g. `httpCarrier(...).open`. */
|
|
2958
|
-
openCarrier: (input: ITransportRouteActionParams) => IExchangeCarrier;
|
|
2959
|
-
/** Secure config; when set (and `securityLevel !== none`) the handshake runs once at bring-up. */
|
|
2960
|
-
security?: ISecureClientConfig;
|
|
2961
|
-
updateRunConfig?: TUpdateActionRunConfig;
|
|
2962
|
-
/** Keys identifying a reusable session, so one carrier is shared across actions to the same peer. */
|
|
2963
|
-
getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
2964
|
-
/**
|
|
2965
|
-
* Optional availability gate. When it returns `false`, the manager skips this transport for that action
|
|
2966
|
-
* (reporting `unsupported`) and falls through to the next — without opening the carrier or computing its
|
|
2967
|
-
* cache key. Re-evaluated per dispatch, so the transport can become available later with no reconnect.
|
|
2968
|
-
*/
|
|
2969
|
-
available?: (input: ITransportRouteActionParams) => boolean;
|
|
2970
|
-
/** Short label for the devtools chip (defaults to "exchange"). */
|
|
2971
|
-
label?: string;
|
|
2972
|
-
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
2973
|
-
}
|
|
2974
|
-
/**
|
|
2975
|
-
* A carrier-agnostic exchange (request → single reply) transport: it drives nice-action's secure session
|
|
2976
|
-
* over any {@link IExchangeCarrier} (HTTP being the one built-in). The duplex counterpart is
|
|
2977
|
-
* {@link LinkTransport}; this is the no-push half — its reply rides the response to its own request, so it
|
|
2978
|
-
* can't deliver an unsolicited frame (the runtime never picks it for the return path).
|
|
2979
|
-
*/
|
|
2980
|
-
declare class ExchangeTransport extends Transport<ETransportShape.exchange> {
|
|
2981
|
-
private readonly options;
|
|
2982
|
-
readonly type = ETransportShape.exchange;
|
|
2983
|
-
constructor(options: IExchangeTransportOptions);
|
|
2984
|
-
static create(options: IExchangeTransportOptions): ExchangeTransport;
|
|
2985
|
-
_createConnection(_ctx: ITransportConnectionContext): ExchangeConnection;
|
|
2986
|
-
getRouteInfo(input: ITransportRouteActionParams): ITransportRouteInfo;
|
|
2987
|
-
}
|
|
2988
|
-
//#endregion
|
|
2989
2235
|
//#region src/ActionRuntime/Transport/err_nice_transport.d.ts
|
|
2990
2236
|
declare enum EErrId_NiceTransport {
|
|
2991
2237
|
timeout = "timeout",
|
|
@@ -3023,79 +2269,50 @@ declare const err_nice_transport: import("@nice-code/error").NiceErrorDomain<{
|
|
|
3023
2269
|
};
|
|
3024
2270
|
}>;
|
|
3025
2271
|
//#endregion
|
|
3026
|
-
//#region src/ActionRuntime/Transport/
|
|
3027
|
-
/**
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
/**
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
* channel, a Bluetooth characteristic, and an in-memory pipe all run the identical secure layer.
|
|
3045
|
-
*/
|
|
3046
|
-
declare class LinkConnection extends TransportConnection<ETransportShape.duplex, ITransportRouteActionParams, IActionTransportReadyData_Link, IActionTransportInitialized_Link, IActionTransportDef_Link> {
|
|
3047
|
-
private resolvers;
|
|
3048
|
-
constructor(def: Omit<IActionTransportDef_Link, "type">, resolvers?: IActionTransportResolvers);
|
|
3049
|
-
protected _getCacheKey(input: ITransportRouteActionParams): string;
|
|
3050
|
-
protected _needsAsyncBringUp(): boolean;
|
|
3051
|
-
protected _awaitCarrierReady(data: IActionTransportReadyData_Link): Promise<void>;
|
|
3052
|
-
protected _finalizeReady(data: IActionTransportReadyData_Link): IActionTransportReadyData_Methods | Promise<IActionTransportReadyData_Methods>;
|
|
3053
|
-
private _sessionContext;
|
|
3054
|
-
_finalizeTransportMethods(data: IActionTransportReadyData_Link): IActionTransportReadyData_Methods;
|
|
3055
|
-
}
|
|
3056
|
-
//#endregion
|
|
3057
|
-
//#region src/ActionRuntime/Transport/Link/LinkTransport.d.ts
|
|
3058
|
-
interface ILinkTransportOptions {
|
|
3059
|
-
/**
|
|
3060
|
-
* Open (or reuse) the carrier for an action — a WebSocket adapter, a WebRTC data channel, a Bluetooth
|
|
3061
|
-
* characteristic, an in-memory pipe, anything that satisfies {@link IDuplexCarrier}.
|
|
3062
|
-
*/
|
|
3063
|
-
openChannel: (input: ITransportRouteActionParams) => IDuplexCarrier;
|
|
3064
|
-
/** Shared codec for every channel (stateless). */
|
|
3065
|
-
formatMessage?: TLinkFormatMessage;
|
|
3066
|
-
/**
|
|
3067
|
-
* Per-channel codec factory — called once per opened channel so stateful codecs (e.g. the binary
|
|
3068
|
-
* session) get their own instance. Takes precedence over `formatMessage`.
|
|
3069
|
-
*/
|
|
3070
|
-
createFormatMessage?: () => TLinkFormatMessage;
|
|
3071
|
-
/** Secure-channel config; when set (and `securityLevel !== none`) the handshake runs on init. */
|
|
3072
|
-
security?: ISecureClientConfig;
|
|
3073
|
-
updateRunConfig?: TUpdateActionRunConfig;
|
|
3074
|
-
/** Keys identifying a reusable channel, so one carrier is shared across actions to the same peer. */
|
|
3075
|
-
getTransportCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
3076
|
-
/**
|
|
3077
|
-
* Optional availability gate. When it returns `false`, the manager skips this transport for that action
|
|
3078
|
-
* (reporting `unsupported`) and falls through to the next — without opening the carrier or computing its
|
|
3079
|
-
* cache key. Re-evaluated per dispatch, so the transport can become available later with no reconnect.
|
|
3080
|
-
*/
|
|
3081
|
-
available?: (input: ITransportRouteActionParams) => boolean;
|
|
3082
|
-
/** Short label for the devtools chip (defaults to "link"). */
|
|
3083
|
-
label?: string;
|
|
3084
|
-
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
2272
|
+
//#region src/ActionRuntime/Transport/SecureSession/exchangeAcceptor.d.ts
|
|
2273
|
+
/** Acceptor secure config for the exchange (HTTP) endpoint — same identity an `AcceptorHandler` uses. */
|
|
2274
|
+
interface IExchangeAcceptorSecurity {
|
|
2275
|
+
/** This acceptor's crypto identity (verify + exchange key pairs, optionally persisted). */
|
|
2276
|
+
link: ClientCryptoKeyLink;
|
|
2277
|
+
/** This acceptor's coordinate — its identity to clients during the handshake. */
|
|
2278
|
+
localCoordinate: IRuntimeCoordinate;
|
|
2279
|
+
/** Wire dictionary version; the handshake rejects a client on a mismatch. */
|
|
2280
|
+
dictionaryVersion: string;
|
|
2281
|
+
/** Accepted level(s) — a single level is strict, an array is a negotiable allowed set. */
|
|
2282
|
+
securityLevel: ESecurityLevel | readonly ESecurityLevel[];
|
|
2283
|
+
/** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */
|
|
2284
|
+
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
2285
|
+
}
|
|
2286
|
+
interface IExchangeAcceptorConfig {
|
|
2287
|
+
security: IExchangeAcceptorSecurity;
|
|
2288
|
+
/** The runtime that executes an inbound action wire and produces its result. */
|
|
2289
|
+
runtime: ActionRuntime;
|
|
3085
2290
|
}
|
|
3086
2291
|
/**
|
|
3087
|
-
*
|
|
3088
|
-
* {@link
|
|
3089
|
-
*
|
|
3090
|
-
*
|
|
2292
|
+
* Acceptor (accept-in) side of the secure exchange protocol — the HTTP counterpart to
|
|
2293
|
+
* {@link AcceptorSecureSession}. Each POST body is one {@link decodeExchangeRequest} envelope; the
|
|
2294
|
+
* acceptor drives the server handshake over the two `hs` POSTs (correlated by `hsid`, since stateless
|
|
2295
|
+
* requests can't rely on channel ordering), mints a session **token** on accept, and on every later `act`
|
|
2296
|
+
* POST resolves the session by token, decrypts the body (at `encrypted`), routes it through the runtime,
|
|
2297
|
+
* and returns the (encrypted) result inline as the reply.
|
|
2298
|
+
*
|
|
2299
|
+
* Sessions and in-flight handshakes are held in memory — fine for a single-instance server. (Surviving a
|
|
2300
|
+
* Durable-Object eviction would persist each token's `keyMaterial` and re-derive the key on a miss, the
|
|
2301
|
+
* same primitive `AcceptorSecureSession.rehydrate` uses; left as a follow-up.)
|
|
3091
2302
|
*/
|
|
3092
|
-
declare class
|
|
3093
|
-
private readonly
|
|
3094
|
-
readonly
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
2303
|
+
declare class ExchangeAcceptor {
|
|
2304
|
+
private readonly _security;
|
|
2305
|
+
private readonly _runtime;
|
|
2306
|
+
private readonly _allowedLevels;
|
|
2307
|
+
private readonly _noneAllowed;
|
|
2308
|
+
private readonly _pendingHandshakes;
|
|
2309
|
+
private readonly _sessions;
|
|
2310
|
+
constructor(config: IExchangeAcceptorConfig);
|
|
2311
|
+
/** Process one POST body (an exchange envelope), returning the reply body to send back. */
|
|
2312
|
+
handlePost(body: string): Promise<string>;
|
|
2313
|
+
private _handleHandshake;
|
|
2314
|
+
private _handleAction;
|
|
2315
|
+
private _err;
|
|
3099
2316
|
}
|
|
3100
2317
|
//#endregion
|
|
3101
2318
|
//#region src/ActionRuntime/Transport/SecureSession/exchangeProtocol.d.ts
|
|
@@ -3372,5 +2589,512 @@ interface IActionPayload_Result_JsonObject<DOM extends IActionDomain = IActionDo
|
|
|
3372
2589
|
type TActionPayload_Any_Instance<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = ActionPayload_Request<DOM, ID> | ActionPayload_Result<DOM, ID> | ActionPayload_Progress<DOM, ID>;
|
|
3373
2590
|
type TActionPayload_Any_JsonObject<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = IActionPayload_Request_JsonObject<DOM, ID> | IActionPayload_Progress_JsonObject<DOM, ID> | IActionPayload_Result_JsonObject<DOM, ID>;
|
|
3374
2591
|
//#endregion
|
|
3375
|
-
|
|
3376
|
-
|
|
2592
|
+
//#region src/ActionRuntime/Handler/ActionHandler.types.d.ts
|
|
2593
|
+
declare enum EActionHandlerType {
|
|
2594
|
+
peer = "peer",
|
|
2595
|
+
local = "local"
|
|
2596
|
+
}
|
|
2597
|
+
interface IActionHandler_Json<T extends EActionHandlerType> {
|
|
2598
|
+
type: T;
|
|
2599
|
+
}
|
|
2600
|
+
interface IActionHandler_Peer_Json extends IActionHandler_Json<EActionHandlerType.peer> {
|
|
2601
|
+
client: IRuntimeCoordinate;
|
|
2602
|
+
}
|
|
2603
|
+
interface IActionHandler_Local_Json extends IActionHandler_Json<EActionHandlerType.local> {}
|
|
2604
|
+
type TActionHandler_Json = IActionHandler_Local_Json | IActionHandler_Peer_Json;
|
|
2605
|
+
interface IHandleActionOptions {
|
|
2606
|
+
timeout?: number;
|
|
2607
|
+
targetPeer?: RuntimeCoordinate;
|
|
2608
|
+
targetLocalRuntime?: ActionRuntime;
|
|
2609
|
+
}
|
|
2610
|
+
interface IExecuteActionOptions<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends IHandleActionOptions {
|
|
2611
|
+
listeners?: TRunningActionUpdateListener<DOM, ID>[];
|
|
2612
|
+
}
|
|
2613
|
+
interface IActionHandler_Base<T extends EActionHandlerType> {
|
|
2614
|
+
cuid: string;
|
|
2615
|
+
handlerType: T;
|
|
2616
|
+
getActionRouter: () => ActionRouter<any>;
|
|
2617
|
+
}
|
|
2618
|
+
/**
|
|
2619
|
+
*
|
|
2620
|
+
* LOCAL ACTION HANDLER
|
|
2621
|
+
*
|
|
2622
|
+
*/
|
|
2623
|
+
interface IHandleActionOptions_Local extends IHandleActionOptions {}
|
|
2624
|
+
interface IActionHandler_Local extends IActionHandler_Base<EActionHandlerType.local> {
|
|
2625
|
+
handleActionRequest: <DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions_Local) => Promise<RunningAction<DOM, ID>>;
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
*
|
|
2629
|
+
* PEER-LINK ACTION HANDLER
|
|
2630
|
+
*
|
|
2631
|
+
*/
|
|
2632
|
+
interface IHandleActionOptions_Peer extends IHandleActionOptions {}
|
|
2633
|
+
interface IActionHandler_Peer extends IActionHandler_Base<EActionHandlerType.peer> {
|
|
2634
|
+
peerClient: RuntimeCoordinate;
|
|
2635
|
+
handleActionRequest: <DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions_Peer) => Promise<RunningAction<DOM, ID>>;
|
|
2636
|
+
_setIncomingActionDataListener(listener: (json: TActionPayload_Any_JsonObject<any>) => void): void;
|
|
2637
|
+
}
|
|
2638
|
+
/**
|
|
2639
|
+
*
|
|
2640
|
+
* COMBINED
|
|
2641
|
+
*
|
|
2642
|
+
*/
|
|
2643
|
+
type TActionHandler = IActionHandler_Local | IActionHandler_Peer;
|
|
2644
|
+
//#endregion
|
|
2645
|
+
//#region src/ActionDefinition/Action/Payload/ActionPayload_Request.d.ts
|
|
2646
|
+
declare class ActionPayload_Request<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends ActionPayload<EActionPayloadType.request, DOM, ID> {
|
|
2647
|
+
readonly input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
2648
|
+
readonly inputHash: string;
|
|
2649
|
+
_callSite?: string;
|
|
2650
|
+
constructor(params: {
|
|
2651
|
+
context: ActionContext<DOM, ID>;
|
|
2652
|
+
}, input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"], data: IActionPayload_Data_Base);
|
|
2653
|
+
successResult(...args: [TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]] extends [never] ? [] | [output: TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]] : [output: TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]]): ActionPayload_Result<DOM, ID>;
|
|
2654
|
+
errorResult(err: TInferActionError<DOM["actionSchema"][ID]>): ActionPayload_Result<DOM, ID>;
|
|
2655
|
+
progress(progress: TActionProgress): ActionPayload_Progress<DOM, ID>;
|
|
2656
|
+
toJsonObject(): IActionPayload_Request_JsonObject<DOM, ID>;
|
|
2657
|
+
toJsonString(): string;
|
|
2658
|
+
runToOutput(options?: IExecuteActionOptions<DOM, ID>): Promise<TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]>;
|
|
2659
|
+
runToResultPayload(options?: IExecuteActionOptions<DOM, ID>): Promise<ActionPayload_Result<DOM, ID>>;
|
|
2660
|
+
run(options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>>;
|
|
2661
|
+
}
|
|
2662
|
+
//#endregion
|
|
2663
|
+
//#region src/ActionDefinition/Action/Core/ActionCore.d.ts
|
|
2664
|
+
declare class ActionCore<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends ActionBase<EActionForm.core, DOM, ID> implements IActionCore<DOM, ID> {
|
|
2665
|
+
readonly _domain: ActionDomain<DOM>;
|
|
2666
|
+
readonly form = EActionForm.core;
|
|
2667
|
+
constructor(_domain: ActionDomain<DOM>, id: ID);
|
|
2668
|
+
is<ACT extends IActionBase<any, any, any>>(action: ACT | unknown | null | undefined): action is TNarrowActionType<DOM, ACT, ID>;
|
|
2669
|
+
toJsonObject(): IActionBase_JsonObject<EActionForm.core, DOM, ID>;
|
|
2670
|
+
request(...args: [TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"]] extends [never] ? [input?: never] : [input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"]]): ActionPayload_Request<DOM, ID>;
|
|
2671
|
+
deserializeInput(serialized: TInferInputFromSchema<DOM["actionSchema"][ID]>["SerdeInput"]): TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
2672
|
+
serializeInput(raw: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"]): TInferInputFromSchema<DOM["actionSchema"][ID]>["SerdeInput"];
|
|
2673
|
+
validateInput(input: unknown): TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
2674
|
+
validateOutput(output: unknown): TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"];
|
|
2675
|
+
}
|
|
2676
|
+
//#endregion
|
|
2677
|
+
//#region src/ActionRuntime/ActionRuntime.d.ts
|
|
2678
|
+
declare class ActionRuntime {
|
|
2679
|
+
private _coordinate;
|
|
2680
|
+
readonly timeCreated: number;
|
|
2681
|
+
readonly runtimeInfo: IRuntimeMeta;
|
|
2682
|
+
private readonly actionRouter;
|
|
2683
|
+
private readonly _pendingRunningActions;
|
|
2684
|
+
private readonly _registeredPeerHandlers;
|
|
2685
|
+
private _applied;
|
|
2686
|
+
static getDefault(): ActionRuntime;
|
|
2687
|
+
constructor(coordinate: RuntimeCoordinate);
|
|
2688
|
+
get coordinate(): RuntimeCoordinate;
|
|
2689
|
+
specifyRuntimeCoordinate(specifics: IRuntimeCoordinateSpecifics & {
|
|
2690
|
+
envId?: string;
|
|
2691
|
+
}): void;
|
|
2692
|
+
registerRunningAction(ra: RunningAction<any, any>): void;
|
|
2693
|
+
resolveIncomingActionPayload(json: TActionPayload_Any_JsonObject<any, any>): void;
|
|
2694
|
+
/**
|
|
2695
|
+
* Handle an incoming action wire (e.g. from a transport layer), route it to
|
|
2696
|
+
* the correct handler, and return the response. The most specific handler
|
|
2697
|
+
* match is chosen (action-ID-specific beats domain-wildcard).
|
|
2698
|
+
*/
|
|
2699
|
+
handleActionPayloadWire<D extends IActionDomain, ID extends keyof D["actionSchema"] & string>(wire: TActionPayload_Any_JsonObject<D, ID>): Promise<RunningAction<D, ID>>;
|
|
2700
|
+
handleActionPayloadWire(wire: unknown): Promise<RunningAction<any, any>>;
|
|
2701
|
+
handleActionPayload<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: TActionPayload_Any_Instance<DOM, ID>, options?: Omit<IHandleActionOptions, "targetLocalRuntime">): Promise<RunningAction<DOM, ID>>;
|
|
2702
|
+
/**
|
|
2703
|
+
* @internal
|
|
2704
|
+
*
|
|
2705
|
+
* Return the first handler registered for the given action, or `undefined`
|
|
2706
|
+
* if none has been registered (action-ID-specific beats domain-wildcard).
|
|
2707
|
+
*/
|
|
2708
|
+
_getHandlerForAction<ACT extends TActionPayload_Any_Instance<any, any>>(action: ACT, options?: Omit<IHandleActionOptions, "targetLocalRuntime">): TActionHandler | undefined;
|
|
2709
|
+
getHandlerForActionOrThrow<ACT extends TActionPayload_Any_Instance<any, any>>(action: ACT, options?: Omit<IHandleActionOptions, "localRuntime">): TActionHandler;
|
|
2710
|
+
/**
|
|
2711
|
+
* Register one or more handlers. Each handler's own `actionRouter` defines
|
|
2712
|
+
* which domains/actions it handles — those routing keys are mirrored into
|
|
2713
|
+
* this runtime's router so the same action can be served by multiple handlers.
|
|
2714
|
+
* Duplicate registrations (same handler cuid for the same key) are skipped.
|
|
2715
|
+
*/
|
|
2716
|
+
addHandlers(handlers: TActionRuntimeHandler[]): this;
|
|
2717
|
+
/**
|
|
2718
|
+
* @internal Low-level primitive — the public way to open a connection is `connectChannel`, which
|
|
2719
|
+
* derives routing from a channel and binds the crypto identity for you. This stays as the raw building
|
|
2720
|
+
* block it sits on (it restates domain lists by hand) and is not part of the supported surface.
|
|
2721
|
+
*
|
|
2722
|
+
* Declare an external "backend client" in one call: build an
|
|
2723
|
+
* {@link ConnectorHandler} for `externalCoordinate` carrying the given
|
|
2724
|
+
* `transports`, route the listed `domains`/`actions` to it, register it (plus any
|
|
2725
|
+
* `localHandlers` — e.g. server→client push handlers that share the same channel)
|
|
2726
|
+
* on this runtime, and `apply()`. Returns the external handler so the caller can
|
|
2727
|
+
* later `clearTransportCache()` it.
|
|
2728
|
+
*/
|
|
2729
|
+
connectTo(externalCoordinate: RuntimeCoordinate, options: {
|
|
2730
|
+
transports: Transport[];
|
|
2731
|
+
domains?: ActionDomain<any>[];
|
|
2732
|
+
actions?: ActionCore<any, any>[];
|
|
2733
|
+
localHandlers?: TActionRuntimeHandler[];
|
|
2734
|
+
defaultTimeout?: number;
|
|
2735
|
+
}): ConnectorHandler;
|
|
2736
|
+
private applyRuntimeForDomain;
|
|
2737
|
+
/**
|
|
2738
|
+
* Register this runtime with all root domains covered by its currently-added handlers,
|
|
2739
|
+
* making it eligible to execute actions dispatched from those domains.
|
|
2740
|
+
* After apply() is called, any subsequent addHandlers() calls also auto-register.
|
|
2741
|
+
*/
|
|
2742
|
+
apply(): this;
|
|
2743
|
+
/**
|
|
2744
|
+
* Find the best registered external handler that can reach `originClient` directly.
|
|
2745
|
+
* Used to locate the return-path channel for dispatching results back to the action origin.
|
|
2746
|
+
* Returns `undefined` if no handler matches (score > 0 required, i.e. at least id must match).
|
|
2747
|
+
*
|
|
2748
|
+
* A handler that currently holds the origin's *live* connection always wins, regardless of its
|
|
2749
|
+
* coordinate score — owning the live socket bound to the origin's exact coordinate (set from the
|
|
2750
|
+
* handshake) is a strictly more precise match than any env-level `peerClient` score. This lets one
|
|
2751
|
+
* server accept clients of *several* envs over a single acceptor (a multi-role Durable Object): the
|
|
2752
|
+
* result/push routes back over the carrier the client actually connected on even when the handler's
|
|
2753
|
+
* `clientEnv` is unset or names a different env. Only when no handler owns a live connection do we fall
|
|
2754
|
+
* back to the plain best-coordinate-score pick (the offline-return and connector-only cases).
|
|
2755
|
+
*/
|
|
2756
|
+
getReturnHandlerForOrigin(originClient: RuntimeCoordinate): PeerLinkHandler | undefined;
|
|
2757
|
+
resetRuntime(): void;
|
|
2758
|
+
private _trySetupReturnDispatch;
|
|
2759
|
+
}
|
|
2760
|
+
//#endregion
|
|
2761
|
+
//#region src/ActionDefinition/Domain/ActionDomain.d.ts
|
|
2762
|
+
type TActionMap<ACT_DOM extends IActionDomain> = { [K in keyof ACT_DOM["actionSchema"] & string]: ActionCore<ACT_DOM, K> };
|
|
2763
|
+
declare class ActionDomain<ACT_DOM extends IActionDomain = IActionDomain> extends ActionDomainBase<ACT_DOM> {
|
|
2764
|
+
private _rootDomain;
|
|
2765
|
+
private readonly _actionMap;
|
|
2766
|
+
constructor(definition: ACT_DOM, {
|
|
2767
|
+
rootDomain
|
|
2768
|
+
}: {
|
|
2769
|
+
rootDomain: ActionRootDomain<any>;
|
|
2770
|
+
});
|
|
2771
|
+
get rootDomain(): ActionRootDomain<any>;
|
|
2772
|
+
/**
|
|
2773
|
+
* @internal
|
|
2774
|
+
* All action observers that should see actions on this domain: the root domain's
|
|
2775
|
+
* observers plus this subdomain's own. Mirrors the listener set the local-dispatch
|
|
2776
|
+
* path assembles in `runAction`/`_runAction`, so inbound actions (pushed from a
|
|
2777
|
+
* backend or another client) can be wired up identically and surface in devtools.
|
|
2778
|
+
*/
|
|
2779
|
+
_collectActionObservers(): TRunningActionUpdateListener<any, any>[];
|
|
2780
|
+
_registerRuntime(runtime: ActionRuntime): void;
|
|
2781
|
+
createChildDomain<SUB_DOM extends IActionDomainChildOptions>(subDomainDef: SUB_DOM & { [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never }): ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>>;
|
|
2782
|
+
get action(): TActionMap<ACT_DOM>;
|
|
2783
|
+
actionsMap(): TActionMap<ACT_DOM>;
|
|
2784
|
+
actionForId<ID extends keyof ACT_DOM["actionSchema"] & string>(id: ID): ActionCore<ACT_DOM, ID>;
|
|
2785
|
+
wrapAsPartialLocalHandler(wrappedActionExecutor: Partial<TWrappableDomainActionHandler<ACT_DOM>>): ActionLocalHandler;
|
|
2786
|
+
wrapAsLocalHandler(wrappedActionExecutor: TWrappableDomainActionHandler<ACT_DOM>): ActionLocalHandler;
|
|
2787
|
+
hydrateContext<ID extends keyof ACT_DOM["actionSchema"] & string>(id: ID, contextData: IActionContext_Data_JsonObject): ActionContext<ACT_DOM, ID>;
|
|
2788
|
+
isDomainAction<ACT extends IActionBase<any, ACT_DOM, any>>(action: ACT | unknown | null | undefined): action is TDistributedDomainActions<ACT_DOM, ACT>;
|
|
2789
|
+
hydrateRequestPayload<ID extends keyof ACT_DOM["actionSchema"] & string, P extends IActionPayload_Request_JsonObject<ACT_DOM, ID>>(serialized: P): TDistributeActionPayload_Request<ACT_DOM, ID>;
|
|
2790
|
+
hydrateResultPayload<ID extends keyof ACT_DOM["actionSchema"] & string, R extends IActionPayload_Result_JsonObject<ACT_DOM, ID>>(serialized: R): TDistributeActionPayload_Result<ACT_DOM, ID>;
|
|
2791
|
+
hydrateAnyAction<ID extends keyof ACT_DOM["actionSchema"] & string, AJ extends TAction_Any_JsonObject<ACT_DOM, ID>>(actionJson: AJ): TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;
|
|
2792
|
+
runAction<ID extends keyof ACT_DOM["actionSchema"] & string, ACT extends ActionPayload_Request<ACT_DOM, ID>>(request: ACT, options?: IExecuteActionOptions<ACT_DOM, ID>): Promise<RunningAction<ACT_DOM, ID>>;
|
|
2793
|
+
private createActionMap;
|
|
2794
|
+
}
|
|
2795
|
+
//#endregion
|
|
2796
|
+
//#region src/ActionDefinition/Action/ActionBase.types.d.ts
|
|
2797
|
+
declare enum EActionForm {
|
|
2798
|
+
core = "core",
|
|
2799
|
+
context = "context",
|
|
2800
|
+
data = "data"
|
|
2801
|
+
}
|
|
2802
|
+
interface INiceActionIdAndDomain<DOM extends IActionDomain = IActionDomain> {
|
|
2803
|
+
domain: DOM["domain"];
|
|
2804
|
+
id: keyof DOM["actionSchema"] & string;
|
|
2805
|
+
}
|
|
2806
|
+
interface IActionBase<FORM extends EActionForm, DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends INiceActionIdAndDomain<DOM> {
|
|
2807
|
+
id: ID;
|
|
2808
|
+
form: FORM;
|
|
2809
|
+
_domain: ActionDomain<DOM>;
|
|
2810
|
+
allDomains: DOM["allDomains"];
|
|
2811
|
+
schema: DOM["actionSchema"][ID];
|
|
2812
|
+
}
|
|
2813
|
+
interface IActionBase_JsonObject<FORM extends EActionForm = EActionForm, DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> {
|
|
2814
|
+
form: FORM;
|
|
2815
|
+
domain: DOM["domain"];
|
|
2816
|
+
allDomains: DOM["allDomains"];
|
|
2817
|
+
id: ID;
|
|
2818
|
+
}
|
|
2819
|
+
//#endregion
|
|
2820
|
+
//#region src/ActionDefinition/Action/Action.combined.types.d.ts
|
|
2821
|
+
/**
|
|
2822
|
+
* Distributes a union ID into a proper discriminated union of ActionPayload_Request instances,
|
|
2823
|
+
* so that narrowing on `.id` also narrows `.input`.
|
|
2824
|
+
*/
|
|
2825
|
+
type TDistributeActionPayload_Request<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string> = ID extends keyof DOM["actionSchema"] & string ? ActionPayload_Request<DOM, ID> : never;
|
|
2826
|
+
/**
|
|
2827
|
+
* Distributes a union ID into a proper discriminated union of ActionPayload_Result instances,
|
|
2828
|
+
* so that narrowing on `.id` also narrows `.result`.
|
|
2829
|
+
*/
|
|
2830
|
+
type TDistributeActionPayload_Result<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string> = ID extends keyof DOM["actionSchema"] & string ? ActionPayload_Result<DOM, ID> : never;
|
|
2831
|
+
/**
|
|
2832
|
+
*
|
|
2833
|
+
* COMBINED JSON TYPES
|
|
2834
|
+
*
|
|
2835
|
+
*/
|
|
2836
|
+
type TAction_Any_JsonObject<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = IActionCore_JsonObject<DOM, ID> | TActionPayload_Any_JsonObject<DOM, ID> | IActionContext_JsonObject<DOM, ID>;
|
|
2837
|
+
/**
|
|
2838
|
+
*
|
|
2839
|
+
* UTILITY TYPES
|
|
2840
|
+
*
|
|
2841
|
+
*/
|
|
2842
|
+
type TDistributedDomainActions<DOM extends IActionDomain, ACT extends IActionBase<any, DOM, any>> = { [ID in keyof DOM["actionSchema"] & string]: TNarrowActionType<DOM, ACT, ID> }[keyof DOM["actionSchema"] & string];
|
|
2843
|
+
type TNarrowActionType<DOM extends IActionDomain, ACT extends IActionBase<any, DOM, any>, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = ACT extends ActionPayload_Result<any> ? ActionPayload_Result<DOM, ID> : ACT extends ActionPayload_Request<any> ? ActionPayload_Request<DOM, ID> : ACT extends ActionPayload_Progress<any> ? ActionPayload_Progress<DOM, ID> : ACT extends ActionCore<any> ? ActionCore<DOM, ID> : never;
|
|
2844
|
+
type TNarrowActionJsonTypeToActionInstanceType<DOM extends IActionDomain, ACT extends TAction_Any_JsonObject<DOM>, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> = ACT extends IActionPayload_Request_JsonObject<any> ? ActionPayload_Request<DOM, ID> : ACT extends IActionPayload_Result_JsonObject<any> ? ActionPayload_Result<DOM, ID> : ACT extends IActionPayload_Progress_JsonObject<any> ? ActionPayload_Progress<DOM, ID> : ACT extends IActionCore_JsonObject<any> ? ActionCore<DOM, ID> : never;
|
|
2845
|
+
//#endregion
|
|
2846
|
+
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/AcceptorHandler.d.ts
|
|
2847
|
+
/** The codec shape `AcceptorHandler` uses to pack/unpack frames — same as the Link transport's. */
|
|
2848
|
+
type TActionChannelFormatMessage = IActionWireFormat;
|
|
2849
|
+
/** How a connection encodes its frames, remembered so we answer each client in its own dialect. */
|
|
2850
|
+
type TActionConnectionEncoding = "json" | "binary";
|
|
2851
|
+
/** A connection's restorable identity — what to persist so a binding survives transport eviction. */
|
|
2852
|
+
interface IAcceptorConnectionBinding {
|
|
2853
|
+
/** Full client coordinate, so `originClient` can be re-injected into frames that omit it. */
|
|
2854
|
+
client: IRuntimeCoordinate;
|
|
2855
|
+
encoding: TActionConnectionEncoding;
|
|
2856
|
+
/**
|
|
2857
|
+
* Secure-session state (set once a connection's handshake completes). Persist it alongside the
|
|
2858
|
+
* binding so an authenticated/encrypted connection resumes after eviction without re-handshaking —
|
|
2859
|
+
* the `keyMaterial` lets the server re-derive the shared key from its own persisted identity.
|
|
2860
|
+
*/
|
|
2861
|
+
secure?: {
|
|
2862
|
+
securityLevel: ESecurityLevel;
|
|
2863
|
+
linkedClientId: TTypeAndId;
|
|
2864
|
+
keyMaterial?: IHandshakeEncryptionKeyMaterial;
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Server-side secure-channel config. When set, each connection negotiates a level from
|
|
2869
|
+
* {@link securityLevel}: an `authenticated`/`encrypted` client must complete the handshake (and is then
|
|
2870
|
+
* bound to its *authenticated* coordinate) before any action frame is accepted. A `none` client (only
|
|
2871
|
+
* when `none` is in the allowed set) is accepted as-is with a self-asserted identity. For the
|
|
2872
|
+
* `encrypted` level the codec source should be a session factory (`createFormatMessage`).
|
|
2873
|
+
*/
|
|
2874
|
+
interface IAcceptorSecurity {
|
|
2875
|
+
/**
|
|
2876
|
+
* Accepted level(s). A single level is strict; an array is a negotiable allowed set — the server
|
|
2877
|
+
* adopts whichever level each client requests (e.g. `[none, authenticated, encrypted]` serves all
|
|
2878
|
+
* three over one endpoint).
|
|
2879
|
+
*/
|
|
2880
|
+
securityLevel: ESecurityLevel | readonly ESecurityLevel[];
|
|
2881
|
+
/** This server's crypto identity (verify + exchange key pairs, optionally persisted). */
|
|
2882
|
+
link: ClientCryptoKeyLink;
|
|
2883
|
+
/** This server's coordinate — its identity to clients during the handshake. */
|
|
2884
|
+
localCoordinate: IRuntimeCoordinate;
|
|
2885
|
+
/** Wire dictionary version; the handshake rejects a client on a mismatch. */
|
|
2886
|
+
dictionaryVersion: string;
|
|
2887
|
+
/** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */
|
|
2888
|
+
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
2889
|
+
}
|
|
2890
|
+
interface IAcceptorHandlerBaseOptions<TConn> {
|
|
2891
|
+
/**
|
|
2892
|
+
* Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env("web_app")`),
|
|
2893
|
+
* scored against an action's `originClient` to pick this handler when *no* handler holds the client's
|
|
2894
|
+
* live connection (the offline-return fallback). A handler that currently owns the live socket always
|
|
2895
|
+
* wins regardless, so this is optional: omit it for a multi-role server that accepts several client envs
|
|
2896
|
+
* over one acceptor — it then defaults to `RuntimeCoordinate.unknown` (scores 0 against every client).
|
|
2897
|
+
*/
|
|
2898
|
+
clientEnv?: RuntimeCoordinate;
|
|
2899
|
+
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
2900
|
+
send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;
|
|
2901
|
+
/**
|
|
2902
|
+
* The runtime this handler belongs to. When set, {@link AcceptorHandler.broadcast} can be called
|
|
2903
|
+
* without threading a runtime through each call. Optional — `pushToClient` still takes one explicitly.
|
|
2904
|
+
*/
|
|
2905
|
+
runtime?: ActionRuntime;
|
|
2906
|
+
/** Timeout (ms) applied to server-initiated actions awaiting a client response. */
|
|
2907
|
+
defaultTimeout?: number;
|
|
2908
|
+
/**
|
|
2909
|
+
* Called once when a connection is first bound to a client identity. Use it to persist the binding
|
|
2910
|
+
* for transports that can resume after eviction — e.g. a Durable Object's hibernatable WebSocket:
|
|
2911
|
+
* `(ws, binding) => ws.serializeAttachment(binding)` — then replay it via {@link AcceptorHandler.rehydrateConnection}
|
|
2912
|
+
* when the channel comes back.
|
|
2913
|
+
*/
|
|
2914
|
+
onConnectionBound?: (connection: TConn, binding: IAcceptorConnectionBinding) => void;
|
|
2915
|
+
/**
|
|
2916
|
+
* Enable the authenticated (optionally encrypted) handshake. When omitted, connections are trusted
|
|
2917
|
+
* as-is (identity self-asserted) — fine for dev / trusted networks.
|
|
2918
|
+
*/
|
|
2919
|
+
security?: IAcceptorSecurity;
|
|
2920
|
+
}
|
|
2921
|
+
/**
|
|
2922
|
+
* Provide exactly one codec source:
|
|
2923
|
+
* - `formatMessage` — a single shared codec for every connection (stateless, e.g. `createBinaryWireAdapter`).
|
|
2924
|
+
* - `createFormatMessage` — a per-connection factory for stateful codecs (e.g.
|
|
2925
|
+
* `createBinaryWireSessionFactory`, whose sessions hold correlation + identity state). Required for the
|
|
2926
|
+
* leanest binary wire; the handler creates and caches one codec per connection.
|
|
2927
|
+
*/
|
|
2928
|
+
type IAcceptorHandlerOptions<TConn> = IAcceptorHandlerBaseOptions<TConn> & ({
|
|
2929
|
+
formatMessage: TActionChannelFormatMessage;
|
|
2930
|
+
createFormatMessage?: never;
|
|
2931
|
+
} | {
|
|
2932
|
+
createFormatMessage: () => TActionChannelFormatMessage;
|
|
2933
|
+
formatMessage?: never;
|
|
2934
|
+
});
|
|
2935
|
+
/**
|
|
2936
|
+
* A connection-aware execution case (see {@link AcceptorHandler.forConnectionDomainCases}). It receives
|
|
2937
|
+
* the primed request plus a per-invocation `context` — whatever the wiring's context mapper produces from
|
|
2938
|
+
* the originating connection. The low-level handler passes the raw connection (`TConn | undefined`); the
|
|
2939
|
+
* higher-level `serveChannel` enriches it into an `IConnectionContext` (state + broadcast + pushBack). A
|
|
2940
|
+
* case may return the action's raw output, a result payload, or nothing (auto-wrapped as an empty
|
|
2941
|
+
* success) — exactly like a local handler case.
|
|
2942
|
+
*/
|
|
2943
|
+
type TAcceptorCaseFn<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string, TCtx> = (action: TDistributeActionPayload_Request<DOM, ID>, context: TCtx) => ReturnType<THandleActionExecutionFn<DOM, ID>> | void;
|
|
2944
|
+
/**
|
|
2945
|
+
* The connection-aware case the bare {@link AcceptorHandler} serves: its `context` is the originating
|
|
2946
|
+
* client's live connection (resolved from the request's `originClient`, `undefined` if the socket is
|
|
2947
|
+
* gone). It's {@link TAcceptorCaseFn} fixed to `TConn | undefined` — the un-enriched shape used by
|
|
2948
|
+
* {@link AcceptorHandler.forConnectionDomainCases} and `acceptChannelConnections`.
|
|
2949
|
+
*/
|
|
2950
|
+
type TAcceptorConnectionCaseFn<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string, TConn> = TAcceptorCaseFn<DOM, ID, TConn | undefined>;
|
|
2951
|
+
/**
|
|
2952
|
+
* Server-side handler for backends that accept many client connections over a single open channel
|
|
2953
|
+
* (WebSockets, Durable Objects, …). It is transport-agnostic: you feed it inbound frames with
|
|
2954
|
+
* {@link receive} and tell it how to write outbound frames via the `send` option.
|
|
2955
|
+
*
|
|
2956
|
+
* Add it alongside your local execution handler:
|
|
2957
|
+
* ```ts
|
|
2958
|
+
* const serverHandler = createAcceptorHandler({ clientEnv, formatMessage, send: (ws, f) => ws.send(f) });
|
|
2959
|
+
* runtime.addHandlers([localHandler, serverHandler]);
|
|
2960
|
+
* // per inbound message (e.g. a Durable Object's webSocketMessage):
|
|
2961
|
+
* serverHandler.receive(ws, message);
|
|
2962
|
+
* ```
|
|
2963
|
+
*
|
|
2964
|
+
* Inbound requests route to your local handler; the runtime's return dispatch then calls this
|
|
2965
|
+
* handler back (it is an external handler keyed to `clientEnv`) to send the result to the originating
|
|
2966
|
+
* connection. The handler keeps a per-connection identity registry so each result lands on the right
|
|
2967
|
+
* socket, and remembers each connection's encoding so binary and JSON clients can share the channel.
|
|
2968
|
+
*
|
|
2969
|
+
* It registers an empty action router, so it is never chosen to *execute* an inbound request — only
|
|
2970
|
+
* to ferry results/pushes back out.
|
|
2971
|
+
*/
|
|
2972
|
+
declare class AcceptorHandler<TConn = unknown> extends PeerLinkHandler {
|
|
2973
|
+
/** Accept-in over a live (duplex) connection registry — it pushes results/broadcasts to bound sockets. */
|
|
2974
|
+
readonly canPush = true;
|
|
2975
|
+
private readonly _formatMessage?;
|
|
2976
|
+
private readonly _createFormatMessage?;
|
|
2977
|
+
private readonly _send;
|
|
2978
|
+
private readonly _runtime?;
|
|
2979
|
+
private readonly _serverTimeout;
|
|
2980
|
+
private _onConnectionBound?;
|
|
2981
|
+
private readonly _security?;
|
|
2982
|
+
/** Normalized accepted levels; whether `none` (plain) is allowed; whether any level needs a handshake. */
|
|
2983
|
+
private readonly _allowedLevels;
|
|
2984
|
+
private readonly _noneAllowed;
|
|
2985
|
+
private readonly _handshakeMode;
|
|
2986
|
+
private readonly _connByClient;
|
|
2987
|
+
private readonly _clientByConn;
|
|
2988
|
+
private readonly _connEncoding;
|
|
2989
|
+
private readonly _codecByConn;
|
|
2990
|
+
private readonly _sessionByConn;
|
|
2991
|
+
constructor(options: IAcceptorHandlerOptions<TConn>);
|
|
2992
|
+
/**
|
|
2993
|
+
* The codec for a connection: a per-connection session (cached) when a factory was provided, else
|
|
2994
|
+
* the single shared `formatMessage`.
|
|
2995
|
+
*/
|
|
2996
|
+
private _codecFor;
|
|
2997
|
+
/**
|
|
2998
|
+
* Register (or replace) the connection-bound persistence callback after construction. Used by
|
|
2999
|
+
* lifecycle helpers like {@link createHibernatableWsServerAdapter} so persistence and replay are
|
|
3000
|
+
* owned by one place instead of being split across the constructor options.
|
|
3001
|
+
*/
|
|
3002
|
+
setOnConnectionBound(onConnectionBound: (connection: TConn, binding: IAcceptorConnectionBinding) => void): void;
|
|
3003
|
+
/**
|
|
3004
|
+
* Feed one inbound frame from a connection into the runtime. Decodes text or binary, binds the
|
|
3005
|
+
* connection to the requesting client's identity, then routes it (requests execute locally;
|
|
3006
|
+
* results/progress resolve pending server-initiated actions).
|
|
3007
|
+
*/
|
|
3008
|
+
receive(connection: TConn, frame: string | ArrayBuffer | Uint8Array): void;
|
|
3009
|
+
private _receivePlain;
|
|
3010
|
+
/**
|
|
3011
|
+
* The secure session for a connection (built lazily on its first secure-mode frame), with the
|
|
3012
|
+
* handler-owned effects — raw send, identity binding + persistence, and inbound routing — wired in as
|
|
3013
|
+
* callbacks. The session owns all crypto/handshake/chain state; the handler keeps only the registry.
|
|
3014
|
+
*/
|
|
3015
|
+
private _sessionFor;
|
|
3016
|
+
/** Bind + persist a connection's authenticated identity once its handshake completes. */
|
|
3017
|
+
private _onConnectionAuthenticated;
|
|
3018
|
+
/** Decode a decrypted authenticated frame, inject the *authenticated* identity, and route it. */
|
|
3019
|
+
private _routeAuthedActionBytes;
|
|
3020
|
+
/**
|
|
3021
|
+
* Ensure an inbound request carries the client's identity and that this connection is bound to it,
|
|
3022
|
+
* so its result can be routed back. A session codec omits `originClient` after the first request, so
|
|
3023
|
+
* when it's missing we restore it from the (possibly rehydrated) binding instead. (Plain mode only;
|
|
3024
|
+
* secure mode binds the authenticated coordinate at handshake time.)
|
|
3025
|
+
*/
|
|
3026
|
+
private _resolveRequestIdentity;
|
|
3027
|
+
/**
|
|
3028
|
+
* Restore a connection→client binding without an inbound frame — for transports that resume after
|
|
3029
|
+
* eviction. Pair it with the {@link IAcceptorHandlerOptions.onConnectionBound} hook: persist
|
|
3030
|
+
* the binding there, then replay each live connection here when the channel comes back (e.g. a
|
|
3031
|
+
* Durable Object iterating `ctx.getWebSockets()` as it wakes from hibernation).
|
|
3032
|
+
*/
|
|
3033
|
+
rehydrateConnection(connection: TConn, binding: IAcceptorConnectionBinding): void;
|
|
3034
|
+
toJsonObject(): IActionHandler_Peer_Json;
|
|
3035
|
+
toHandlerRouteItem(): IActionRouteItemHandler;
|
|
3036
|
+
/** Forget a connection (call on socket close) so stale entries don't misroute later results. */
|
|
3037
|
+
dropConnection(connection: TConn): void;
|
|
3038
|
+
/** Live connection for a client coordinate, if currently registered. */
|
|
3039
|
+
getConnectionForClient(client: RuntimeCoordinate): TConn | undefined;
|
|
3040
|
+
/** This acceptor owns the origin's return path when it currently holds a live connection bound to it. */
|
|
3041
|
+
ownsLiveConnectionFor(origin: RuntimeCoordinate): boolean;
|
|
3042
|
+
/** Whether this acceptor currently tracks `connection` — used to pick the owning handler among several. */
|
|
3043
|
+
hasConnection(connection: TConn): boolean;
|
|
3044
|
+
/**
|
|
3045
|
+
* Send (and optionally await) a server-initiated action to a specific connected client. Pass the
|
|
3046
|
+
* connection token directly (e.g. the `ws`) or a client `RuntimeCoordinate` to look one up.
|
|
3047
|
+
*/
|
|
3048
|
+
pushToClient<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(runtime: ActionRuntime, target: TConn | RuntimeCoordinate, request: ActionPayload_Request<DOM, ID>, options?: {
|
|
3049
|
+
timeout?: number;
|
|
3050
|
+
}): RunningAction<DOM, ID>;
|
|
3051
|
+
/**
|
|
3052
|
+
* Build a local handler whose cases are connection-aware: each case receives the primed request and
|
|
3053
|
+
* the originating client's live connection (resolved from `originClient`), so handlers don't repeat
|
|
3054
|
+
* the `getConnectionForClient(action.context.originClient)` lookup. Cases may return raw output or
|
|
3055
|
+
* nothing, just like {@link ActionLocalHandler.forDomainActionCases}. Add the returned handler to the
|
|
3056
|
+
* runtime alongside this server handler:
|
|
3057
|
+
* ```ts
|
|
3058
|
+
* runtime.addHandlers([serverHandler.forConnectionDomainCases(domain, { … }), serverHandler]);
|
|
3059
|
+
* ```
|
|
3060
|
+
*/
|
|
3061
|
+
forConnectionDomainCases<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>, cases: { [ID in keyof FOR_DOM["actionSchema"] & string]?: TAcceptorConnectionCaseFn<FOR_DOM, ID, TConn> }): ActionLocalHandler;
|
|
3062
|
+
/**
|
|
3063
|
+
* Like {@link forConnectionDomainCases} but spanning several domains with one merged case map — used
|
|
3064
|
+
* by channel-derived wiring (`acceptChannelConnections` / `serveChannel`) where the channel's
|
|
3065
|
+
* `toAcceptor` domains are served together. Each domain takes only the cases whose ids it owns, so a
|
|
3066
|
+
* single map can cover several domains and unrelated ids are ignored.
|
|
3067
|
+
*
|
|
3068
|
+
* `mapContext` turns the resolved connection into whatever the case's second argument should be: the
|
|
3069
|
+
* raw connection for the low-level helper, or an enriched `IConnectionContext` for `serveChannel`. It's
|
|
3070
|
+
* called once per inbound action, after the originating connection is resolved.
|
|
3071
|
+
*/
|
|
3072
|
+
forConnectionDomainCasesMulti<TCtx>(domains: readonly ActionDomain<any>[], cases: Record<string, TAcceptorCaseFn<any, any, TCtx> | undefined>, mapContext: (connection: TConn | undefined, request: ActionPayload_Request<any, any>) => TCtx): ActionLocalHandler;
|
|
3073
|
+
/**
|
|
3074
|
+
* Fan a server-initiated request out to every currently-bound connection. A fresh request is built
|
|
3075
|
+
* per connection (each push mutates its own action context) and dispatched fire-and-forget. Pass
|
|
3076
|
+
* `except` to skip the originating socket and `where` to filter by connection (e.g. read its
|
|
3077
|
+
* attachment for a role). Iterating bound connections (rather than every accepted socket) skips
|
|
3078
|
+
* sockets that are still mid-handshake and so can't yet receive a frame.
|
|
3079
|
+
*/
|
|
3080
|
+
broadcast<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(makeRequest: () => ActionPayload_Request<DOM, ID>, options?: {
|
|
3081
|
+
runtime?: ActionRuntime;
|
|
3082
|
+
except?: TConn | null;
|
|
3083
|
+
where?: (connection: TConn) => boolean;
|
|
3084
|
+
timeout?: number;
|
|
3085
|
+
onError?: (error: unknown, connection: TConn) => void;
|
|
3086
|
+
}): void;
|
|
3087
|
+
sendReturnPayload(payload: TActionPayload_Any_Instance<any, any>, config: {
|
|
3088
|
+
targetLocalRuntime: ActionRuntime;
|
|
3089
|
+
}): Promise<boolean>;
|
|
3090
|
+
handleActionRequest<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions): Promise<RunningAction<DOM, ID>>;
|
|
3091
|
+
private _dispatch;
|
|
3092
|
+
private _sendPayload;
|
|
3093
|
+
private _bindConnection;
|
|
3094
|
+
private _resolveConnection;
|
|
3095
|
+
private _resolveSingleConnection;
|
|
3096
|
+
}
|
|
3097
|
+
declare const createAcceptorHandler: <TConn = unknown>(options: IAcceptorHandlerOptions<TConn>) => AcceptorHandler<TConn>;
|
|
3098
|
+
//#endregion
|
|
3099
|
+
export { httpAcceptorCarrier as $, createInMemoryTofuVerifyKeyResolver as $n, TCarrier as $t, TActionResultOutcome as A, TOnResolveIncomingResponseJson as An, IActionCore_JsonObject as Ar, IHibernatableWsServerAdapterOptions as At, decodeExchangeReply as B, Transport as Bn, TPossibleDomainIdList as Br, TChannelAcceptorCases as Bt, IActionProgress_Custom as C, IUpdateActionRunConfig_Output as Cn, IRuntimeCoordinate as Cr, serveChannel as Ct, TActionPayload_Any_Instance as D, TOnResolveIncomingRequest as Dn, TRuntimeCoordinateEnvId as Dr, TAcceptorCarrier as Dt, IActionRouteItemHandler as E, TOnResolveAnyIncomingActionData_Json as En, RuntimeCoordinate as Er, IExchangeAcceptorCarrier as Et, decodeActionFrame as F, TTransportStatusInfo as Fn, TActionDomainSchema as Fr, createConnectionStateStore as Ft, IExchangeAcceptorSecurity as G, IClientHandshakeConfig as Gn, TActionSchemaOptions as Gr, defineChannel as Gt, encodeExchange as H, createSecureAcceptorHandler as Hn, EActionResponseMode as Hr, acceptChannel as Ht, EErrId_NiceAction as I, TTransportStatusInfo_GetTransport_Output as In, TDomainActionId as Ir, IAcceptChannelOptions as It, IHttpCarrierOptions as J, IHandshakeEncryptionKeyMaterial as Jn, IActionWireFormat as Jt, EErrId_NiceTransport as K, IClientVerifyKeyResolveInput as Kn, TActionSerializationDefinition as Kr, IBinaryWireSessionOptions as Kt, err_nice_action as L, TUpdateActionRunConfig as Ln, TInferInputFromSchema as Lr, IActionChannel as Lt, isActionPayload_Request_JsonObject as M, TSendReturnDataMethod as Mn, IActionDomainChildOptions as Mr, ConnectionStateStore as Mt, isActionPayload_Any_JsonObject as N, TTransportCache as Nn, IActionRootDomain as Nr, IConnectionAttachment as Nt, TActionPayload_Any_JsonObject as O, TOnResolveIncomingRequestJson as On, TRuntimeCoordinateStringId as Or, isExchangeAcceptorCarrier as Ot, IActionFrameDecoder as P, TTransportInitializationFinishedInfo as Pn, TActionDomainChildDef as Pr, IConnectionStateStoreOptions as Pt, IHttpAcceptorCarrierOptions as Q, createClientHandshake as Qn, IExchangeCarrierSource as Qt, TExchangeReply as R, TransportConnection as Rn, TInferOutputFromSchema as Rr, IConnectChannelOptions as Rt, IActionPayload_Result_JsonObject as S, ITransportStatusInfo_Unsupported as Sn, ActionPayload_Progress as Sr, IServeConnectionStateOptions as St, IActionProgress_Percentage as T, TOnResolveAnyIncomingActionData as Tn, IRuntimeFullCoordinates as Tr, IDuplexAcceptorCarrier as Tt, ExchangeAcceptor as U, EHandshakeMessageType as Un, TInferActionError as Ur, acceptChannelConnections as Ut, decodeExchangeRequest as V, ISecureAcceptorHandlerOptions as Vn, ActionSchema as Vr, TChannelPushHandlers as Vt, IExchangeAcceptorConfig as W, ESecurityLevel as Wn, actionSchema as Wr, connectChannel as Wt, TCarrierFetch as X, IServerHandshakeConfig as Xn, IDuplexCarrierSource as Xt, IHttpCarrierRequest as Y, IHandshakeResult as Yn, IDuplexCarrier as Yt, httpCarrier as Z, THandshakeMessage as Zn, IExchangeCarrier as Zt, IActionPayload_Data_Base as _, ITransportRouteInfo as _n, IRunningActionUpdate_Success as _r, TServeHostOptions as _t, TAcceptorConnectionCaseFn as a, ETransportStatus as an, ActionLocalHandler as ar, err_nice_transport_ws as at, IActionPayload_Request_JsonObject as b, ITransportStatusInfo_Initializing as bn, TRunningActionUpdateListener as br, IConnectionContext as bt, createAcceptorHandler as c, IActionTransportReady as cn, createActionRootDomain as cr, IRtcDataChannelLike as ct, ActionCore as d, IActionTransportResolvers as dn, ERunningActionFinishedType as dr, inMemoryCarrier as dt, TFrame$1 as en, createServerHandshake as er, IWsCarrierOptions as et, ActionPayload_Request as f, ISecureClientConfig as fn, ERunningActionState as fr, IInMemoryChannelPair as ft, IActionPayload_Base_JsonObject as g, ITransportRouteClientParams as gn, IRunningActionUpdate_Started as gr, IChannelHostAdapter as gt, IActionPayload_Base as h, ITransportRouteActionParams as hn, IRunningActionUpdate_Progress as hr, err_nice_external_client as ht, TAcceptorCaseFn as i, ETransportShape as in, runtimeLinkId as ir, EErrId_NiceTransport_WebSocket as it, isActionPayload_Result_JsonObject as j, TSendActionDataMethod as jn, IActionDomain as jr, createHibernatableWsServerAdapter as jt, TActionProgress as k, TOnResolveIncomingResponse as kn, IActionCore as kr, IDuplexConnectionRouter as kt, ActionDomain as l, IActionTransportReadyData_Base as ln, ActionRootDomain as lr, rtcDataChannelByteChannel as lt, EActionProgressType as m, ITransportMethod_SendActionData_Input as mn, IRunningActionUpdate_Abort as mr, createInMemoryChannelPair as mt, IAcceptorConnectionBinding as n, createConnectorHandler as nn, decodeHandshakeMessage as nr, IWsAcceptorCarrierOptions as nt, TActionChannelFormatMessage as o, IActionTransportDef as on, createLocalHandler as or, IRtcCarrierOptions as ot, EActionPayloadType as p, ITransportDispatchAction as pn, ERunningActionUpdateType as pr, IInMemoryServerEndpoint as pt, err_nice_transport as q, IClientVerifyKeyResolver as qn, TTransportedValue as qr, createBinaryWireSessionFactory as qt, IAcceptorHandlerOptions as r, PeerLinkHandler as rn, encodeHandshakeMessage as rr, wsAcceptorCarrier as rt, TActionConnectionEncoding as s, IActionTransportInitialized as sn, MaybePromise as sr, rtcCarrier as st, AcceptorHandler as t, ConnectorHandler as tn, createStorageTofuVerifyKeyResolver as tr, wsCarrier as tt, ActionRuntime as u, IActionTransportReadyData_Methods as un, RunningAction as ur, IInMemoryCarrier as ut, IActionPayload_Progress as v, ITransportStatusInfo_Base as vn, TRunningActionUpdate as vr, serveHost as vt, IActionProgress_None as w, TGetTransportFn as wn, IRuntimeCoordinateSpecifics as wr, IAcceptorAttachmentStore as wt, IActionPayload_Result as x, ITransportStatusInfo_Ready as xn, ActionPayload_Result as xr, IServeChannelOptions as xt, IActionPayload_Progress_JsonObject as y, ITransportStatusInfo_Failed as yn, TRunningActionUpdateFinished as yr, IChannelServer as yt, TExchangeRequest as z, ITransportConnectionContext as zn, TPossibleDomainId as zr, IConnectTransport as zt };
|
|
3100
|
+
//# sourceMappingURL=AcceptorHandler-BizUtq4u.d.mts.map
|