@nice-code/action 0.23.0 → 0.24.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 +18 -21
- package/build/{ActionPayload.types-B-OSg09t.d.mts → AcceptorHandler-11-QMdx2.d.mts} +967 -1346
- package/build/{ActionPayload.types-DIOeVapm.d.cts → AcceptorHandler-CxD0c1BE.d.cts} +967 -1346
- package/build/{ActionDevtoolsCore-BjbhFqc0.d.mts → ActionDevtoolsCore-37JP4bOG.d.cts} +2 -2
- package/build/{ActionDevtoolsCore-kk7oZBv9.d.cts → ActionDevtoolsCore-Cgq-go1R.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 +344 -0
- package/build/advanced/index.d.mts +344 -0
- package/build/advanced/index.mjs +88 -0
- package/build/advanced/index.mjs.map +1 -0
- package/build/{httpAcceptorCarrier-hYPuoNuP.cjs → createHibernatableWsServerAdapter-BNi4k9j3.cjs} +258 -470
- package/build/createHibernatableWsServerAdapter-BNi4k9j3.cjs.map +1 -0
- package/build/{httpAcceptorCarrier-DJVxzDVd.mjs → createHibernatableWsServerAdapter-C07RfUTH.mjs} +233 -421
- package/build/createHibernatableWsServerAdapter-C07RfUTH.mjs.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-C3S_bDkL.cjs +454 -0
- package/build/httpAcceptorCarrier-C3S_bDkL.cjs.map +1 -0
- package/build/httpAcceptorCarrier-DPBEuewS.mjs +401 -0
- package/build/httpAcceptorCarrier-DPBEuewS.mjs.map +1 -0
- package/build/index.cjs +69 -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 +1 -1
- package/build/platform/cloudflare/index.cjs.map +1 -1
- package/build/platform/cloudflare/index.d.cts +3 -3
- package/build/platform/cloudflare/index.d.mts +3 -3
- package/build/platform/cloudflare/index.mjs +1 -1
- 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,50 @@ 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 to route results/pushes back over this handler.
|
|
824
|
+
*/
|
|
825
|
+
clientEnv: RuntimeCoordinate;
|
|
826
|
+
/** This server's runtime — its coordinate is the server identity presented in the handshake. */
|
|
827
|
+
runtime: ActionRuntime;
|
|
828
|
+
/**
|
|
829
|
+
* One backing store for the server's crypto identity *and* its trust-on-first-use verify-key pins.
|
|
830
|
+
* Their keys don't collide, so a single adapter is enough; back it with persistent storage (e.g. a
|
|
831
|
+
* Durable Object's storage) so identity and pins survive eviction.
|
|
832
|
+
*/
|
|
833
|
+
storage: StorageAdapter;
|
|
834
|
+
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
835
|
+
send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;
|
|
836
|
+
/**
|
|
837
|
+
* The server's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storage`.
|
|
838
|
+
* Pass an existing link to share one identity across several acceptors on the same server (e.g. a
|
|
839
|
+
* WebSocket acceptor and a secure-HTTP {@link createActionFetchHandler}), so they present the same
|
|
840
|
+
* verify/exchange keys — avoiding a divergent-key race when two fresh links initialize concurrently.
|
|
841
|
+
*/
|
|
842
|
+
link?: ClientCryptoKeyLink;
|
|
843
|
+
/** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */
|
|
844
|
+
securityLevel?: ESecurityLevel | readonly ESecurityLevel[];
|
|
845
|
+
/** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storage`. */
|
|
846
|
+
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
847
|
+
/** Timeout (ms) applied to server-initiated actions awaiting a client response. */
|
|
848
|
+
defaultTimeout?: number;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Build an {@link AcceptorHandler} for the secure binary channel with the boilerplate folded in:
|
|
852
|
+
* it creates the {@link ClientCryptoKeyLink} and the storage-backed TOFU resolver from a single
|
|
853
|
+
* `storage`, installs the channel's per-connection codec, and assembles the `security` block
|
|
854
|
+
* from the runtime coordinate + channel version (accepting all three levels by default).
|
|
855
|
+
*
|
|
856
|
+
* For a hibernatable transport (e.g. a Durable Object), pair it with
|
|
857
|
+
* {@link createHibernatableWsServerAdapter} to wire persistence + replay.
|
|
858
|
+
*/
|
|
859
|
+
declare function createSecureAcceptorHandler<TConn = unknown>(options: ISecureAcceptorHandlerOptions<TConn>): AcceptorHandler<TConn>;
|
|
860
|
+
//#endregion
|
|
961
861
|
//#region src/ActionRuntime/Transport/Transport.d.ts
|
|
962
862
|
/**
|
|
963
863
|
* Context handed to a {@link Transport} definition when a handler builds a live connection from it.
|
|
@@ -967,9 +867,8 @@ interface ITransportConnectionContext {
|
|
|
967
867
|
resolvers?: IActionTransportResolvers;
|
|
968
868
|
}
|
|
969
869
|
/**
|
|
970
|
-
* Reusable transport definition.
|
|
971
|
-
* `
|
|
972
|
-
* `ConnectorHandler`. A single
|
|
870
|
+
* Reusable transport definition. Built by the internal `transport({ carrier, secure })` factory (which
|
|
871
|
+
* `connectChannel` / `serveChannel` drive) and passed to a `ConnectorHandler`. A single
|
|
973
872
|
* definition can be shared across multiple handlers — each handler builds its own live
|
|
974
873
|
* {@link TransportConnection} via {@link TransportConnection._createConnection}.
|
|
975
874
|
*/
|
|
@@ -1197,6 +1096,62 @@ interface IActionTransportDef<TYPE extends ETransportShape, INIT extends IAction
|
|
|
1197
1096
|
initialize: () => INIT;
|
|
1198
1097
|
}
|
|
1199
1098
|
//#endregion
|
|
1099
|
+
//#region src/ActionRuntime/Handler/PeerLink/PeerLinkHandler.d.ts
|
|
1100
|
+
/**
|
|
1101
|
+
* Shared base for every handler that routes a domain set to/from *another runtime* (a "peer") — the
|
|
1102
|
+
* unified peer-link concept. Both specializations extend this as siblings, differing only in *who
|
|
1103
|
+
* establishes the connection*, which is a transport trait, not a routing one:
|
|
1104
|
+
*
|
|
1105
|
+
* - {@link ConnectorHandler} — **dial-out**: this runtime opens connection(s) to one peer
|
|
1106
|
+
* over a transport stack (with caching + fallback). The classic "client → backend" link.
|
|
1107
|
+
* - {@link AcceptorHandler} — **accept-in**: connections are accepted from many peers and fed in
|
|
1108
|
+
* via `receive()`; it keeps a per-connection registry and can push to any of them.
|
|
1109
|
+
*
|
|
1110
|
+
* To the runtime there is no "client" vs "server" — both are peer-link handlers (`handlerType =
|
|
1111
|
+
* external`) keyed to a peer coordinate, chosen by the return-path dispatch via {@link sendReturnPayload}.
|
|
1112
|
+
*/
|
|
1113
|
+
declare abstract class PeerLinkHandler extends ActionHandler<EActionHandlerType.peer> implements IActionHandler_Peer {
|
|
1114
|
+
/** The peer runtime this handler links to (an env-only coordinate for an accept-in handler). */
|
|
1115
|
+
readonly peerClient: RuntimeCoordinate;
|
|
1116
|
+
readonly handlerType = EActionHandlerType.peer;
|
|
1117
|
+
/**
|
|
1118
|
+
* Whether this link can deliver an *unsolicited* frame to the peer (a result/progress pushed back on
|
|
1119
|
+
* the return path, or a `broadcast`). A duplex carrier (WebSocket/WebRTC/…) can; an exchange-only
|
|
1120
|
+
* carrier (HTTP) cannot — its reply must ride the response to its own request. The runtime's
|
|
1121
|
+
* return-path dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) skips handlers that can't
|
|
1122
|
+
* push, so an exchange-only handler is never asked to deliver one.
|
|
1123
|
+
*/
|
|
1124
|
+
abstract readonly canPush: boolean;
|
|
1125
|
+
readonly actionRouter: ActionRouter<true>;
|
|
1126
|
+
/** Listeners installed by the runtime (`resolveIncomingActionPayload`) for inbound peer frames. */
|
|
1127
|
+
private readonly _incomingActionDataListeners;
|
|
1128
|
+
constructor(peerCoordinate: RuntimeCoordinate);
|
|
1129
|
+
forDomain<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>): this;
|
|
1130
|
+
forAction<ACT_DOM extends IActionDomain, ID extends keyof ACT_DOM["actionSchema"] & string>(action: ActionCore<ACT_DOM, ID>): this;
|
|
1131
|
+
forActionIds<ACT_DOM extends IActionDomain, IDS extends ReadonlyArray<keyof ACT_DOM["actionSchema"] & string>>(domain: ActionDomain<ACT_DOM>, ids: IDS): this;
|
|
1132
|
+
_setIncomingActionDataListener(listener: (json: TActionPayload_Any_JsonObject<any, any>) => void): void;
|
|
1133
|
+
/** Hand a decoded inbound frame to the runtime (called by each specialization's receive path). */
|
|
1134
|
+
protected _emitIncoming(json: TActionPayload_Any_JsonObject<any, any>): void;
|
|
1135
|
+
/**
|
|
1136
|
+
* Dispatch a result/progress payload back to the action's origin peer over this link. The runtime's
|
|
1137
|
+
* return-path dispatch calls it on whichever peer-link handler best reaches `originClient`. Returns
|
|
1138
|
+
* `true` if it was sent, `false` if no channel was available.
|
|
1139
|
+
*/
|
|
1140
|
+
abstract sendReturnPayload(payload: TActionPayload_Any_Instance<any, any>, config: {
|
|
1141
|
+
targetLocalRuntime: ActionRuntime;
|
|
1142
|
+
}): Promise<boolean>;
|
|
1143
|
+
/**
|
|
1144
|
+
* Whether this handler currently holds a *live* connection bound to `origin`. The runtime's return-path
|
|
1145
|
+
* dispatch ({@link ActionRuntime.getReturnHandlerForOrigin}) prefers a handler that owns the origin's
|
|
1146
|
+
* connection over a mere coordinate match, so with several duplex acceptors a result/push routes back
|
|
1147
|
+
* over the carrier the client connected on. Defaults to `false`; an acceptor overrides it from its
|
|
1148
|
+
* connection registry.
|
|
1149
|
+
*/
|
|
1150
|
+
ownsLiveConnectionFor(_origin: RuntimeCoordinate): boolean;
|
|
1151
|
+
/** Release any long-lived connections this handler owns (a teardown). No-op by default. */
|
|
1152
|
+
clearTransportCache(): void;
|
|
1153
|
+
}
|
|
1154
|
+
//#endregion
|
|
1200
1155
|
//#region src/ActionRuntime/Handler/PeerLink/Connector/ConnectorHandler.types.d.ts
|
|
1201
1156
|
interface IConnectorHandlerConfig {
|
|
1202
1157
|
defaultTimeout?: number;
|
|
@@ -1242,180 +1197,98 @@ declare class ConnectorHandler extends PeerLinkHandler {
|
|
|
1242
1197
|
}
|
|
1243
1198
|
declare const createConnectorHandler: (config: IConnectorHandlerConfig) => ConnectorHandler;
|
|
1244
1199
|
//#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;
|
|
1200
|
+
//#region src/ActionRuntime/Transport/Carrier/Carrier.types.d.ts
|
|
1201
|
+
/**
|
|
1202
|
+
* Carrier shapes — the only transport-specific surface a new protocol must implement. The secure
|
|
1203
|
+
* session (handshake + frame crypto + codec) and the action routing on top of it are carrier-agnostic;
|
|
1204
|
+
* a carrier just moves frames. Two shapes capture every carrier:
|
|
1205
|
+
*
|
|
1206
|
+
* - {@link IDuplexCarrier} — a persistent, push-capable byte stream (WebSocket, WebRTC `RTCDataChannel`,
|
|
1207
|
+
* Bluetooth GATT, an in-memory pipe). Either side can send at any time, so it supports server→client
|
|
1208
|
+
* pushes (the return path + broadcast).
|
|
1209
|
+
* - {@link IExchangeCarrier} — a request → single-correlated-reply carrier with no unsolicited push
|
|
1210
|
+
* (HTTP, and anything request/response-shaped). The reply rides the response to its own request.
|
|
1211
|
+
*
|
|
1212
|
+
* Frames are `string` (text — handshake control messages and JSON action frames) or binary
|
|
1213
|
+
* (`Uint8Array`/`ArrayBuffer` — the optimized binary wire / encrypted frames).
|
|
1214
|
+
*/
|
|
1215
|
+
type TFrame$1 = string | Uint8Array | ArrayBuffer;
|
|
1216
|
+
/**
|
|
1217
|
+
* A bidirectional, push-capable byte stream. Reduces every duplex carrier to "open, send bytes, receive
|
|
1218
|
+
* bytes, close" — a WebSocket, a WebRTC data channel, a Bluetooth characteristic, or an in-memory pipe
|
|
1219
|
+
* all satisfy this, so the identical secure session runs over each.
|
|
1220
|
+
*/
|
|
1221
|
+
interface IDuplexCarrier {
|
|
1222
|
+
/** Resolves once the carrier is open and ready to send; rejects if it closes/errors before opening. */
|
|
1223
|
+
readonly ready: Promise<void>;
|
|
1224
|
+
/** Whether the carrier is currently open (a synchronous guard before `send`). */
|
|
1225
|
+
isOpen(): boolean;
|
|
1226
|
+
/** Write one frame to the peer. */
|
|
1227
|
+
send(frame: TFrame$1): void;
|
|
1339
1228
|
/**
|
|
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.
|
|
1229
|
+
* Register the carrier's handlers. Called exactly once by the session after `ready`. `onMessage`
|
|
1230
|
+
* receives every inbound frame; `onClose` fires when the carrier goes away.
|
|
1345
1231
|
*/
|
|
1346
|
-
|
|
1232
|
+
attach(handlers: {
|
|
1233
|
+
onMessage: (frame: TFrame$1) => void;
|
|
1234
|
+
onClose: () => void;
|
|
1235
|
+
onError?: (error: unknown) => void;
|
|
1236
|
+
}): void;
|
|
1237
|
+
/** Close the carrier deliberately (a teardown). */
|
|
1238
|
+
close(): void;
|
|
1239
|
+
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1240
|
+
readonly label?: string;
|
|
1347
1241
|
}
|
|
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>>;
|
|
1242
|
+
/**
|
|
1243
|
+
* A request → single-correlated-reply carrier with no unsolicited push (HTTP). One `exchange` sends a
|
|
1244
|
+
* frame and resolves with exactly the one reply frame for it; the carrier itself correlates them (the
|
|
1245
|
+
* HTTP transaction), so no correlation id is needed on the wire.
|
|
1246
|
+
*/
|
|
1247
|
+
interface IExchangeCarrier {
|
|
1248
|
+
/** Send one frame, await the single correlated reply frame. */
|
|
1249
|
+
exchange(frame: TFrame$1, opts?: {
|
|
1250
|
+
signal?: AbortSignal;
|
|
1251
|
+
}): Promise<TFrame$1>;
|
|
1252
|
+
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1253
|
+
readonly label?: string;
|
|
1363
1254
|
}
|
|
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;
|
|
1255
|
+
type TCarrier = IDuplexCarrier | IExchangeCarrier;
|
|
1256
|
+
/**
|
|
1257
|
+
* A reusable opener for a {@link IDuplexCarrier} plus the per-action metadata a duplex transport needs.
|
|
1258
|
+
* Built by the small carrier factories (`wsCarrier`, `rtcCarrier`, `inMemoryCarrier`) and passed as a
|
|
1259
|
+
* `carrier` to `connectChannel`'s transports (the internal `transport()` factory drives it) — so adding a
|
|
1260
|
+
* new carrier is "write one of these", nothing else.
|
|
1261
|
+
*/
|
|
1262
|
+
interface IDuplexCarrierSource {
|
|
1263
|
+
/** Open (or reuse) the carrier for an action. */
|
|
1264
|
+
open: (input: ITransportRouteActionParams) => IDuplexCarrier;
|
|
1265
|
+
/** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */
|
|
1266
|
+
getCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
1267
|
+
/** Devtools route info for an action routed over this carrier. */
|
|
1268
|
+
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
1269
|
+
/** Short carrier-kind label for the devtools chip (e.g. `"ws"`, `"webrtc"`, `"memory"`). */
|
|
1270
|
+
readonly carrierLabel: string;
|
|
1398
1271
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1272
|
+
/**
|
|
1273
|
+
* The exchange-shape counterpart to {@link IDuplexCarrierSource}: a reusable opener for an
|
|
1274
|
+
* {@link IExchangeCarrier} plus the per-action metadata an exchange transport needs. Built by
|
|
1275
|
+
* `httpCarrier` and passed as a `carrier` to `connectChannel`'s transports — adding a new request/reply
|
|
1276
|
+
* protocol is "write one of these". The `shape` tag lets the internal `transport()` factory pick the
|
|
1277
|
+
* duplex vs exchange transport.
|
|
1278
|
+
*/
|
|
1279
|
+
interface IExchangeCarrierSource {
|
|
1280
|
+
/** Discriminant so a generic factory can tell an exchange source from a duplex one. */
|
|
1281
|
+
readonly shape: "exchange";
|
|
1282
|
+
/** Open (or reuse) the carrier for an action. */
|
|
1283
|
+
open: (input: ITransportRouteActionParams) => IExchangeCarrier;
|
|
1284
|
+
/** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */
|
|
1285
|
+
getCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
1286
|
+
/** Devtools route info for an action routed over this carrier. */
|
|
1287
|
+
getRouteInfo?: (input: ITransportRouteActionParams) => ITransportRouteInfo;
|
|
1288
|
+
/** Short carrier-kind label for the devtools chip (e.g. `"http"`). */
|
|
1289
|
+
readonly carrierLabel: string;
|
|
1412
1290
|
}
|
|
1413
1291
|
//#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
1292
|
//#region src/ActionRuntime/Transport/codec/actionWireCodec.d.ts
|
|
1420
1293
|
/**
|
|
1421
1294
|
* Shared building blocks for the binary action codecs (the stateless {@link createBinaryWireAdapter} and
|
|
@@ -1441,507 +1314,145 @@ interface IActionWireFormat {
|
|
|
1441
1314
|
incoming?: (input: string | ArrayBuffer | Uint8Array | Blob) => TActionPayload_Any_JsonObject<any, any> | undefined;
|
|
1442
1315
|
}
|
|
1443
1316
|
//#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
|
-
};
|
|
1317
|
+
//#region src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.d.ts
|
|
1318
|
+
type TFormatMessage = IActionWireFormat;
|
|
1319
|
+
interface IBinaryWireSessionOptions {
|
|
1320
|
+
/** Override how long an unresolved correlation is retained before being swept (ms). */
|
|
1321
|
+
correlationTtlMs?: number;
|
|
1464
1322
|
}
|
|
1465
1323
|
/**
|
|
1466
|
-
*
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1324
|
+
* Builds a factory of *stateful, per-connection* codecs for {@link LinkTransport} /
|
|
1325
|
+
* `AcceptorHandler` — the maximally compact binary wire. Call the returned factory once per live
|
|
1326
|
+
* connection (each socket on the client, each accepted connection on the server) so every channel
|
|
1327
|
+
* gets its own correlation + identity state.
|
|
1328
|
+
*
|
|
1329
|
+
* On top of everything {@link createBinaryWireAdapter} drops, a session also drops:
|
|
1330
|
+
* - **`cuid`** — replaced by a per-connection integer correlation id. The initiator maps it to its
|
|
1331
|
+
* real cuid; the responder echoes it; each side reconstructs the cuid from its own map. Correlation
|
|
1332
|
+
* only needs to be unique per socket, so a counter suffices.
|
|
1333
|
+
* - **`originClient` after the first request** — the first request each side sends carries its
|
|
1334
|
+
* identity; the peer remembers it and injects it into later frames. Replies omit it entirely (a
|
|
1335
|
+
* reply carries the initiator's own origin, which the initiator already knows).
|
|
1336
|
+
*
|
|
1337
|
+
* Both ends MUST build the factory from the same domains in the same order (positional dictionary).
|
|
1338
|
+
* Text frames still return `undefined` from `incoming`, so JSON clients remain interoperable.
|
|
1339
|
+
*
|
|
1340
|
+
* Hibernation note: after a server connection is evicted its session resets, so a still-connected
|
|
1341
|
+
* client (whose session persists) will keep omitting `originClient`. The server must therefore restore
|
|
1342
|
+
* the connection→client binding from its own store (see `AcceptorHandler.rehydrateConnection`) and
|
|
1343
|
+
* inject `originClient` from there — the session alone can't recover it.
|
|
1344
|
+
*/
|
|
1345
|
+
declare function createBinaryWireSessionFactory(domains: ActionDomain<any>[], options?: IBinaryWireSessionOptions): () => TFormatMessage;
|
|
1346
|
+
//#endregion
|
|
1347
|
+
//#region src/ActionRuntime/Channel/ActionChannel.d.ts
|
|
1348
|
+
/**
|
|
1349
|
+
* A transport-agnostic routing contract between two runtimes, declared *by role* rather than by
|
|
1350
|
+
* "client"/"server". The two ends are named for the only asymmetry that survives every carrier (WS,
|
|
1351
|
+
* WebRTC, BLE, raw TCP): which side dials and which side accepts.
|
|
1352
|
+
*
|
|
1353
|
+
* - The **connector** dials out and opens the link ({@link connectChannel}).
|
|
1354
|
+
* - The **acceptor** accepts incoming links and can push back ({@link acceptChannelConnections}).
|
|
1355
|
+
*
|
|
1356
|
+
* `toAcceptor` domains flow connector→acceptor (the classic "request"); `toConnector` domains flow
|
|
1357
|
+
* acceptor→connector (the classic "push"). Both ends derive their routing from the same channel instead
|
|
1358
|
+
* of restating domain lists — and because the contract is independent of how bytes move, the very same
|
|
1359
|
+
* channel can be carried over HTTP, secure WebSockets, or a mix (WS preferred, HTTP fallback).
|
|
1360
|
+
*
|
|
1361
|
+
* Beyond the routing, a channel also carries its *wire identity* — the per-connection binary codec both
|
|
1362
|
+
* ends build from the same domain list, plus the `dictionaryVersion` the handshake checks for drift.
|
|
1363
|
+
* Whether a given transport runs encrypted is a per-transport choice (see {@link IConnectTransport.secure}
|
|
1364
|
+
* and the acceptor's `securityLevel`), not a property of the channel — so one `defineChannel` definition
|
|
1365
|
+
* serves both plain and secure transports.
|
|
1366
|
+
*/
|
|
1367
|
+
interface IActionChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[]> {
|
|
1504
1368
|
/**
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
* `(ws, binding) => ws.serializeAttachment(binding)` — then replay it via {@link AcceptorHandler.rehydrateConnection}
|
|
1508
|
-
* when the channel comes back.
|
|
1369
|
+
* Domains the connector *sends to the acceptor* (connector→acceptor requests). The connector forwards
|
|
1370
|
+
* them over its transport(s); the acceptor executes them.
|
|
1509
1371
|
*/
|
|
1510
|
-
|
|
1372
|
+
toAcceptorDomains: TO_ACCEPTOR;
|
|
1511
1373
|
/**
|
|
1512
|
-
*
|
|
1513
|
-
*
|
|
1374
|
+
* Domains the acceptor *pushes to the connector* (acceptor→connector). The connector registers local
|
|
1375
|
+
* handlers for them ({@link connectChannel}'s `onPush`); the acceptor broadcasts them. Pushes need a
|
|
1376
|
+
* bidirectional transport (e.g. a WebSocket) — over a request-only transport like HTTP they simply
|
|
1377
|
+
* never flow.
|
|
1514
1378
|
*/
|
|
1515
|
-
|
|
1379
|
+
toConnectorDomains: TO_CONNECTOR;
|
|
1380
|
+
/** Wire dictionary version — derived from the domains by default; the handshake rejects a mismatch. */
|
|
1381
|
+
dictionaryVersion: string;
|
|
1382
|
+
/** Per-connection session codec factory (call once per live connection). */
|
|
1383
|
+
createCodec: () => IActionWireFormat;
|
|
1516
1384
|
}
|
|
1517
1385
|
/**
|
|
1518
|
-
*
|
|
1519
|
-
*
|
|
1520
|
-
*
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
formatMessage?: never;
|
|
1530
|
-
});
|
|
1531
|
-
/**
|
|
1532
|
-
* A connection-aware execution case (see {@link AcceptorHandler.forConnectionDomainCases}). It receives
|
|
1533
|
-
* the primed request plus a per-invocation `context` — whatever the wiring's context mapper produces from
|
|
1534
|
-
* the originating connection. The low-level handler passes the raw connection (`TConn | undefined`); the
|
|
1535
|
-
* higher-level `serveChannel` enriches it into an `IConnectionContext` (state + broadcast + pushBack). A
|
|
1536
|
-
* case may return the action's raw output, a result payload, or nothing (auto-wrapped as an empty
|
|
1537
|
-
* success) — exactly like a local handler case.
|
|
1386
|
+
* Declare a transport-agnostic channel by role — the single source of truth both peers share. Each end
|
|
1387
|
+
* MUST call this with the same domains in the same order (the binary wire dictionary is positional); the
|
|
1388
|
+
* `dictionaryVersion` is derived from those domains unless you pin an explicit one. The wire dictionary
|
|
1389
|
+
* spans `[...toAcceptor, ...toConnector]` in that order, so add new domains to the end of their list to
|
|
1390
|
+
* keep older peers compatible.
|
|
1391
|
+
*
|
|
1392
|
+
* Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`
|
|
1393
|
+
* (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see
|
|
1394
|
+
* {@link connectChannel} and {@link serveChannel}) instead of being restated at each end. Security is a
|
|
1395
|
+
* per-transport concern, not a channel one, so this same definition is used whether a transport runs
|
|
1396
|
+
* plain or encrypted.
|
|
1538
1397
|
*/
|
|
1539
|
-
|
|
1398
|
+
declare function defineChannel<const TO_ACCEPTOR extends readonly ActionDomain<any>[] = [], const TO_CONNECTOR extends readonly ActionDomain<any>[] = []>(options: {
|
|
1399
|
+
/** 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. */
|
|
1400
|
+
toConnector: TO_CONNECTOR; /** Pin a human-readable version instead of the derived hash (must match on both ends). */
|
|
1401
|
+
dictionaryVersion?: string; /** Tuning for the per-connection binary session (e.g. correlation TTL). */
|
|
1402
|
+
sessionOptions?: IBinaryWireSessionOptions;
|
|
1403
|
+
}): IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>;
|
|
1404
|
+
type TUnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
1405
|
+
type TDomainPushHandlers<D> = D extends ActionDomain<infer DEF> ? Partial<TWrappableDomainActionHandler<DEF>> : never;
|
|
1540
1406
|
/**
|
|
1541
|
-
* The
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
* {@link AcceptorHandler.forConnectionDomainCases} and `acceptChannelConnections`.
|
|
1407
|
+
* The `onPush` map for a channel: the merged set of every acceptor→connector (`toConnector`) action
|
|
1408
|
+
* handler, each receiving the pushed action's input. Derived from the channel's `toConnectorDomains`, so
|
|
1409
|
+
* the keys and input types follow the channel definition.
|
|
1545
1410
|
*/
|
|
1546
|
-
type
|
|
1411
|
+
type TChannelPushHandlers<TO_CONNECTOR extends readonly ActionDomain<any>[]> = TUnionToIntersection<TDomainPushHandlers<TO_CONNECTOR[number]>>;
|
|
1547
1412
|
/**
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1552
|
-
* Add it alongside your local execution handler:
|
|
1553
|
-
* ```ts
|
|
1554
|
-
* const serverHandler = createAcceptorHandler({ clientEnv, formatMessage, send: (ws, f) => ws.send(f) });
|
|
1555
|
-
* runtime.addHandlers([localHandler, serverHandler]);
|
|
1556
|
-
* // per inbound message (e.g. a Durable Object's webSocketMessage):
|
|
1557
|
-
* serverHandler.receive(ws, message);
|
|
1558
|
-
* ```
|
|
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.
|
|
1413
|
+
* One transport to the peer, declared by *carrier* — the dial-out dual of `serveChannel`'s acceptor
|
|
1414
|
+
* carriers. {@link connectChannel} binds the shared facts (channel codec/version, runtime, crypto
|
|
1415
|
+
* identity) into each one, so a descriptor only carries what differs between transports: the carrier and
|
|
1416
|
+
* whether it runs the secure handshake.
|
|
1564
1417
|
*
|
|
1565
|
-
*
|
|
1566
|
-
*
|
|
1418
|
+
* A duplex carrier (`wsCarrier(() => ({ url }))`, `rtcCarrier(dc)`) builds a push-capable link; an exchange carrier
|
|
1419
|
+
* (`httpCarrier(...)`) builds a request/reply transport. List them in preference order — the connection
|
|
1420
|
+
* prefers the first that's ready and falls through on failure (e.g. secure WS preferred, HTTP fallback).
|
|
1567
1421
|
*/
|
|
1568
|
-
|
|
1569
|
-
/**
|
|
1570
|
-
|
|
1571
|
-
private readonly _formatMessage?;
|
|
1572
|
-
private readonly _createFormatMessage?;
|
|
1573
|
-
private readonly _send;
|
|
1574
|
-
private readonly _runtime?;
|
|
1575
|
-
private readonly _serverTimeout;
|
|
1576
|
-
private _onConnectionBound?;
|
|
1577
|
-
private readonly _security?;
|
|
1578
|
-
/** Normalized accepted levels; whether `none` (plain) is allowed; whether any level needs a handshake. */
|
|
1579
|
-
private readonly _allowedLevels;
|
|
1580
|
-
private readonly _noneAllowed;
|
|
1581
|
-
private readonly _handshakeMode;
|
|
1582
|
-
private readonly _connByClient;
|
|
1583
|
-
private readonly _clientByConn;
|
|
1584
|
-
private readonly _connEncoding;
|
|
1585
|
-
private readonly _codecByConn;
|
|
1586
|
-
private readonly _sessionByConn;
|
|
1587
|
-
constructor(options: IAcceptorHandlerOptions<TConn>);
|
|
1588
|
-
/**
|
|
1589
|
-
* The codec for a connection: a per-connection session (cached) when a factory was provided, else
|
|
1590
|
-
* the single shared `formatMessage`.
|
|
1591
|
-
*/
|
|
1592
|
-
private _codecFor;
|
|
1593
|
-
/**
|
|
1594
|
-
* Register (or replace) the connection-bound persistence callback after construction. Used by
|
|
1595
|
-
* lifecycle helpers like {@link createHibernatableWsServerAdapter} so persistence and replay are
|
|
1596
|
-
* owned by one place instead of being split across the constructor options.
|
|
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;
|
|
1422
|
+
interface IConnectTransport {
|
|
1423
|
+
/** How to reach the peer — a duplex carrier (push-capable) or an exchange carrier (request/reply). */
|
|
1424
|
+
carrier: IDuplexCarrierSource | IExchangeCarrierSource;
|
|
1616
1425
|
/**
|
|
1617
|
-
*
|
|
1618
|
-
*
|
|
1619
|
-
*
|
|
1620
|
-
* secure mode binds the authenticated coordinate at handshake time.)
|
|
1426
|
+
* Run the authenticated/encrypted handshake over this carrier. Defaults to `true`. A secure transport
|
|
1427
|
+
* draws its identity from the connection's shared `link`/`storage`; set `false` for a plain transport
|
|
1428
|
+
* (e.g. a bare HTTP fallback beside a secure WS), which then needs no `storage`.
|
|
1621
1429
|
*/
|
|
1622
|
-
|
|
1430
|
+
secure?: boolean;
|
|
1431
|
+
/** Security level for this secure transport; defaults to the connection-level `securityLevel`. */
|
|
1432
|
+
securityLevel?: ESecurityLevel;
|
|
1623
1433
|
/**
|
|
1624
|
-
*
|
|
1625
|
-
*
|
|
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).
|
|
1434
|
+
* Optional availability gate — when it returns `false` this transport is skipped and the connection
|
|
1435
|
+
* falls through to the next in preference order, re-evaluated per dispatch. Omit = always available.
|
|
1628
1436
|
*/
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
/**
|
|
1635
|
-
|
|
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;
|
|
1437
|
+
available?: (input: ITransportRouteActionParams) => boolean;
|
|
1438
|
+
/** Override the devtools chip label (defaults to the carrier's own label). */
|
|
1439
|
+
label?: string;
|
|
1440
|
+
}
|
|
1441
|
+
interface IConnectChannelOptions<TO_CONNECTOR extends readonly ActionDomain<any>[]> {
|
|
1442
|
+
/** The peer's runtime coordinate — the acceptor this connection dials. */
|
|
1443
|
+
peer: RuntimeCoordinate;
|
|
1640
1444
|
/**
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1445
|
+
* The transports to the peer, by carrier, in preference order (e.g. secure WS preferred, HTTP fallback).
|
|
1446
|
+
* They all carry the channel's `toAcceptor` domains; the connection prefers the first that's ready and
|
|
1447
|
+
* falls through on failure. {@link connectChannel} binds the channel + runtime + crypto identity into
|
|
1448
|
+
* each — the dial-out dual of `serveChannel`'s `carriers`.
|
|
1643
1449
|
*/
|
|
1644
|
-
|
|
1645
|
-
timeout?: number;
|
|
1646
|
-
}): RunningAction<DOM, ID>;
|
|
1450
|
+
transports: readonly IConnectTransport[];
|
|
1647
1451
|
/**
|
|
1648
|
-
*
|
|
1649
|
-
* the
|
|
1650
|
-
*
|
|
1651
|
-
*
|
|
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.
|
|
1675
|
-
*/
|
|
1676
|
-
broadcast<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(makeRequest: () => ActionPayload_Request<DOM, ID>, options?: {
|
|
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;
|
|
1692
|
-
}
|
|
1693
|
-
declare const createAcceptorHandler: <TConn = unknown>(options: IAcceptorHandlerOptions<TConn>) => AcceptorHandler<TConn>;
|
|
1694
|
-
//#endregion
|
|
1695
|
-
//#region src/ActionRuntime/Transport/Carrier/Carrier.types.d.ts
|
|
1696
|
-
/**
|
|
1697
|
-
* Carrier shapes — the only transport-specific surface a new protocol must implement. The secure
|
|
1698
|
-
* session (handshake + frame crypto + codec) and the action routing on top of it are carrier-agnostic;
|
|
1699
|
-
* a carrier just moves frames. Two shapes capture every carrier:
|
|
1700
|
-
*
|
|
1701
|
-
* - {@link IDuplexCarrier} — a persistent, push-capable byte stream (WebSocket, WebRTC `RTCDataChannel`,
|
|
1702
|
-
* Bluetooth GATT, an in-memory pipe). Either side can send at any time, so it supports server→client
|
|
1703
|
-
* pushes (the return path + broadcast).
|
|
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.
|
|
1706
|
-
*
|
|
1707
|
-
* Frames are `string` (text — handshake control messages and JSON action frames) or binary
|
|
1708
|
-
* (`Uint8Array`/`ArrayBuffer` — the optimized binary wire / encrypted frames).
|
|
1709
|
-
*/
|
|
1710
|
-
type TFrame$1 = string | Uint8Array | ArrayBuffer;
|
|
1711
|
-
/**
|
|
1712
|
-
* A bidirectional, push-capable byte stream. Reduces every duplex carrier to "open, send bytes, receive
|
|
1713
|
-
* bytes, close" — a WebSocket, a WebRTC data channel, a Bluetooth characteristic, or an in-memory pipe
|
|
1714
|
-
* all satisfy this, so the identical secure session runs over each.
|
|
1715
|
-
*/
|
|
1716
|
-
interface IDuplexCarrier {
|
|
1717
|
-
/** Resolves once the carrier is open and ready to send; rejects if it closes/errors before opening. */
|
|
1718
|
-
readonly ready: Promise<void>;
|
|
1719
|
-
/** Whether the carrier is currently open (a synchronous guard before `send`). */
|
|
1720
|
-
isOpen(): boolean;
|
|
1721
|
-
/** Write one frame to the peer. */
|
|
1722
|
-
send(frame: TFrame$1): void;
|
|
1723
|
-
/**
|
|
1724
|
-
* Register the carrier's handlers. Called exactly once by the session after `ready`. `onMessage`
|
|
1725
|
-
* receives every inbound frame; `onClose` fires when the carrier goes away.
|
|
1726
|
-
*/
|
|
1727
|
-
attach(handlers: {
|
|
1728
|
-
onMessage: (frame: TFrame$1) => void;
|
|
1729
|
-
onClose: () => void;
|
|
1730
|
-
onError?: (error: unknown) => void;
|
|
1731
|
-
}): void;
|
|
1732
|
-
/** Close the carrier deliberately (a teardown). */
|
|
1733
|
-
close(): void;
|
|
1734
|
-
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1735
|
-
readonly label?: string;
|
|
1736
|
-
}
|
|
1737
|
-
/**
|
|
1738
|
-
* A request → single-correlated-reply carrier with no unsolicited push (HTTP). One `exchange` sends a
|
|
1739
|
-
* frame and resolves with exactly the one reply frame for it; the carrier itself correlates them (the
|
|
1740
|
-
* HTTP transaction), so no correlation id is needed on the wire.
|
|
1741
|
-
*/
|
|
1742
|
-
interface IExchangeCarrier {
|
|
1743
|
-
/** Send one frame, await the single correlated reply frame. */
|
|
1744
|
-
exchange(frame: TFrame$1, opts?: {
|
|
1745
|
-
signal?: AbortSignal;
|
|
1746
|
-
}): Promise<TFrame$1>;
|
|
1747
|
-
/** Optional human-readable endpoint for the devtools route chip. */
|
|
1748
|
-
readonly label?: string;
|
|
1749
|
-
}
|
|
1750
|
-
type TCarrier = IDuplexCarrier | IExchangeCarrier;
|
|
1751
|
-
/**
|
|
1752
|
-
* A reusable opener for a {@link IDuplexCarrier} plus the per-action metadata a duplex transport needs.
|
|
1753
|
-
* Built by the small carrier factories (`wsCarrier`, `rtcCarrier`, `inMemoryCarrier`) and handed to
|
|
1754
|
-
* {@link secureTransport} / `LinkTransport` — so adding a new carrier is "write one of these", nothing
|
|
1755
|
-
* else.
|
|
1756
|
-
*/
|
|
1757
|
-
interface IDuplexCarrierSource {
|
|
1758
|
-
/** Open (or reuse) the carrier for an action. */
|
|
1759
|
-
open: (input: ITransportRouteActionParams) => IDuplexCarrier;
|
|
1760
|
-
/** Keys identifying a reusable carrier, so one carrier is shared across actions to the same peer. */
|
|
1761
|
-
getCacheKey?: (input: ITransportRouteActionParams) => string[];
|
|
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;
|
|
1766
|
-
}
|
|
1767
|
-
/**
|
|
1768
|
-
* The exchange-shape counterpart to {@link IDuplexCarrierSource}: a reusable opener for an
|
|
1769
|
-
* {@link IExchangeCarrier} plus the per-action metadata an exchange transport needs. Built by
|
|
1770
|
-
* `httpCarrier` and handed to {@link secureTransport} — adding a new request/reply protocol is "write
|
|
1771
|
-
* one of these". The `shape` tag lets {@link secureTransport} pick the duplex vs exchange transport.
|
|
1772
|
-
*/
|
|
1773
|
-
interface IExchangeCarrierSource {
|
|
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
|
-
}
|
|
1785
|
-
//#endregion
|
|
1786
|
-
//#region src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.d.ts
|
|
1787
|
-
type TFormatMessage = IActionWireFormat;
|
|
1788
|
-
interface IBinaryWireSessionOptions {
|
|
1789
|
-
/** Override how long an unresolved correlation is retained before being swept (ms). */
|
|
1790
|
-
correlationTtlMs?: number;
|
|
1791
|
-
}
|
|
1792
|
-
/**
|
|
1793
|
-
* Builds a factory of *stateful, per-connection* codecs for {@link LinkTransport} /
|
|
1794
|
-
* `AcceptorHandler` — the maximally compact binary wire. Call the returned factory once per live
|
|
1795
|
-
* connection (each socket on the client, each accepted connection on the server) so every channel
|
|
1796
|
-
* gets its own correlation + identity state.
|
|
1797
|
-
*
|
|
1798
|
-
* On top of everything {@link createBinaryWireAdapter} drops, a session also drops:
|
|
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.
|
|
1808
|
-
*
|
|
1809
|
-
* Hibernation note: after a server connection is evicted its session resets, so a still-connected
|
|
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.
|
|
1836
|
-
*
|
|
1837
|
-
* Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`
|
|
1838
|
-
* (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see
|
|
1839
|
-
* {@link connectChannel} and `acceptChannelConnections`) instead of being restated at each end. The
|
|
1840
|
-
* wire dictionary spans `[...toAcceptor, ...toConnector]` in that order; add new domains to the end of
|
|
1841
|
-
* their list to keep older peers compatible. (`domains` is still accepted as a legacy alias for
|
|
1842
|
-
* `toAcceptor`.)
|
|
1843
|
-
*/
|
|
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
|
-
/**
|
|
1853
|
-
* A transport-agnostic routing contract between two runtimes, declared *by role* rather than by
|
|
1854
|
-
* "client"/"server". The two ends are named for the only asymmetry that survives every carrier (WS,
|
|
1855
|
-
* WebRTC, BLE, raw TCP): which side dials and which side accepts.
|
|
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).
|
|
1864
|
-
*
|
|
1865
|
-
* Build a plain one with {@link defineChannel}; layer wire-specific identity on top with
|
|
1866
|
-
* `defineSecureChannel` (which returns an `ISecureChannel` — still an `IActionChannel`, so it works
|
|
1867
|
-
* everywhere a channel is expected).
|
|
1868
|
-
*/
|
|
1869
|
-
interface IActionChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[]> {
|
|
1870
|
-
/**
|
|
1871
|
-
* Domains the connector *sends to the acceptor* (connector→acceptor requests). The connector forwards
|
|
1872
|
-
* them over its transport(s); the acceptor executes them.
|
|
1873
|
-
*/
|
|
1874
|
-
toAcceptorDomains: TO_ACCEPTOR;
|
|
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;
|
|
1882
|
-
}
|
|
1883
|
-
/**
|
|
1884
|
-
* Declare a transport-agnostic channel by role. Use it for HTTP, custom transports, or as the routing
|
|
1885
|
-
* half of a richer channel. The order of each list is part of the contract for wire formats that pack
|
|
1886
|
-
* positionally (see `defineSecureChannel`) — add new domains to the end of their list. (`domains` is
|
|
1887
|
-
* accepted as a legacy alias for `toAcceptor`.)
|
|
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.
|
|
1899
|
-
*/
|
|
1900
|
-
type TChannelPushHandlers<TO_CONNECTOR extends readonly ActionDomain<any>[]> = TUnionToIntersection<TDomainPushHandlers<TO_CONNECTOR[number]>>;
|
|
1901
|
-
/**
|
|
1902
|
-
* One transport to the peer, declared by *carrier* — the dial-out dual of `serveChannel`'s acceptor
|
|
1903
|
-
* carriers. {@link connectChannel} binds the shared facts (channel codec/version, runtime, crypto
|
|
1904
|
-
* identity) into each one, so a descriptor only carries what differs between transports: the carrier and
|
|
1905
|
-
* whether it runs the secure handshake.
|
|
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).
|
|
1910
|
-
*/
|
|
1911
|
-
interface IConnectTransport {
|
|
1912
|
-
/** How to reach the peer — a duplex carrier (push-capable) or an exchange carrier (request/reply). */
|
|
1913
|
-
carrier: IDuplexCarrierSource | IExchangeCarrierSource;
|
|
1914
|
-
/**
|
|
1915
|
-
* Run the authenticated/encrypted handshake over this carrier. Defaults to `true`. A secure transport
|
|
1916
|
-
* draws its identity from the connection's shared `link`/`storage`; set `false` for a plain transport
|
|
1917
|
-
* (e.g. a bare HTTP fallback beside a secure WS), which then needs no `storage`.
|
|
1918
|
-
*/
|
|
1919
|
-
secure?: boolean;
|
|
1920
|
-
/** Security level for this secure transport; defaults to the connection-level `securityLevel`. */
|
|
1921
|
-
securityLevel?: ESecurityLevel;
|
|
1922
|
-
/**
|
|
1923
|
-
* Optional availability gate — when it returns `false` this transport is skipped and the connection
|
|
1924
|
-
* falls through to the next in preference order, re-evaluated per dispatch. Omit = always available.
|
|
1925
|
-
*/
|
|
1926
|
-
available?: (input: ITransportRouteActionParams) => boolean;
|
|
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;
|
|
1933
|
-
/**
|
|
1934
|
-
* The transports to the peer, by carrier, in preference order (e.g. secure WS preferred, HTTP fallback).
|
|
1935
|
-
* They all carry the channel's `toAcceptor` domains; the connection prefers the first that's ready and
|
|
1936
|
-
* falls through on failure. {@link connectChannel} binds the channel + runtime + crypto identity into
|
|
1937
|
-
* each — the dial-out dual of `serveChannel`'s `carriers`.
|
|
1938
|
-
*/
|
|
1939
|
-
transports: readonly IConnectTransport[];
|
|
1940
|
-
/**
|
|
1941
|
-
* One backing store for this connection's crypto identity, fanned across every *secure* transport so
|
|
1942
|
-
* they present the same verify/exchange keys. Required when any transport is secure (the default); a
|
|
1943
|
-
* fully-plain connection (every transport `secure: false`) may omit it. Pass `link` instead to share an
|
|
1944
|
-
* existing identity.
|
|
1452
|
+
* One backing store for this connection's crypto identity, fanned across every *secure* transport so
|
|
1453
|
+
* they present the same verify/exchange keys. Required when any transport is secure (the default); a
|
|
1454
|
+
* fully-plain connection (every transport `secure: false`) may omit it. Pass `link` instead to share an
|
|
1455
|
+
* existing identity.
|
|
1945
1456
|
*/
|
|
1946
1457
|
storage?: StorageAdapter;
|
|
1947
1458
|
/** The connection's crypto identity. Defaults to a fresh {@link ClientCryptoKeyLink} over `storage`. */
|
|
@@ -1970,7 +1481,7 @@ interface IConnectChannelOptions<TO_CONNECTOR extends readonly ActionDomain<any>
|
|
|
1970
1481
|
* ```
|
|
1971
1482
|
* Returns the {@link ConnectorHandler} so the caller can later `clearTransportCache()` it.
|
|
1972
1483
|
*/
|
|
1973
|
-
declare function connectChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[]>(runtime: ActionRuntime, channel:
|
|
1484
|
+
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;
|
|
1974
1485
|
type TDomainAcceptorCases<D, TCtx> = D extends ActionDomain<infer DEF> ? { [ID in keyof DEF["actionSchema"] & string]?: TAcceptorCaseFn<DEF, ID, TCtx> } : never;
|
|
1975
1486
|
/**
|
|
1976
1487
|
* The connection-aware case map for a channel's acceptor side: the merged set of every
|
|
@@ -1995,44 +1506,33 @@ type TChannelAcceptorCases<TO_ACCEPTOR extends readonly ActionDomain<any>[], TCt
|
|
|
1995
1506
|
* broadcast + pushBack context, serve the channel through `serveChannel`'s `channelCases` instead.
|
|
1996
1507
|
*/
|
|
1997
1508
|
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;
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
clientEnv: RuntimeCoordinate;
|
|
2004
|
-
/**
|
|
2005
|
-
* One backing store for the acceptor's crypto identity *and* its trust-on-first-use verify-key pins
|
|
2006
|
-
* (their keys don't collide). Back it with persistent storage so identity + pins survive eviction.
|
|
2007
|
-
*/
|
|
2008
|
-
storageAdapter: StorageAdapter;
|
|
2009
|
-
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
2010
|
-
send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;
|
|
2011
|
-
/**
|
|
2012
|
-
* The acceptor's crypto identity. Defaults to a fresh `ClientCryptoKeyLink` over `storageAdapter`.
|
|
2013
|
-
* Pass an existing link to share one identity across several acceptors on the same server (e.g. this
|
|
2014
|
-
* WebSocket acceptor and a secure-HTTP `createActionFetchHandler`), so they present the same keys.
|
|
2015
|
-
*/
|
|
2016
|
-
link?: ClientCryptoKeyLink;
|
|
2017
|
-
/** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */
|
|
2018
|
-
securityLevel?: ESecurityLevel | readonly ESecurityLevel[];
|
|
2019
|
-
/** Trust decision for a client's verify key; defaults to storage-backed TOFU over `storageAdapter`. */
|
|
2020
|
-
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
2021
|
-
/** Timeout (ms) applied to acceptor-initiated actions awaiting a client response. */
|
|
2022
|
-
defaultTimeout?: number;
|
|
2023
|
-
}
|
|
1509
|
+
/**
|
|
1510
|
+
* {@link acceptChannel}'s options — the secure-acceptor builder options minus the `channel` and `runtime`
|
|
1511
|
+
* it already takes positionally. One option bag, shared with the underlying {@link createSecureAcceptorHandler}.
|
|
1512
|
+
*/
|
|
1513
|
+
type IAcceptChannelOptions<TConn> = Omit<ISecureAcceptorHandlerOptions<TConn>, "channel" | "runtime">;
|
|
2024
1514
|
/**
|
|
2025
1515
|
* Build the secure {@link AcceptorHandler} for a channel — the accept-in counterpart to
|
|
2026
|
-
* {@link connectChannel}. It folds in the
|
|
2027
|
-
* `ClientCryptoKeyLink` + storage-backed TOFU resolver from one `
|
|
1516
|
+
* {@link connectChannel}. It folds in the boilerplate of {@link createSecureAcceptorHandler} (the
|
|
1517
|
+
* `ClientCryptoKeyLink` + storage-backed TOFU resolver from one `storage`, the channel's codec +
|
|
2028
1518
|
* dictionary version, the `security` block from the runtime coordinate) but takes the `(runtime, channel,
|
|
2029
1519
|
* options)` shape of the channel family. Pair it with {@link acceptChannelConnections} for execution:
|
|
2030
1520
|
* ```ts
|
|
2031
|
-
* const acceptor = acceptChannel(runtime, gameChannel, { clientEnv,
|
|
1521
|
+
* const acceptor = acceptChannel(runtime, gameChannel, { clientEnv, storage, send });
|
|
2032
1522
|
* runtime.addHandlers([acceptChannelConnections(acceptor, gameChannel, { … }), acceptor]);
|
|
2033
1523
|
* ```
|
|
2034
1524
|
*/
|
|
2035
|
-
declare function acceptChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn = unknown>(runtime: ActionRuntime, channel:
|
|
1525
|
+
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>;
|
|
1526
|
+
//#endregion
|
|
1527
|
+
//#region src/ActionRuntime/ActionRuntime.types.d.ts
|
|
1528
|
+
interface IRuntimeMeta {
|
|
1529
|
+
assumed: boolean;
|
|
1530
|
+
runtimeName: RuntimeName;
|
|
1531
|
+
}
|
|
1532
|
+
interface IActionRuntimeManagerContext {
|
|
1533
|
+
domain?: string;
|
|
1534
|
+
}
|
|
1535
|
+
type TActionRuntimeHandler = ActionLocalHandler | PeerLinkHandler;
|
|
2036
1536
|
//#endregion
|
|
2037
1537
|
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/ConnectionStateStore.d.ts
|
|
2038
1538
|
/**
|
|
@@ -2251,8 +1751,8 @@ interface IDuplexAcceptorCarrier<TConn = unknown> extends IDuplexCarrierLifecycl
|
|
|
2251
1751
|
* default it speaks the *secure* exchange protocol (handshake → token session → encrypted frames), whose
|
|
2252
1752
|
* identity is supplied centrally by `serveChannel`. Set {@link secure} to `false` for a plain endpoint
|
|
2253
1753
|
* that POSTs the raw action wire and returns the result inline — the request/reply dual of the connector's
|
|
2254
|
-
* `
|
|
2255
|
-
* plain HTTP fallback on the same runtime. Built by `httpAcceptorCarrier`.
|
|
1754
|
+
* plain HTTP transport (`{ carrier: httpCarrier(...), secure: false }`). So a server can pair a secure
|
|
1755
|
+
* duplex (WebSocket) with a plain HTTP fallback on the same runtime. Built by `httpAcceptorCarrier`.
|
|
2256
1756
|
*/
|
|
2257
1757
|
interface IExchangeAcceptorCarrier {
|
|
2258
1758
|
/** Discriminant so `serveChannel` can tell an exchange carrier from a duplex one. */
|
|
@@ -2465,12 +1965,12 @@ interface IChannelServer<TConn, TApp = unknown> {
|
|
|
2465
1965
|
* carrier, and so on — so it stays carrier-agnostic. Passing `connectionState` narrows the return so
|
|
2466
1966
|
* `server.connections` is non-optional.
|
|
2467
1967
|
*/
|
|
2468
|
-
declare function serveChannel<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn, TApp>(runtime: ActionRuntime, channel:
|
|
1968
|
+
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
1969
|
connectionState: IServeConnectionStateOptions<TApp>;
|
|
2470
1970
|
}): IChannelServer<TConn, TApp> & {
|
|
2471
1971
|
connections: ConnectionStateStore<TConn, TApp>;
|
|
2472
1972
|
};
|
|
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:
|
|
1973
|
+
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
1974
|
//#endregion
|
|
2475
1975
|
//#region src/ActionRuntime/Channel/serveHost.d.ts
|
|
2476
1976
|
/**
|
|
@@ -2503,157 +2003,12 @@ type TServeHostOptions<TO_ACCEPTOR extends readonly ActionDomain<any>[], TConn,
|
|
|
2503
2003
|
* the host adapter and nothing else. Passing `connectionState` narrows the return so `server.connections`
|
|
2504
2004
|
* is non-optional, exactly as with `serveChannel`.
|
|
2505
2005
|
*/
|
|
2506
|
-
declare function serveHost<TO_ACCEPTOR extends readonly ActionDomain<any>[], TO_CONNECTOR extends readonly ActionDomain<any>[], TConn, TApp>(runtime: ActionRuntime, channel:
|
|
2006
|
+
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
2007
|
connectionState: IServeConnectionStateOptions<TApp>;
|
|
2508
2008
|
}): IChannelServer<TConn, TApp> & {
|
|
2509
2009
|
connections: ConnectionStateStore<TConn, TApp>;
|
|
2510
2010
|
};
|
|
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>;
|
|
2011
|
+
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
2012
|
//#endregion
|
|
2658
2013
|
//#region src/ActionRuntime/Handler/PeerLink/Connector/err_nice_external_client.d.ts
|
|
2659
2014
|
declare const err_nice_external_client: import("@nice-code/error").NiceErrorDomain<{
|
|
@@ -2693,16 +2048,15 @@ declare function createInMemoryChannelPair(): IInMemoryChannelPair;
|
|
|
2693
2048
|
//#endregion
|
|
2694
2049
|
//#region src/ActionRuntime/Transport/Carrier/duplex/inMemory/inMemoryCarrier.d.ts
|
|
2695
2050
|
interface IInMemoryCarrier {
|
|
2696
|
-
/** The connector end — pass as the `carrier` to
|
|
2051
|
+
/** The connector end — pass as the `carrier` to one of `connectChannel`'s transports. */
|
|
2697
2052
|
carrier: IDuplexCarrierSource;
|
|
2698
2053
|
/** The acceptor end — wire into an `AcceptorHandler` (`send` + `receive`). */
|
|
2699
2054
|
serverEndpoint: IInMemoryServerEndpoint;
|
|
2700
2055
|
}
|
|
2701
2056
|
/**
|
|
2702
2057
|
* 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.
|
|
2058
|
+
* {@link IDuplexCarrierSource} for `connectChannel`; the acceptor end plugs into an `AcceptorHandler`.
|
|
2059
|
+
* Ideal for tests and for running two runtimes in one process, or proving a non-WS carrier end to end.
|
|
2706
2060
|
*/
|
|
2707
2061
|
declare function inMemoryCarrier(): IInMemoryCarrier;
|
|
2708
2062
|
//#endregion
|
|
@@ -2738,8 +2092,8 @@ interface IRtcCarrierOptions {
|
|
|
2738
2092
|
}
|
|
2739
2093
|
/**
|
|
2740
2094
|
* A WebRTC {@link IDuplexCarrierSource} over an already-negotiated `RTCDataChannel` (signaling is the
|
|
2741
|
-
* app's concern).
|
|
2742
|
-
* identical secure session as a WebSocket.
|
|
2095
|
+
* app's concern). Pass it as a `carrier` to `connectChannel` so two browsers/apps linked peer-to-peer run
|
|
2096
|
+
* the identical secure session as a WebSocket.
|
|
2743
2097
|
*/
|
|
2744
2098
|
declare function rtcCarrier(dataChannel: IRtcDataChannelLike, options?: IRtcCarrierOptions): IDuplexCarrierSource;
|
|
2745
2099
|
//#endregion
|
|
@@ -2806,8 +2160,8 @@ interface IWsCarrierOptions {
|
|
|
2806
2160
|
}
|
|
2807
2161
|
/**
|
|
2808
2162
|
* A WebSocket {@link IDuplexCarrierSource}: opens an `arraybuffer` socket (cached per endpoint) and adapts
|
|
2809
|
-
* it to a carrier.
|
|
2810
|
-
*
|
|
2163
|
+
* it to a carrier. Pass it as a `carrier` to `connectChannel` — the WebSocket is now "just another
|
|
2164
|
+
* carrier" under the shared secure session, with no WS-specific transport class.
|
|
2811
2165
|
*
|
|
2812
2166
|
* `createRequest` derives the socket URL per action (keep it simple with `() => ({ url })`), so dynamic
|
|
2813
2167
|
* endpoints (e.g. a per-run query param) need no `createWebSocket` escape hatch.
|
|
@@ -2819,8 +2173,9 @@ interface IHttpAcceptorCarrierOptions {
|
|
|
2819
2173
|
/**
|
|
2820
2174
|
* Whether this endpoint runs the secure exchange protocol (default `true`). Pass `false` for a plain
|
|
2821
2175
|
* 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
|
|
2176
|
+
* of a connector's plain HTTP transport (`{ carrier: httpCarrier(...), secure: false }`). A plain
|
|
2177
|
+
* endpoint ignores the crypto identity, so it can sit alongside a secure WebSocket on the same server
|
|
2178
|
+
* (e.g. a secure WS preferred, plain HTTP fallback).
|
|
2824
2179
|
*/
|
|
2825
2180
|
secure?: boolean;
|
|
2826
2181
|
/** Which requests carry an action exchange envelope on `POST`. Defaults to `serveChannel`'s path match. */
|
|
@@ -2863,129 +2218,16 @@ interface IHttpCarrierOptions {
|
|
|
2863
2218
|
}
|
|
2864
2219
|
/**
|
|
2865
2220
|
* 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
|
|
2221
|
+
* resolves with the response body as the single correlated reply. Pass it as a `carrier` to
|
|
2222
|
+
* `connectChannel` — a secure HTTP transport then runs the *same* secure session as a duplex carrier
|
|
2223
|
+
* (handshake → token → encrypted frames), the request/reply correlation provided for free by the HTTP
|
|
2224
|
+
* transaction.
|
|
2869
2225
|
*
|
|
2870
2226
|
* `createRequest` derives the URL/headers per action (keep it simple with `() => ({ url })`). The body is
|
|
2871
2227
|
* the session's responsibility, so it is never built here.
|
|
2872
2228
|
*/
|
|
2873
2229
|
declare function httpCarrier(createRequest: (input: ITransportRouteActionParams) => IHttpCarrierRequest, options?: IHttpCarrierOptions): IExchangeCarrierSource;
|
|
2874
2230
|
//#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
2231
|
//#region src/ActionRuntime/Transport/err_nice_transport.d.ts
|
|
2990
2232
|
declare enum EErrId_NiceTransport {
|
|
2991
2233
|
timeout = "timeout",
|
|
@@ -3023,130 +2265,6 @@ declare const err_nice_transport: import("@nice-code/error").NiceErrorDomain<{
|
|
|
3023
2265
|
};
|
|
3024
2266
|
}>;
|
|
3025
2267
|
//#endregion
|
|
3026
|
-
//#region src/ActionRuntime/Transport/Link/TransportLink.types.d.ts
|
|
3027
|
-
/** The per-connection codec (positional binary wire / JSON fallback) the carrier's session uses. */
|
|
3028
|
-
type TLinkFormatMessage = IActionWireFormat;
|
|
3029
|
-
interface IActionTransportReadyData_Link extends IActionTransportReadyData_Base {
|
|
3030
|
-
/** The live carrier this connection drives its session over. */
|
|
3031
|
-
channel: IDuplexCarrier;
|
|
3032
|
-
formatMessage?: TLinkFormatMessage;
|
|
3033
|
-
/** Optional authenticated/encrypted channel; the connection runs the handshake during init. */
|
|
3034
|
-
secureChannel?: ISecureClientConfig;
|
|
3035
|
-
}
|
|
3036
|
-
interface IActionTransportInitialized_Link extends IActionTransportInitialized<ITransportRouteActionParams, IActionTransportReadyData_Link> {}
|
|
3037
|
-
interface IActionTransportDef_Link extends IActionTransportDef<ETransportShape.duplex, IActionTransportInitialized_Link> {}
|
|
3038
|
-
//#endregion
|
|
3039
|
-
//#region src/ActionRuntime/Transport/Link/LinkConnection.d.ts
|
|
3040
|
-
/**
|
|
3041
|
-
* Carrier-agnostic live connection. It owns only the *bring-up* (open the carrier, then run the secure
|
|
3042
|
-
* session); the session itself — handshake, frame crypto, codec, send/receive — lives in the shared
|
|
3043
|
-
* {@link finalizeSecureLinkMethods}/{@link finalizePlainLinkMethods}, so a WebSocket, a WebRTC data
|
|
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;
|
|
3085
|
-
}
|
|
3086
|
-
/**
|
|
3087
|
-
* A carrier-agnostic transport: it drives nice-action's secure session + action routing over any
|
|
3088
|
-
* {@link IDuplexCarrier}. The WebSocket transport is the special case that opens a `WebSocket`;
|
|
3089
|
-
* this opens whatever `openChannel` returns, so the identical secure layer works over WebRTC, Bluetooth,
|
|
3090
|
-
* or an in-memory pipe. Reported with an overridable carrier label in the devtools (defaults to "link").
|
|
3091
|
-
*/
|
|
3092
|
-
declare class LinkTransport extends Transport<ETransportShape.duplex> {
|
|
3093
|
-
private readonly options;
|
|
3094
|
-
readonly type = ETransportShape.duplex;
|
|
3095
|
-
constructor(options: ILinkTransportOptions);
|
|
3096
|
-
static create(options: ILinkTransportOptions): LinkTransport;
|
|
3097
|
-
_createConnection(ctx: ITransportConnectionContext): LinkConnection;
|
|
3098
|
-
getRouteInfo(input: ITransportRouteActionParams): ITransportRouteInfo;
|
|
3099
|
-
}
|
|
3100
|
-
//#endregion
|
|
3101
|
-
//#region src/ActionRuntime/Transport/SecureSession/exchangeProtocol.d.ts
|
|
3102
|
-
/**
|
|
3103
|
-
* The application-level envelope for secure action traffic over an {@link IExchangeCarrier} (HTTP). An
|
|
3104
|
-
* exchange carrier only moves one request frame → one reply frame with no unsolicited push, so the
|
|
3105
|
-
* handshake and the per-action token + crypto all ride in this envelope (a JSON string body) rather than
|
|
3106
|
-
* on a persistent channel. The three security levels share it:
|
|
3107
|
-
*
|
|
3108
|
-
* - `none` — no handshake, no token: an `act` envelope carries the plaintext wire both ways.
|
|
3109
|
-
* - `authenticated` — a one-time handshake yields a session `token`; each later `act` carries it +
|
|
3110
|
-
* the plaintext wire.
|
|
3111
|
-
* - `encrypted` — same, but the wire is AES-GCM ciphertext, base64 in the `c` field.
|
|
3112
|
-
*
|
|
3113
|
-
* The handshake runs as two `hs` exchanges (hello→welcome, prove→accept) correlated by a client-chosen
|
|
3114
|
-
* `hsid`, since stateless requests can't rely on channel ordering. The `accept` reply carries the token.
|
|
3115
|
-
*/
|
|
3116
|
-
type TWireJson = TActionPayload_Any_JsonObject<any, any>;
|
|
3117
|
-
/** Connector → acceptor request envelope. */
|
|
3118
|
-
type TExchangeRequest = {
|
|
3119
|
-
k: "hs";
|
|
3120
|
-
hsid: string;
|
|
3121
|
-
m: string;
|
|
3122
|
-
} | {
|
|
3123
|
-
k: "act";
|
|
3124
|
-
t?: string;
|
|
3125
|
-
w: TWireJson;
|
|
3126
|
-
} | {
|
|
3127
|
-
k: "act";
|
|
3128
|
-
t?: string;
|
|
3129
|
-
c: string;
|
|
3130
|
-
};
|
|
3131
|
-
/** Acceptor → connector reply envelope. */
|
|
3132
|
-
type TExchangeReply = {
|
|
3133
|
-
k: "hs";
|
|
3134
|
-
m: string;
|
|
3135
|
-
t?: string;
|
|
3136
|
-
} | {
|
|
3137
|
-
k: "act";
|
|
3138
|
-
w: TWireJson;
|
|
3139
|
-
} | {
|
|
3140
|
-
k: "act";
|
|
3141
|
-
c: string;
|
|
3142
|
-
} | {
|
|
3143
|
-
k: "err";
|
|
3144
|
-
message: string;
|
|
3145
|
-
};
|
|
3146
|
-
declare function encodeExchange(envelope: TExchangeRequest | TExchangeReply): string;
|
|
3147
|
-
declare function decodeExchangeRequest(raw: string): TExchangeRequest | undefined;
|
|
3148
|
-
declare function decodeExchangeReply(raw: string): TExchangeReply | undefined;
|
|
3149
|
-
//#endregion
|
|
3150
2268
|
//#region src/errors/err_nice_action.d.ts
|
|
3151
2269
|
declare enum EErrId_NiceAction {
|
|
3152
2270
|
not_implemented = "not_implemented",
|
|
@@ -3372,5 +2490,508 @@ interface IActionPayload_Result_JsonObject<DOM extends IActionDomain = IActionDo
|
|
|
3372
2490
|
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
2491
|
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
2492
|
//#endregion
|
|
3375
|
-
|
|
3376
|
-
|
|
2493
|
+
//#region src/ActionRuntime/Handler/ActionHandler.types.d.ts
|
|
2494
|
+
declare enum EActionHandlerType {
|
|
2495
|
+
peer = "peer",
|
|
2496
|
+
local = "local"
|
|
2497
|
+
}
|
|
2498
|
+
interface IActionHandler_Json<T extends EActionHandlerType> {
|
|
2499
|
+
type: T;
|
|
2500
|
+
}
|
|
2501
|
+
interface IActionHandler_Peer_Json extends IActionHandler_Json<EActionHandlerType.peer> {
|
|
2502
|
+
client: IRuntimeCoordinate;
|
|
2503
|
+
}
|
|
2504
|
+
interface IActionHandler_Local_Json extends IActionHandler_Json<EActionHandlerType.local> {}
|
|
2505
|
+
type TActionHandler_Json = IActionHandler_Local_Json | IActionHandler_Peer_Json;
|
|
2506
|
+
interface IHandleActionOptions {
|
|
2507
|
+
timeout?: number;
|
|
2508
|
+
targetPeer?: RuntimeCoordinate;
|
|
2509
|
+
targetLocalRuntime?: ActionRuntime;
|
|
2510
|
+
}
|
|
2511
|
+
interface IExecuteActionOptions<DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends IHandleActionOptions {
|
|
2512
|
+
listeners?: TRunningActionUpdateListener<DOM, ID>[];
|
|
2513
|
+
}
|
|
2514
|
+
interface IActionHandler_Base<T extends EActionHandlerType> {
|
|
2515
|
+
cuid: string;
|
|
2516
|
+
handlerType: T;
|
|
2517
|
+
getActionRouter: () => ActionRouter<any>;
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
*
|
|
2521
|
+
* LOCAL ACTION HANDLER
|
|
2522
|
+
*
|
|
2523
|
+
*/
|
|
2524
|
+
interface IHandleActionOptions_Local extends IHandleActionOptions {}
|
|
2525
|
+
interface IActionHandler_Local extends IActionHandler_Base<EActionHandlerType.local> {
|
|
2526
|
+
handleActionRequest: <DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions_Local) => Promise<RunningAction<DOM, ID>>;
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
*
|
|
2530
|
+
* PEER-LINK ACTION HANDLER
|
|
2531
|
+
*
|
|
2532
|
+
*/
|
|
2533
|
+
interface IHandleActionOptions_Peer extends IHandleActionOptions {}
|
|
2534
|
+
interface IActionHandler_Peer extends IActionHandler_Base<EActionHandlerType.peer> {
|
|
2535
|
+
peerClient: RuntimeCoordinate;
|
|
2536
|
+
handleActionRequest: <DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions_Peer) => Promise<RunningAction<DOM, ID>>;
|
|
2537
|
+
_setIncomingActionDataListener(listener: (json: TActionPayload_Any_JsonObject<any>) => void): void;
|
|
2538
|
+
}
|
|
2539
|
+
/**
|
|
2540
|
+
*
|
|
2541
|
+
* COMBINED
|
|
2542
|
+
*
|
|
2543
|
+
*/
|
|
2544
|
+
type TActionHandler = IActionHandler_Local | IActionHandler_Peer;
|
|
2545
|
+
//#endregion
|
|
2546
|
+
//#region src/ActionDefinition/Action/Payload/ActionPayload_Request.d.ts
|
|
2547
|
+
declare class ActionPayload_Request<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends ActionPayload<EActionPayloadType.request, DOM, ID> {
|
|
2548
|
+
readonly input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
2549
|
+
readonly inputHash: string;
|
|
2550
|
+
_callSite?: string;
|
|
2551
|
+
constructor(params: {
|
|
2552
|
+
context: ActionContext<DOM, ID>;
|
|
2553
|
+
}, input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"], data: IActionPayload_Data_Base);
|
|
2554
|
+
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>;
|
|
2555
|
+
errorResult(err: TInferActionError<DOM["actionSchema"][ID]>): ActionPayload_Result<DOM, ID>;
|
|
2556
|
+
progress(progress: TActionProgress): ActionPayload_Progress<DOM, ID>;
|
|
2557
|
+
toJsonObject(): IActionPayload_Request_JsonObject<DOM, ID>;
|
|
2558
|
+
toJsonString(): string;
|
|
2559
|
+
runToOutput(options?: IExecuteActionOptions<DOM, ID>): Promise<TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"]>;
|
|
2560
|
+
runToResultPayload(options?: IExecuteActionOptions<DOM, ID>): Promise<ActionPayload_Result<DOM, ID>>;
|
|
2561
|
+
run(options?: IExecuteActionOptions<DOM, ID>): Promise<RunningAction<DOM, ID>>;
|
|
2562
|
+
}
|
|
2563
|
+
//#endregion
|
|
2564
|
+
//#region src/ActionDefinition/Action/Core/ActionCore.d.ts
|
|
2565
|
+
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> {
|
|
2566
|
+
readonly _domain: ActionDomain<DOM>;
|
|
2567
|
+
readonly form = EActionForm.core;
|
|
2568
|
+
constructor(_domain: ActionDomain<DOM>, id: ID);
|
|
2569
|
+
is<ACT extends IActionBase<any, any, any>>(action: ACT | unknown | null | undefined): action is TNarrowActionType<DOM, ACT, ID>;
|
|
2570
|
+
toJsonObject(): IActionBase_JsonObject<EActionForm.core, DOM, ID>;
|
|
2571
|
+
request(...args: [TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"]] extends [never] ? [input?: never] : [input: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"]]): ActionPayload_Request<DOM, ID>;
|
|
2572
|
+
deserializeInput(serialized: TInferInputFromSchema<DOM["actionSchema"][ID]>["SerdeInput"]): TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
2573
|
+
serializeInput(raw: TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"]): TInferInputFromSchema<DOM["actionSchema"][ID]>["SerdeInput"];
|
|
2574
|
+
validateInput(input: unknown): TInferInputFromSchema<DOM["actionSchema"][ID]>["Input"];
|
|
2575
|
+
validateOutput(output: unknown): TInferOutputFromSchema<DOM["actionSchema"][ID]>["Output"];
|
|
2576
|
+
}
|
|
2577
|
+
//#endregion
|
|
2578
|
+
//#region src/ActionRuntime/ActionRuntime.d.ts
|
|
2579
|
+
declare class ActionRuntime {
|
|
2580
|
+
private _coordinate;
|
|
2581
|
+
readonly timeCreated: number;
|
|
2582
|
+
readonly runtimeInfo: IRuntimeMeta;
|
|
2583
|
+
private readonly actionRouter;
|
|
2584
|
+
private readonly _pendingRunningActions;
|
|
2585
|
+
private readonly _registeredPeerHandlers;
|
|
2586
|
+
private _applied;
|
|
2587
|
+
static getDefault(): ActionRuntime;
|
|
2588
|
+
constructor(coordinate: RuntimeCoordinate);
|
|
2589
|
+
get coordinate(): RuntimeCoordinate;
|
|
2590
|
+
specifyRuntimeCoordinate(specifics: IRuntimeCoordinateSpecifics & {
|
|
2591
|
+
envId?: string;
|
|
2592
|
+
}): void;
|
|
2593
|
+
registerRunningAction(ra: RunningAction<any, any>): void;
|
|
2594
|
+
resolveIncomingActionPayload(json: TActionPayload_Any_JsonObject<any, any>): void;
|
|
2595
|
+
/**
|
|
2596
|
+
* Handle an incoming action wire (e.g. from a transport layer), route it to
|
|
2597
|
+
* the correct handler, and return the response. The most specific handler
|
|
2598
|
+
* match is chosen (action-ID-specific beats domain-wildcard).
|
|
2599
|
+
*/
|
|
2600
|
+
handleActionPayloadWire<D extends IActionDomain, ID extends keyof D["actionSchema"] & string>(wire: TActionPayload_Any_JsonObject<D, ID>): Promise<RunningAction<D, ID>>;
|
|
2601
|
+
handleActionPayloadWire(wire: unknown): Promise<RunningAction<any, any>>;
|
|
2602
|
+
handleActionPayload<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: TActionPayload_Any_Instance<DOM, ID>, options?: Omit<IHandleActionOptions, "targetLocalRuntime">): Promise<RunningAction<DOM, ID>>;
|
|
2603
|
+
/**
|
|
2604
|
+
* @internal
|
|
2605
|
+
*
|
|
2606
|
+
* Return the first handler registered for the given action, or `undefined`
|
|
2607
|
+
* if none has been registered (action-ID-specific beats domain-wildcard).
|
|
2608
|
+
*/
|
|
2609
|
+
_getHandlerForAction<ACT extends TActionPayload_Any_Instance<any, any>>(action: ACT, options?: Omit<IHandleActionOptions, "targetLocalRuntime">): TActionHandler | undefined;
|
|
2610
|
+
getHandlerForActionOrThrow<ACT extends TActionPayload_Any_Instance<any, any>>(action: ACT, options?: Omit<IHandleActionOptions, "localRuntime">): TActionHandler;
|
|
2611
|
+
/**
|
|
2612
|
+
* Register one or more handlers. Each handler's own `actionRouter` defines
|
|
2613
|
+
* which domains/actions it handles — those routing keys are mirrored into
|
|
2614
|
+
* this runtime's router so the same action can be served by multiple handlers.
|
|
2615
|
+
* Duplicate registrations (same handler cuid for the same key) are skipped.
|
|
2616
|
+
*/
|
|
2617
|
+
addHandlers(handlers: TActionRuntimeHandler[]): this;
|
|
2618
|
+
/**
|
|
2619
|
+
* @internal Low-level primitive — the public way to open a connection is `connectChannel`, which
|
|
2620
|
+
* derives routing from a channel and binds the crypto identity for you. This stays as the raw building
|
|
2621
|
+
* block it sits on (it restates domain lists by hand) and is not part of the supported surface.
|
|
2622
|
+
*
|
|
2623
|
+
* Declare an external "backend client" in one call: build an
|
|
2624
|
+
* {@link ConnectorHandler} for `externalCoordinate` carrying the given
|
|
2625
|
+
* `transports`, route the listed `domains`/`actions` to it, register it (plus any
|
|
2626
|
+
* `localHandlers` — e.g. server→client push handlers that share the same channel)
|
|
2627
|
+
* on this runtime, and `apply()`. Returns the external handler so the caller can
|
|
2628
|
+
* later `clearTransportCache()` it.
|
|
2629
|
+
*/
|
|
2630
|
+
connectTo(externalCoordinate: RuntimeCoordinate, options: {
|
|
2631
|
+
transports: Transport[];
|
|
2632
|
+
domains?: ActionDomain<any>[];
|
|
2633
|
+
actions?: ActionCore<any, any>[];
|
|
2634
|
+
localHandlers?: TActionRuntimeHandler[];
|
|
2635
|
+
defaultTimeout?: number;
|
|
2636
|
+
}): ConnectorHandler;
|
|
2637
|
+
private applyRuntimeForDomain;
|
|
2638
|
+
/**
|
|
2639
|
+
* Register this runtime with all root domains covered by its currently-added handlers,
|
|
2640
|
+
* making it eligible to execute actions dispatched from those domains.
|
|
2641
|
+
* After apply() is called, any subsequent addHandlers() calls also auto-register.
|
|
2642
|
+
*/
|
|
2643
|
+
apply(): this;
|
|
2644
|
+
/**
|
|
2645
|
+
* Find the best registered external handler that can reach `originClient` directly.
|
|
2646
|
+
* Used to locate the return-path channel for dispatching results back to the action origin.
|
|
2647
|
+
* Returns `undefined` if no handler matches (score > 0 required, i.e. at least id must match).
|
|
2648
|
+
*
|
|
2649
|
+
* A handler that currently holds the origin's *live* connection always wins over a mere coordinate
|
|
2650
|
+
* match — so with several duplex acceptors (e.g. WS + WebRTC) a result/push routes back over the carrier
|
|
2651
|
+
* the client actually connected on, never a same-coordinate sibling that lacks the socket. Only when no
|
|
2652
|
+
* handler owns a live connection do we fall back to the plain best-coordinate-score pick (the
|
|
2653
|
+
* single-acceptor and connector-only cases, unchanged).
|
|
2654
|
+
*/
|
|
2655
|
+
getReturnHandlerForOrigin(originClient: RuntimeCoordinate): PeerLinkHandler | undefined;
|
|
2656
|
+
resetRuntime(): void;
|
|
2657
|
+
private _trySetupReturnDispatch;
|
|
2658
|
+
}
|
|
2659
|
+
//#endregion
|
|
2660
|
+
//#region src/ActionDefinition/Domain/ActionDomain.d.ts
|
|
2661
|
+
type TActionMap<ACT_DOM extends IActionDomain> = { [K in keyof ACT_DOM["actionSchema"] & string]: ActionCore<ACT_DOM, K> };
|
|
2662
|
+
declare class ActionDomain<ACT_DOM extends IActionDomain = IActionDomain> extends ActionDomainBase<ACT_DOM> {
|
|
2663
|
+
private _rootDomain;
|
|
2664
|
+
private readonly _actionMap;
|
|
2665
|
+
constructor(definition: ACT_DOM, {
|
|
2666
|
+
rootDomain
|
|
2667
|
+
}: {
|
|
2668
|
+
rootDomain: ActionRootDomain<any>;
|
|
2669
|
+
});
|
|
2670
|
+
get rootDomain(): ActionRootDomain<any>;
|
|
2671
|
+
/**
|
|
2672
|
+
* @internal
|
|
2673
|
+
* All action observers that should see actions on this domain: the root domain's
|
|
2674
|
+
* observers plus this subdomain's own. Mirrors the listener set the local-dispatch
|
|
2675
|
+
* path assembles in `runAction`/`_runAction`, so inbound actions (pushed from a
|
|
2676
|
+
* backend or another client) can be wired up identically and surface in devtools.
|
|
2677
|
+
*/
|
|
2678
|
+
_collectActionObservers(): TRunningActionUpdateListener<any, any>[];
|
|
2679
|
+
_registerRuntime(runtime: ActionRuntime): void;
|
|
2680
|
+
createChildDomain<SUB_DOM extends IActionDomainChildOptions>(subDomainDef: SUB_DOM & { [K in Exclude<keyof SUB_DOM, keyof IActionDomainChildOptions>]: never }): ActionDomain<TActionDomainChildDef<ACT_DOM, SUB_DOM>>;
|
|
2681
|
+
get action(): TActionMap<ACT_DOM>;
|
|
2682
|
+
actionsMap(): TActionMap<ACT_DOM>;
|
|
2683
|
+
actionForId<ID extends keyof ACT_DOM["actionSchema"] & string>(id: ID): ActionCore<ACT_DOM, ID>;
|
|
2684
|
+
wrapAsPartialLocalHandler(wrappedActionExecutor: Partial<TWrappableDomainActionHandler<ACT_DOM>>): ActionLocalHandler;
|
|
2685
|
+
wrapAsLocalHandler(wrappedActionExecutor: TWrappableDomainActionHandler<ACT_DOM>): ActionLocalHandler;
|
|
2686
|
+
hydrateContext<ID extends keyof ACT_DOM["actionSchema"] & string>(id: ID, contextData: IActionContext_Data_JsonObject): ActionContext<ACT_DOM, ID>;
|
|
2687
|
+
isDomainAction<ACT extends IActionBase<any, ACT_DOM, any>>(action: ACT | unknown | null | undefined): action is TDistributedDomainActions<ACT_DOM, ACT>;
|
|
2688
|
+
hydrateRequestPayload<ID extends keyof ACT_DOM["actionSchema"] & string, P extends IActionPayload_Request_JsonObject<ACT_DOM, ID>>(serialized: P): TDistributeActionPayload_Request<ACT_DOM, ID>;
|
|
2689
|
+
hydrateResultPayload<ID extends keyof ACT_DOM["actionSchema"] & string, R extends IActionPayload_Result_JsonObject<ACT_DOM, ID>>(serialized: R): TDistributeActionPayload_Result<ACT_DOM, ID>;
|
|
2690
|
+
hydrateAnyAction<ID extends keyof ACT_DOM["actionSchema"] & string, AJ extends TAction_Any_JsonObject<ACT_DOM, ID>>(actionJson: AJ): TNarrowActionJsonTypeToActionInstanceType<ACT_DOM, AJ, ID>;
|
|
2691
|
+
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>>;
|
|
2692
|
+
private createActionMap;
|
|
2693
|
+
}
|
|
2694
|
+
//#endregion
|
|
2695
|
+
//#region src/ActionDefinition/Action/ActionBase.types.d.ts
|
|
2696
|
+
declare enum EActionForm {
|
|
2697
|
+
core = "core",
|
|
2698
|
+
context = "context",
|
|
2699
|
+
data = "data"
|
|
2700
|
+
}
|
|
2701
|
+
interface INiceActionIdAndDomain<DOM extends IActionDomain = IActionDomain> {
|
|
2702
|
+
domain: DOM["domain"];
|
|
2703
|
+
id: keyof DOM["actionSchema"] & string;
|
|
2704
|
+
}
|
|
2705
|
+
interface IActionBase<FORM extends EActionForm, DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> extends INiceActionIdAndDomain<DOM> {
|
|
2706
|
+
id: ID;
|
|
2707
|
+
form: FORM;
|
|
2708
|
+
_domain: ActionDomain<DOM>;
|
|
2709
|
+
allDomains: DOM["allDomains"];
|
|
2710
|
+
schema: DOM["actionSchema"][ID];
|
|
2711
|
+
}
|
|
2712
|
+
interface IActionBase_JsonObject<FORM extends EActionForm = EActionForm, DOM extends IActionDomain = IActionDomain, ID extends keyof DOM["actionSchema"] & string = keyof DOM["actionSchema"] & string> {
|
|
2713
|
+
form: FORM;
|
|
2714
|
+
domain: DOM["domain"];
|
|
2715
|
+
allDomains: DOM["allDomains"];
|
|
2716
|
+
id: ID;
|
|
2717
|
+
}
|
|
2718
|
+
//#endregion
|
|
2719
|
+
//#region src/ActionDefinition/Action/Action.combined.types.d.ts
|
|
2720
|
+
/**
|
|
2721
|
+
* Distributes a union ID into a proper discriminated union of ActionPayload_Request instances,
|
|
2722
|
+
* so that narrowing on `.id` also narrows `.input`.
|
|
2723
|
+
*/
|
|
2724
|
+
type TDistributeActionPayload_Request<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string> = ID extends keyof DOM["actionSchema"] & string ? ActionPayload_Request<DOM, ID> : never;
|
|
2725
|
+
/**
|
|
2726
|
+
* Distributes a union ID into a proper discriminated union of ActionPayload_Result instances,
|
|
2727
|
+
* so that narrowing on `.id` also narrows `.result`.
|
|
2728
|
+
*/
|
|
2729
|
+
type TDistributeActionPayload_Result<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string> = ID extends keyof DOM["actionSchema"] & string ? ActionPayload_Result<DOM, ID> : never;
|
|
2730
|
+
/**
|
|
2731
|
+
*
|
|
2732
|
+
* COMBINED JSON TYPES
|
|
2733
|
+
*
|
|
2734
|
+
*/
|
|
2735
|
+
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>;
|
|
2736
|
+
/**
|
|
2737
|
+
*
|
|
2738
|
+
* UTILITY TYPES
|
|
2739
|
+
*
|
|
2740
|
+
*/
|
|
2741
|
+
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];
|
|
2742
|
+
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;
|
|
2743
|
+
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;
|
|
2744
|
+
//#endregion
|
|
2745
|
+
//#region src/ActionRuntime/Handler/PeerLink/Acceptor/AcceptorHandler.d.ts
|
|
2746
|
+
/** The codec shape `AcceptorHandler` uses to pack/unpack frames — same as the Link transport's. */
|
|
2747
|
+
type TActionChannelFormatMessage = IActionWireFormat;
|
|
2748
|
+
/** How a connection encodes its frames, remembered so we answer each client in its own dialect. */
|
|
2749
|
+
type TActionConnectionEncoding = "json" | "binary";
|
|
2750
|
+
/** A connection's restorable identity — what to persist so a binding survives transport eviction. */
|
|
2751
|
+
interface IAcceptorConnectionBinding {
|
|
2752
|
+
/** Full client coordinate, so `originClient` can be re-injected into frames that omit it. */
|
|
2753
|
+
client: IRuntimeCoordinate;
|
|
2754
|
+
encoding: TActionConnectionEncoding;
|
|
2755
|
+
/**
|
|
2756
|
+
* Secure-session state (set once a connection's handshake completes). Persist it alongside the
|
|
2757
|
+
* binding so an authenticated/encrypted connection resumes after eviction without re-handshaking —
|
|
2758
|
+
* the `keyMaterial` lets the server re-derive the shared key from its own persisted identity.
|
|
2759
|
+
*/
|
|
2760
|
+
secure?: {
|
|
2761
|
+
securityLevel: ESecurityLevel;
|
|
2762
|
+
linkedClientId: TTypeAndId;
|
|
2763
|
+
keyMaterial?: IHandshakeEncryptionKeyMaterial;
|
|
2764
|
+
};
|
|
2765
|
+
}
|
|
2766
|
+
/**
|
|
2767
|
+
* Server-side secure-channel config. When set, each connection negotiates a level from
|
|
2768
|
+
* {@link securityLevel}: an `authenticated`/`encrypted` client must complete the handshake (and is then
|
|
2769
|
+
* bound to its *authenticated* coordinate) before any action frame is accepted. A `none` client (only
|
|
2770
|
+
* when `none` is in the allowed set) is accepted as-is with a self-asserted identity. For the
|
|
2771
|
+
* `encrypted` level the codec source should be a session factory (`createFormatMessage`).
|
|
2772
|
+
*/
|
|
2773
|
+
interface IAcceptorSecurity {
|
|
2774
|
+
/**
|
|
2775
|
+
* Accepted level(s). A single level is strict; an array is a negotiable allowed set — the server
|
|
2776
|
+
* adopts whichever level each client requests (e.g. `[none, authenticated, encrypted]` serves all
|
|
2777
|
+
* three over one endpoint).
|
|
2778
|
+
*/
|
|
2779
|
+
securityLevel: ESecurityLevel | readonly ESecurityLevel[];
|
|
2780
|
+
/** This server's crypto identity (verify + exchange key pairs, optionally persisted). */
|
|
2781
|
+
link: ClientCryptoKeyLink;
|
|
2782
|
+
/** This server's coordinate — its identity to clients during the handshake. */
|
|
2783
|
+
localCoordinate: IRuntimeCoordinate;
|
|
2784
|
+
/** Wire dictionary version; the handshake rejects a client on a mismatch. */
|
|
2785
|
+
dictionaryVersion: string;
|
|
2786
|
+
/** Trust decision for a client's verify key (defaults to in-memory TOFU inside the handshake). */
|
|
2787
|
+
verifyKeyResolver?: IClientVerifyKeyResolver;
|
|
2788
|
+
}
|
|
2789
|
+
interface IAcceptorHandlerBaseOptions<TConn> {
|
|
2790
|
+
/**
|
|
2791
|
+
* Coordinate of the *connecting clients* (typically env-only, e.g. `RuntimeCoordinate.env("web_app")`).
|
|
2792
|
+
* The runtime's return-path dispatch scores incoming actions' `originClient` against this to pick
|
|
2793
|
+
* this handler for sending results/pushes back over the right channel.
|
|
2794
|
+
*/
|
|
2795
|
+
clientEnv: RuntimeCoordinate;
|
|
2796
|
+
/** Write an encoded frame to a specific live connection (e.g. `(ws, frame) => ws.send(frame)`). */
|
|
2797
|
+
send: (connection: TConn, frame: string | Uint8Array | ArrayBuffer) => void;
|
|
2798
|
+
/**
|
|
2799
|
+
* The runtime this handler belongs to. When set, {@link AcceptorHandler.broadcast} can be called
|
|
2800
|
+
* without threading a runtime through each call. Optional — `pushToClient` still takes one explicitly.
|
|
2801
|
+
*/
|
|
2802
|
+
runtime?: ActionRuntime;
|
|
2803
|
+
/** Timeout (ms) applied to server-initiated actions awaiting a client response. */
|
|
2804
|
+
defaultTimeout?: number;
|
|
2805
|
+
/**
|
|
2806
|
+
* Called once when a connection is first bound to a client identity. Use it to persist the binding
|
|
2807
|
+
* for transports that can resume after eviction — e.g. a Durable Object's hibernatable WebSocket:
|
|
2808
|
+
* `(ws, binding) => ws.serializeAttachment(binding)` — then replay it via {@link AcceptorHandler.rehydrateConnection}
|
|
2809
|
+
* when the channel comes back.
|
|
2810
|
+
*/
|
|
2811
|
+
onConnectionBound?: (connection: TConn, binding: IAcceptorConnectionBinding) => void;
|
|
2812
|
+
/**
|
|
2813
|
+
* Enable the authenticated (optionally encrypted) handshake. When omitted, connections are trusted
|
|
2814
|
+
* as-is (identity self-asserted) — fine for dev / trusted networks.
|
|
2815
|
+
*/
|
|
2816
|
+
security?: IAcceptorSecurity;
|
|
2817
|
+
}
|
|
2818
|
+
/**
|
|
2819
|
+
* Provide exactly one codec source:
|
|
2820
|
+
* - `formatMessage` — a single shared codec for every connection (stateless, e.g. `createBinaryWireAdapter`).
|
|
2821
|
+
* - `createFormatMessage` — a per-connection factory for stateful codecs (e.g.
|
|
2822
|
+
* `createBinaryWireSessionFactory`, whose sessions hold correlation + identity state). Required for the
|
|
2823
|
+
* leanest binary wire; the handler creates and caches one codec per connection.
|
|
2824
|
+
*/
|
|
2825
|
+
type IAcceptorHandlerOptions<TConn> = IAcceptorHandlerBaseOptions<TConn> & ({
|
|
2826
|
+
formatMessage: TActionChannelFormatMessage;
|
|
2827
|
+
createFormatMessage?: never;
|
|
2828
|
+
} | {
|
|
2829
|
+
createFormatMessage: () => TActionChannelFormatMessage;
|
|
2830
|
+
formatMessage?: never;
|
|
2831
|
+
});
|
|
2832
|
+
/**
|
|
2833
|
+
* A connection-aware execution case (see {@link AcceptorHandler.forConnectionDomainCases}). It receives
|
|
2834
|
+
* the primed request plus a per-invocation `context` — whatever the wiring's context mapper produces from
|
|
2835
|
+
* the originating connection. The low-level handler passes the raw connection (`TConn | undefined`); the
|
|
2836
|
+
* higher-level `serveChannel` enriches it into an `IConnectionContext` (state + broadcast + pushBack). A
|
|
2837
|
+
* case may return the action's raw output, a result payload, or nothing (auto-wrapped as an empty
|
|
2838
|
+
* success) — exactly like a local handler case.
|
|
2839
|
+
*/
|
|
2840
|
+
type TAcceptorCaseFn<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string, TCtx> = (action: TDistributeActionPayload_Request<DOM, ID>, context: TCtx) => ReturnType<THandleActionExecutionFn<DOM, ID>> | void;
|
|
2841
|
+
/**
|
|
2842
|
+
* The connection-aware case the bare {@link AcceptorHandler} serves: its `context` is the originating
|
|
2843
|
+
* client's live connection (resolved from the request's `originClient`, `undefined` if the socket is
|
|
2844
|
+
* gone). It's {@link TAcceptorCaseFn} fixed to `TConn | undefined` — the un-enriched shape used by
|
|
2845
|
+
* {@link AcceptorHandler.forConnectionDomainCases} and `acceptChannelConnections`.
|
|
2846
|
+
*/
|
|
2847
|
+
type TAcceptorConnectionCaseFn<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string, TConn> = TAcceptorCaseFn<DOM, ID, TConn | undefined>;
|
|
2848
|
+
/**
|
|
2849
|
+
* Server-side handler for backends that accept many client connections over a single open channel
|
|
2850
|
+
* (WebSockets, Durable Objects, …). It is transport-agnostic: you feed it inbound frames with
|
|
2851
|
+
* {@link receive} and tell it how to write outbound frames via the `send` option.
|
|
2852
|
+
*
|
|
2853
|
+
* Add it alongside your local execution handler:
|
|
2854
|
+
* ```ts
|
|
2855
|
+
* const serverHandler = createAcceptorHandler({ clientEnv, formatMessage, send: (ws, f) => ws.send(f) });
|
|
2856
|
+
* runtime.addHandlers([localHandler, serverHandler]);
|
|
2857
|
+
* // per inbound message (e.g. a Durable Object's webSocketMessage):
|
|
2858
|
+
* serverHandler.receive(ws, message);
|
|
2859
|
+
* ```
|
|
2860
|
+
*
|
|
2861
|
+
* Inbound requests route to your local handler; the runtime's return dispatch then calls this
|
|
2862
|
+
* handler back (it is an external handler keyed to `clientEnv`) to send the result to the originating
|
|
2863
|
+
* connection. The handler keeps a per-connection identity registry so each result lands on the right
|
|
2864
|
+
* socket, and remembers each connection's encoding so binary and JSON clients can share the channel.
|
|
2865
|
+
*
|
|
2866
|
+
* It registers an empty action router, so it is never chosen to *execute* an inbound request — only
|
|
2867
|
+
* to ferry results/pushes back out.
|
|
2868
|
+
*/
|
|
2869
|
+
declare class AcceptorHandler<TConn = unknown> extends PeerLinkHandler {
|
|
2870
|
+
/** Accept-in over a live (duplex) connection registry — it pushes results/broadcasts to bound sockets. */
|
|
2871
|
+
readonly canPush = true;
|
|
2872
|
+
private readonly _formatMessage?;
|
|
2873
|
+
private readonly _createFormatMessage?;
|
|
2874
|
+
private readonly _send;
|
|
2875
|
+
private readonly _runtime?;
|
|
2876
|
+
private readonly _serverTimeout;
|
|
2877
|
+
private _onConnectionBound?;
|
|
2878
|
+
private readonly _security?;
|
|
2879
|
+
/** Normalized accepted levels; whether `none` (plain) is allowed; whether any level needs a handshake. */
|
|
2880
|
+
private readonly _allowedLevels;
|
|
2881
|
+
private readonly _noneAllowed;
|
|
2882
|
+
private readonly _handshakeMode;
|
|
2883
|
+
private readonly _connByClient;
|
|
2884
|
+
private readonly _clientByConn;
|
|
2885
|
+
private readonly _connEncoding;
|
|
2886
|
+
private readonly _codecByConn;
|
|
2887
|
+
private readonly _sessionByConn;
|
|
2888
|
+
constructor(options: IAcceptorHandlerOptions<TConn>);
|
|
2889
|
+
/**
|
|
2890
|
+
* The codec for a connection: a per-connection session (cached) when a factory was provided, else
|
|
2891
|
+
* the single shared `formatMessage`.
|
|
2892
|
+
*/
|
|
2893
|
+
private _codecFor;
|
|
2894
|
+
/**
|
|
2895
|
+
* Register (or replace) the connection-bound persistence callback after construction. Used by
|
|
2896
|
+
* lifecycle helpers like {@link createHibernatableWsServerAdapter} so persistence and replay are
|
|
2897
|
+
* owned by one place instead of being split across the constructor options.
|
|
2898
|
+
*/
|
|
2899
|
+
setOnConnectionBound(onConnectionBound: (connection: TConn, binding: IAcceptorConnectionBinding) => void): void;
|
|
2900
|
+
/**
|
|
2901
|
+
* Feed one inbound frame from a connection into the runtime. Decodes text or binary, binds the
|
|
2902
|
+
* connection to the requesting client's identity, then routes it (requests execute locally;
|
|
2903
|
+
* results/progress resolve pending server-initiated actions).
|
|
2904
|
+
*/
|
|
2905
|
+
receive(connection: TConn, frame: string | ArrayBuffer | Uint8Array): void;
|
|
2906
|
+
private _receivePlain;
|
|
2907
|
+
/**
|
|
2908
|
+
* The secure session for a connection (built lazily on its first secure-mode frame), with the
|
|
2909
|
+
* handler-owned effects — raw send, identity binding + persistence, and inbound routing — wired in as
|
|
2910
|
+
* callbacks. The session owns all crypto/handshake/chain state; the handler keeps only the registry.
|
|
2911
|
+
*/
|
|
2912
|
+
private _sessionFor;
|
|
2913
|
+
/** Bind + persist a connection's authenticated identity once its handshake completes. */
|
|
2914
|
+
private _onConnectionAuthenticated;
|
|
2915
|
+
/** Decode a decrypted authenticated frame, inject the *authenticated* identity, and route it. */
|
|
2916
|
+
private _routeAuthedActionBytes;
|
|
2917
|
+
/**
|
|
2918
|
+
* Ensure an inbound request carries the client's identity and that this connection is bound to it,
|
|
2919
|
+
* so its result can be routed back. A session codec omits `originClient` after the first request, so
|
|
2920
|
+
* when it's missing we restore it from the (possibly rehydrated) binding instead. (Plain mode only;
|
|
2921
|
+
* secure mode binds the authenticated coordinate at handshake time.)
|
|
2922
|
+
*/
|
|
2923
|
+
private _resolveRequestIdentity;
|
|
2924
|
+
/**
|
|
2925
|
+
* Restore a connection→client binding without an inbound frame — for transports that resume after
|
|
2926
|
+
* eviction. Pair it with the {@link IAcceptorHandlerOptions.onConnectionBound} hook: persist
|
|
2927
|
+
* the binding there, then replay each live connection here when the channel comes back (e.g. a
|
|
2928
|
+
* Durable Object iterating `ctx.getWebSockets()` as it wakes from hibernation).
|
|
2929
|
+
*/
|
|
2930
|
+
rehydrateConnection(connection: TConn, binding: IAcceptorConnectionBinding): void;
|
|
2931
|
+
toJsonObject(): IActionHandler_Peer_Json;
|
|
2932
|
+
toHandlerRouteItem(): IActionRouteItemHandler;
|
|
2933
|
+
/** Forget a connection (call on socket close) so stale entries don't misroute later results. */
|
|
2934
|
+
dropConnection(connection: TConn): void;
|
|
2935
|
+
/** Live connection for a client coordinate, if currently registered. */
|
|
2936
|
+
getConnectionForClient(client: RuntimeCoordinate): TConn | undefined;
|
|
2937
|
+
/** This acceptor owns the origin's return path when it currently holds a live connection bound to it. */
|
|
2938
|
+
ownsLiveConnectionFor(origin: RuntimeCoordinate): boolean;
|
|
2939
|
+
/** Whether this acceptor currently tracks `connection` — used to pick the owning handler among several. */
|
|
2940
|
+
hasConnection(connection: TConn): boolean;
|
|
2941
|
+
/**
|
|
2942
|
+
* Send (and optionally await) a server-initiated action to a specific connected client. Pass the
|
|
2943
|
+
* connection token directly (e.g. the `ws`) or a client `RuntimeCoordinate` to look one up.
|
|
2944
|
+
*/
|
|
2945
|
+
pushToClient<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(runtime: ActionRuntime, target: TConn | RuntimeCoordinate, request: ActionPayload_Request<DOM, ID>, options?: {
|
|
2946
|
+
timeout?: number;
|
|
2947
|
+
}): RunningAction<DOM, ID>;
|
|
2948
|
+
/**
|
|
2949
|
+
* Build a local handler whose cases are connection-aware: each case receives the primed request and
|
|
2950
|
+
* the originating client's live connection (resolved from `originClient`), so handlers don't repeat
|
|
2951
|
+
* the `getConnectionForClient(action.context.originClient)` lookup. Cases may return raw output or
|
|
2952
|
+
* nothing, just like {@link ActionLocalHandler.forDomainActionCases}. Add the returned handler to the
|
|
2953
|
+
* runtime alongside this server handler:
|
|
2954
|
+
* ```ts
|
|
2955
|
+
* runtime.addHandlers([serverHandler.forConnectionDomainCases(domain, { … }), serverHandler]);
|
|
2956
|
+
* ```
|
|
2957
|
+
*/
|
|
2958
|
+
forConnectionDomainCases<FOR_DOM extends IActionDomain>(domain: ActionDomain<FOR_DOM>, cases: { [ID in keyof FOR_DOM["actionSchema"] & string]?: TAcceptorConnectionCaseFn<FOR_DOM, ID, TConn> }): ActionLocalHandler;
|
|
2959
|
+
/**
|
|
2960
|
+
* Like {@link forConnectionDomainCases} but spanning several domains with one merged case map — used
|
|
2961
|
+
* by channel-derived wiring (`acceptChannelConnections` / `serveChannel`) where the channel's
|
|
2962
|
+
* `toAcceptor` domains are served together. Each domain takes only the cases whose ids it owns, so a
|
|
2963
|
+
* single map can cover several domains and unrelated ids are ignored.
|
|
2964
|
+
*
|
|
2965
|
+
* `mapContext` turns the resolved connection into whatever the case's second argument should be: the
|
|
2966
|
+
* raw connection for the low-level helper, or an enriched `IConnectionContext` for `serveChannel`. It's
|
|
2967
|
+
* called once per inbound action, after the originating connection is resolved.
|
|
2968
|
+
*/
|
|
2969
|
+
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;
|
|
2970
|
+
/**
|
|
2971
|
+
* Fan a server-initiated request out to every currently-bound connection. A fresh request is built
|
|
2972
|
+
* per connection (each push mutates its own action context) and dispatched fire-and-forget. Pass
|
|
2973
|
+
* `except` to skip the originating socket and `where` to filter by connection (e.g. read its
|
|
2974
|
+
* attachment for a role). Iterating bound connections (rather than every accepted socket) skips
|
|
2975
|
+
* sockets that are still mid-handshake and so can't yet receive a frame.
|
|
2976
|
+
*/
|
|
2977
|
+
broadcast<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(makeRequest: () => ActionPayload_Request<DOM, ID>, options?: {
|
|
2978
|
+
runtime?: ActionRuntime;
|
|
2979
|
+
except?: TConn | null;
|
|
2980
|
+
where?: (connection: TConn) => boolean;
|
|
2981
|
+
timeout?: number;
|
|
2982
|
+
onError?: (error: unknown, connection: TConn) => void;
|
|
2983
|
+
}): void;
|
|
2984
|
+
sendReturnPayload(payload: TActionPayload_Any_Instance<any, any>, config: {
|
|
2985
|
+
targetLocalRuntime: ActionRuntime;
|
|
2986
|
+
}): Promise<boolean>;
|
|
2987
|
+
handleActionRequest<DOM extends IActionDomain, ID extends keyof DOM["actionSchema"] & string>(action: ActionPayload_Request<DOM, ID>, config?: IHandleActionOptions): Promise<RunningAction<DOM, ID>>;
|
|
2988
|
+
private _dispatch;
|
|
2989
|
+
private _sendPayload;
|
|
2990
|
+
private _bindConnection;
|
|
2991
|
+
private _resolveConnection;
|
|
2992
|
+
private _resolveSingleConnection;
|
|
2993
|
+
}
|
|
2994
|
+
declare const createAcceptorHandler: <TConn = unknown>(options: IAcceptorHandlerOptions<TConn>) => AcceptorHandler<TConn>;
|
|
2995
|
+
//#endregion
|
|
2996
|
+
export { rtcCarrier as $, MaybePromise as $n, IActionTransportInitialized as $t, TActionResultOutcome as A, TransportConnection as An, TInferOutputFromSchema as Ar, IConnectChannelOptions as At, IHttpCarrierOptions as B, IHandshakeEncryptionKeyMaterial as Bn, IActionWireFormat as Bt, IActionProgress_Custom as C, TSendActionDataMethod as Cn, IActionDomain as Cr, createHibernatableWsServerAdapter as Ct, TActionPayload_Any_Instance as D, TTransportStatusInfo as Dn, TActionDomainSchema as Dr, createConnectionStateStore as Dt, IActionRouteItemHandler as E, TTransportInitializationFinishedInfo as En, TActionDomainChildDef as Er, IConnectionStateStoreOptions as Et, decodeActionFrame as F, EHandshakeMessageType as Fn, TInferActionError as Fr, acceptChannelConnections as Ft, httpAcceptorCarrier as G, createInMemoryTofuVerifyKeyResolver as Gn, TCarrier as Gt, TCarrierFetch as H, IServerHandshakeConfig as Hn, IDuplexCarrierSource as Ht, EErrId_NiceAction as I, ESecurityLevel as In, actionSchema as Ir, connectChannel as It, IWsAcceptorCarrierOptions as J, decodeHandshakeMessage as Jn, createConnectorHandler as Jt, IWsCarrierOptions as K, createServerHandshake as Kn, TFrame$1 as Kt, err_nice_action as L, IClientHandshakeConfig as Ln, TActionSchemaOptions as Lr, defineChannel as Lt, isActionPayload_Request_JsonObject as M, Transport as Mn, TPossibleDomainIdList as Mr, TChannelAcceptorCases as Mt, isActionPayload_Any_JsonObject as N, ISecureAcceptorHandlerOptions as Nn, ActionSchema as Nr, TChannelPushHandlers as Nt, TActionPayload_Any_JsonObject as O, TTransportStatusInfo_GetTransport_Output as On, TDomainActionId as Or, IAcceptChannelOptions as Ot, IActionFrameDecoder as P, createSecureAcceptorHandler as Pn, EActionResponseMode as Pr, acceptChannel as Pt, IRtcCarrierOptions as Q, createLocalHandler as Qn, IActionTransportDef as Qt, EErrId_NiceTransport as R, IClientVerifyKeyResolveInput as Rn, TActionSerializationDefinition as Rr, IBinaryWireSessionOptions as Rt, IActionPayload_Result_JsonObject as S, TOnResolveIncomingResponseJson as Sn, IActionCore_JsonObject as Sr, IHibernatableWsServerAdapterOptions as St, IActionProgress_Percentage as T, TTransportCache as Tn, IActionRootDomain as Tr, IConnectionAttachment as Tt, httpCarrier as U, THandshakeMessage as Un, IExchangeCarrier as Ut, IHttpCarrierRequest as V, IHandshakeResult as Vn, IDuplexCarrier as Vt, IHttpAcceptorCarrierOptions as W, createClientHandshake as Wn, IExchangeCarrierSource as Wt, EErrId_NiceTransport_WebSocket as X, runtimeLinkId as Xn, ETransportShape as Xt, wsAcceptorCarrier as Y, encodeHandshakeMessage as Yn, PeerLinkHandler as Yt, err_nice_transport_ws as Z, ActionLocalHandler as Zn, ETransportStatus as Zt, IActionPayload_Data_Base as _, TOnResolveAnyIncomingActionData as _n, IRuntimeFullCoordinates as _r, IDuplexAcceptorCarrier as _t, TAcceptorConnectionCaseFn as a, ITransportDispatchAction as an, ERunningActionUpdateType as ar, IInMemoryServerEndpoint as at, IActionPayload_Request_JsonObject as b, TOnResolveIncomingRequestJson as bn, TRuntimeCoordinateStringId as br, isExchangeAcceptorCarrier as bt, createAcceptorHandler as c, ITransportRouteClientParams as cn, IRunningActionUpdate_Started as cr, IChannelHostAdapter as ct, ActionCore as d, ITransportStatusInfo_Failed as dn, TRunningActionUpdateFinished as dr, IChannelServer as dt, IActionTransportReady as en, createActionRootDomain as er, IRtcDataChannelLike as et, ActionPayload_Request as f, ITransportStatusInfo_Initializing as fn, TRunningActionUpdateListener as fr, IConnectionContext as ft, IActionPayload_Base_JsonObject as g, TGetTransportFn as gn, IRuntimeCoordinateSpecifics as gr, IAcceptorAttachmentStore as gt, IActionPayload_Base as h, IUpdateActionRunConfig_Output as hn, IRuntimeCoordinate as hr, serveChannel as ht, TAcceptorCaseFn as i, ISecureClientConfig as in, ERunningActionState as ir, IInMemoryChannelPair as it, isActionPayload_Result_JsonObject as j, ITransportConnectionContext as jn, TPossibleDomainId as jr, IConnectTransport as jt, TActionProgress as k, TUpdateActionRunConfig as kn, TInferInputFromSchema as kr, IActionChannel as kt, ActionDomain as l, ITransportRouteInfo as ln, IRunningActionUpdate_Success as lr, TServeHostOptions as lt, EActionProgressType as m, ITransportStatusInfo_Unsupported as mn, ActionPayload_Progress as mr, IServeConnectionStateOptions as mt, IAcceptorConnectionBinding as n, IActionTransportReadyData_Methods as nn, RunningAction as nr, IInMemoryCarrier as nt, TActionChannelFormatMessage as o, ITransportMethod_SendActionData_Input as on, IRunningActionUpdate_Abort as or, createInMemoryChannelPair as ot, EActionPayloadType as p, ITransportStatusInfo_Ready as pn, ActionPayload_Result as pr, IServeChannelOptions as pt, wsCarrier as q, createStorageTofuVerifyKeyResolver as qn, ConnectorHandler as qt, IAcceptorHandlerOptions as r, IActionTransportResolvers as rn, ERunningActionFinishedType as rr, inMemoryCarrier as rt, TActionConnectionEncoding as s, ITransportRouteActionParams as sn, IRunningActionUpdate_Progress as sr, err_nice_external_client as st, AcceptorHandler as t, IActionTransportReadyData_Base as tn, ActionRootDomain as tr, rtcDataChannelByteChannel as tt, ActionRuntime as u, ITransportStatusInfo_Base as un, TRunningActionUpdate as ur, serveHost as ut, IActionPayload_Progress as v, TOnResolveAnyIncomingActionData_Json as vn, RuntimeCoordinate as vr, IExchangeAcceptorCarrier as vt, IActionProgress_None as w, TSendReturnDataMethod as wn, IActionDomainChildOptions as wr, ConnectionStateStore as wt, IActionPayload_Result as x, TOnResolveIncomingResponse as xn, IActionCore as xr, IDuplexConnectionRouter as xt, IActionPayload_Progress_JsonObject as y, TOnResolveIncomingRequest as yn, TRuntimeCoordinateEnvId as yr, TAcceptorCarrier as yt, err_nice_transport as z, IClientVerifyKeyResolver as zn, TTransportedValue as zr, createBinaryWireSessionFactory as zt };
|
|
2997
|
+
//# sourceMappingURL=AcceptorHandler-11-QMdx2.d.mts.map
|