@nice-code/action 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -26
- package/build/{ActionPayload.types-B-OSg09t.d.mts → AcceptorHandler-BizUtq4u.d.mts} +1267 -1543
- package/build/{ActionPayload.types-DIOeVapm.d.cts → AcceptorHandler-CxPfZtIl.d.cts} +1267 -1543
- package/build/{ActionDevtoolsCore-BjbhFqc0.d.mts → ActionDevtoolsCore-D9KBBI2V.d.cts} +2 -2
- package/build/{ActionDevtoolsCore-kk7oZBv9.d.cts → ActionDevtoolsCore-xZjAtB4H.d.mts} +2 -2
- package/build/advanced/index.cjs +115 -0
- package/build/advanced/index.cjs.map +1 -0
- package/build/advanced/index.d.cts +249 -0
- package/build/advanced/index.d.mts +249 -0
- package/build/advanced/index.mjs +88 -0
- package/build/advanced/index.mjs.map +1 -0
- package/build/{httpAcceptorCarrier-DJVxzDVd.mjs → createHibernatableWsServerAdapter-BkjESd01.mjs} +243 -429
- package/build/createHibernatableWsServerAdapter-BkjESd01.mjs.map +1 -0
- package/build/{httpAcceptorCarrier-hYPuoNuP.cjs → createHibernatableWsServerAdapter-FSDWrxoF.cjs} +268 -478
- package/build/createHibernatableWsServerAdapter-FSDWrxoF.cjs.map +1 -0
- package/build/devtools/browser/index.d.cts +1 -1
- package/build/devtools/browser/index.d.mts +1 -1
- package/build/devtools/server/index.d.cts +1 -1
- package/build/devtools/server/index.d.mts +1 -1
- package/build/httpAcceptorCarrier-BQYaXI9j.cjs +454 -0
- package/build/httpAcceptorCarrier-BQYaXI9j.cjs.map +1 -0
- package/build/httpAcceptorCarrier-DWqsCz3h.mjs +401 -0
- package/build/httpAcceptorCarrier-DWqsCz3h.mjs.map +1 -0
- package/build/index.cjs +73 -449
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +2 -2
- package/build/index.d.mts +2 -2
- package/build/index.mjs +13 -365
- package/build/index.mjs.map +1 -1
- package/build/platform/cloudflare/index.cjs +45 -1
- package/build/platform/cloudflare/index.cjs.map +1 -1
- package/build/platform/cloudflare/index.d.cts +42 -4
- package/build/platform/cloudflare/index.d.mts +42 -4
- package/build/platform/cloudflare/index.mjs +45 -2
- package/build/platform/cloudflare/index.mjs.map +1 -1
- package/build/react-query/index.d.cts +1 -1
- package/build/react-query/index.d.mts +1 -1
- package/package.json +15 -4
- package/build/httpAcceptorCarrier-DJVxzDVd.mjs.map +0 -1
- package/build/httpAcceptorCarrier-hYPuoNuP.cjs.map +0 -1
package/build/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as ActionPayload_Request, B as EErrId_NiceTransport, E as createInMemoryTofuVerifyKeyResolver, G as ActionSchema, H as err_nice_external_client, J as isActionPayload_Result_JsonObject, K as EActionResponseMode, M as ActionLocalHandler, N as createLocalHandler, O as createStorageTofuVerifyKeyResolver, P as ActionRuntime, Q as RunningAction, S as decodeActionFrame, U as isActionPayload_Any_JsonObject, V as err_nice_transport, W as isActionPayload_Request_JsonObject, X as EErrId_NiceAction, Y as isAction_Base_JsonObject, Z as err_nice_action, a as ExchangeAcceptor, at as RuntimeCoordinate, c as decodeExchangeReply, et as ActionPayload_Result, it as ActionBase, j as runtimeLinkId, l as decodeExchangeRequest, nt as EActionProgressType, ot as runtimeCoordinateToStringIds, q as actionSchema, rt as ActionPayload, tt as EActionPayloadType, u as encodeExchange, w as ESecurityLevel } from "./createHibernatableWsServerAdapter-BkjESd01.mjs";
|
|
2
2
|
import { n as ERunningActionState, r as ERunningActionUpdateType, t as ERunningActionFinishedType } from "./RunningAction.types-C176rqHG.mjs";
|
|
3
|
+
import { a as isExchangeAcceptorCarrier, c as connectChannel, i as serveChannel, l as defineChannel, n as wsAcceptorCarrier, o as acceptChannel, r as serveHost, s as acceptChannelConnections, t as httpAcceptorCarrier } from "./httpAcceptorCarrier-DWqsCz3h.mjs";
|
|
3
4
|
import { nanoid } from "nanoid";
|
|
4
5
|
import { err } from "@nice-code/error";
|
|
5
|
-
import { pack, unpack } from "msgpackr";
|
|
6
6
|
//#region src/ActionDefinition/Action/Context/ActionContext.ts
|
|
7
7
|
var ActionContext = class extends ActionBase {
|
|
8
8
|
_domain;
|
|
@@ -471,275 +471,6 @@ const createActionRootDomain = (definition) => {
|
|
|
471
471
|
return new ActionRootDomain(definition);
|
|
472
472
|
};
|
|
473
473
|
//#endregion
|
|
474
|
-
//#region src/ActionRuntime/Transport/codec/actionWireCodec.ts
|
|
475
|
-
/**
|
|
476
|
-
* Tiny integer codes for the payload type, so the verbose `"request"`/`"result"`/`"progress"`
|
|
477
|
-
* strings never hit the wire. The index in {@link ReversePayloadType} must line up with the value.
|
|
478
|
-
*/
|
|
479
|
-
const PayloadTypeToInt = {
|
|
480
|
-
["request"]: 0,
|
|
481
|
-
["result"]: 1,
|
|
482
|
-
["progress"]: 2
|
|
483
|
-
};
|
|
484
|
-
const ReversePayloadType = [
|
|
485
|
-
"request",
|
|
486
|
-
"result",
|
|
487
|
-
"progress"
|
|
488
|
-
];
|
|
489
|
-
/**
|
|
490
|
-
* Build the positional `domain:id` ↔ integer dictionary. Both ends of a channel MUST build it from
|
|
491
|
-
* the same domains in the same order — the mapping is positional, so a mismatch routes to the wrong
|
|
492
|
-
* action. Add new transported domains to the end of the list.
|
|
493
|
-
*/
|
|
494
|
-
function buildActionRouteDictionary(domains) {
|
|
495
|
-
const routeToInt = /* @__PURE__ */ new Map();
|
|
496
|
-
const intToRoute = [];
|
|
497
|
-
for (const dom of domains) for (const actionId of Object.keys(dom.actionSchema)) {
|
|
498
|
-
const routeKey = `${dom.domain}:${actionId}`;
|
|
499
|
-
if (routeToInt.has(routeKey)) continue;
|
|
500
|
-
routeToInt.set(routeKey, intToRoute.length);
|
|
501
|
-
intToRoute.push({
|
|
502
|
-
domain: dom.domain,
|
|
503
|
-
id: actionId,
|
|
504
|
-
allDomains: dom.allDomains
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
return {
|
|
508
|
-
routeToInt,
|
|
509
|
-
intToRoute
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
/** Pull the type-specific payload (`input` / `result` / `progress`) out of a wire JSON object. */
|
|
513
|
-
function extractWirePayload(json) {
|
|
514
|
-
if (json.type === "request") return json.input;
|
|
515
|
-
if (json.type === "result") return json.result;
|
|
516
|
-
if (json.type === "progress") return json.progress;
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Reassemble a full wire JSON object from its decoded parts. `inputHash`/`outputHash` are emitted
|
|
520
|
-
* empty — the hydration constructors recompute them — and the result still satisfies
|
|
521
|
-
* `isActionPayload_Any_JsonObject` so it flows through validation like a JSON frame.
|
|
522
|
-
*/
|
|
523
|
-
function assembleWireJson(routeMeta, payloadType, time, context, payloadData) {
|
|
524
|
-
const base = {
|
|
525
|
-
form: "data",
|
|
526
|
-
domain: routeMeta.domain,
|
|
527
|
-
id: routeMeta.id,
|
|
528
|
-
allDomains: routeMeta.allDomains,
|
|
529
|
-
time,
|
|
530
|
-
context
|
|
531
|
-
};
|
|
532
|
-
if (payloadType === "request") return {
|
|
533
|
-
...base,
|
|
534
|
-
type: "request",
|
|
535
|
-
input: payloadData,
|
|
536
|
-
inputHash: ""
|
|
537
|
-
};
|
|
538
|
-
if (payloadType === "result") return {
|
|
539
|
-
...base,
|
|
540
|
-
type: "result",
|
|
541
|
-
result: payloadData,
|
|
542
|
-
outputHash: ""
|
|
543
|
-
};
|
|
544
|
-
return {
|
|
545
|
-
...base,
|
|
546
|
-
type: "progress",
|
|
547
|
-
progress: payloadData
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region src/ActionRuntime/Transport/codec/createBinaryWireSessionFactory.ts
|
|
552
|
-
/**
|
|
553
|
-
* Positional layout of the *session* binary envelope — the leanest frame. Compared to the stateless
|
|
554
|
-
* adapter it replaces the 21-char `cuid` with a small per-connection integer and only carries
|
|
555
|
-
* `originClient` on the very first request of each direction (the peer remembers it afterwards).
|
|
556
|
-
*
|
|
557
|
-
* [ routeInt, typeInt, corrId, time, originClient?, payloadData ]
|
|
558
|
-
*/
|
|
559
|
-
const ENVELOPE$1 = {
|
|
560
|
-
route: 0,
|
|
561
|
-
type: 1,
|
|
562
|
-
corr: 2,
|
|
563
|
-
time: 3,
|
|
564
|
-
originClient: 4,
|
|
565
|
-
payload: 5
|
|
566
|
-
};
|
|
567
|
-
const ENVELOPE_LENGTH$1 = 6;
|
|
568
|
-
/**
|
|
569
|
-
* How long a pending correlation entry is kept before it's swept. A correlation only matters until its
|
|
570
|
-
* action resolves or times out, so anything older than the longest realistic action timeout can be
|
|
571
|
-
* dropped — this bounds memory when requests time out or a connection dies mid-flight (their replies
|
|
572
|
-
* would never arrive, leaving the entry orphaned). Generous default so live correlations are never
|
|
573
|
-
* pruned (the default transport timeout is 10s).
|
|
574
|
-
*/
|
|
575
|
-
const DEFAULT_CORRELATION_TTL_MS = 5 * 6e4;
|
|
576
|
-
function isKnownIdentity(coordinate) {
|
|
577
|
-
return coordinate != null && coordinate.envId !== "_unset_";
|
|
578
|
-
}
|
|
579
|
-
/**
|
|
580
|
-
* Drop entries older than `ttlMs`. Maps keep insertion order and entries are inserted in time order,
|
|
581
|
-
* so the oldest are first — stop sweeping at the first live entry.
|
|
582
|
-
*/
|
|
583
|
-
function pruneExpired(map, now, ttlMs) {
|
|
584
|
-
for (const [key, entry] of map) {
|
|
585
|
-
if (now - entry.time <= ttlMs) break;
|
|
586
|
-
map.delete(key);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* Builds a factory of *stateful, per-connection* codecs for {@link LinkTransport} /
|
|
591
|
-
* `AcceptorHandler` — the maximally compact binary wire. Call the returned factory once per live
|
|
592
|
-
* connection (each socket on the client, each accepted connection on the server) so every channel
|
|
593
|
-
* gets its own correlation + identity state.
|
|
594
|
-
*
|
|
595
|
-
* On top of everything {@link createBinaryWireAdapter} drops, a session also drops:
|
|
596
|
-
* - **`cuid`** — replaced by a per-connection integer correlation id. The initiator maps it to its
|
|
597
|
-
* real cuid; the responder echoes it; each side reconstructs the cuid from its own map. Correlation
|
|
598
|
-
* only needs to be unique per socket, so a counter suffices.
|
|
599
|
-
* - **`originClient` after the first request** — the first request each side sends carries its
|
|
600
|
-
* identity; the peer remembers it and injects it into later frames. Replies omit it entirely (a
|
|
601
|
-
* reply carries the initiator's own origin, which the initiator already knows).
|
|
602
|
-
*
|
|
603
|
-
* Both ends MUST build the factory from the same domains in the same order (positional dictionary).
|
|
604
|
-
* Text frames still return `undefined` from `incoming`, so JSON clients remain interoperable.
|
|
605
|
-
*
|
|
606
|
-
* Hibernation note: after a server connection is evicted its session resets, so a still-connected
|
|
607
|
-
* client (whose session persists) will keep omitting `originClient`. The server must therefore restore
|
|
608
|
-
* the connection→client binding from its own store (see `AcceptorHandler.rehydrateConnection`) and
|
|
609
|
-
* inject `originClient` from there — the session alone can't recover it.
|
|
610
|
-
*/
|
|
611
|
-
function createBinaryWireSessionFactory(domains, options) {
|
|
612
|
-
const { routeToInt, intToRoute } = buildActionRouteDictionary(domains);
|
|
613
|
-
const unknownIdentity = RuntimeCoordinate.unknown.toJsonObject();
|
|
614
|
-
const ttlMs = options?.correlationTtlMs ?? DEFAULT_CORRELATION_TTL_MS;
|
|
615
|
-
return () => {
|
|
616
|
-
let outCounter = 0;
|
|
617
|
-
const corrToCuid = /* @__PURE__ */ new Map();
|
|
618
|
-
const cuidToCorr = /* @__PURE__ */ new Map();
|
|
619
|
-
let selfIdentity;
|
|
620
|
-
let peerIdentity;
|
|
621
|
-
return {
|
|
622
|
-
outgoing: (input) => {
|
|
623
|
-
const json = input.action.toJsonObject();
|
|
624
|
-
const routeKey = `${json.domain}:${json.id}`;
|
|
625
|
-
const routeInt = routeToInt.get(routeKey);
|
|
626
|
-
if (routeInt == null) throw new Error(`[binary-wire] Cannot pack unregistered action route: ${routeKey}`);
|
|
627
|
-
const now = Date.now();
|
|
628
|
-
pruneExpired(corrToCuid, now, ttlMs);
|
|
629
|
-
pruneExpired(cuidToCorr, now, ttlMs);
|
|
630
|
-
let corr;
|
|
631
|
-
let wireIdentity;
|
|
632
|
-
if (json.type === "request") {
|
|
633
|
-
corr = outCounter++;
|
|
634
|
-
corrToCuid.set(corr, {
|
|
635
|
-
value: json.context.cuid,
|
|
636
|
-
time: now
|
|
637
|
-
});
|
|
638
|
-
if (selfIdentity == null && isKnownIdentity(json.context.originClient)) {
|
|
639
|
-
selfIdentity = json.context.originClient;
|
|
640
|
-
wireIdentity = json.context.originClient;
|
|
641
|
-
}
|
|
642
|
-
} else {
|
|
643
|
-
corr = cuidToCorr.get(json.context.cuid)?.value ?? -1;
|
|
644
|
-
if (json.type === "result") cuidToCorr.delete(json.context.cuid);
|
|
645
|
-
}
|
|
646
|
-
const envelope = new Array(ENVELOPE_LENGTH$1);
|
|
647
|
-
envelope[ENVELOPE$1.route] = routeInt;
|
|
648
|
-
envelope[ENVELOPE$1.type] = PayloadTypeToInt[json.type];
|
|
649
|
-
envelope[ENVELOPE$1.corr] = corr;
|
|
650
|
-
envelope[ENVELOPE$1.time] = json.time;
|
|
651
|
-
envelope[ENVELOPE$1.originClient] = wireIdentity;
|
|
652
|
-
envelope[ENVELOPE$1.payload] = extractWirePayload(json);
|
|
653
|
-
return pack(envelope);
|
|
654
|
-
},
|
|
655
|
-
incoming: (frame) => {
|
|
656
|
-
let buffer;
|
|
657
|
-
if (frame instanceof ArrayBuffer) buffer = new Uint8Array(frame);
|
|
658
|
-
else if (frame instanceof Uint8Array) buffer = frame;
|
|
659
|
-
else return;
|
|
660
|
-
try {
|
|
661
|
-
const envelope = unpack(buffer);
|
|
662
|
-
if (!Array.isArray(envelope) || envelope.length !== ENVELOPE_LENGTH$1) return void 0;
|
|
663
|
-
const routeMeta = intToRoute[envelope[ENVELOPE$1.route]];
|
|
664
|
-
const payloadType = ReversePayloadType[envelope[ENVELOPE$1.type]];
|
|
665
|
-
if (routeMeta == null || payloadType == null) return void 0;
|
|
666
|
-
const now = Date.now();
|
|
667
|
-
pruneExpired(corrToCuid, now, ttlMs);
|
|
668
|
-
pruneExpired(cuidToCorr, now, ttlMs);
|
|
669
|
-
const corr = envelope[ENVELOPE$1.corr];
|
|
670
|
-
const time = envelope[ENVELOPE$1.time];
|
|
671
|
-
const wireIdentity = envelope[ENVELOPE$1.originClient];
|
|
672
|
-
let cuid;
|
|
673
|
-
let originClient;
|
|
674
|
-
if (payloadType === "request") {
|
|
675
|
-
cuid = nanoid();
|
|
676
|
-
cuidToCorr.set(cuid, {
|
|
677
|
-
value: corr,
|
|
678
|
-
time: now
|
|
679
|
-
});
|
|
680
|
-
if (isKnownIdentity(wireIdentity)) peerIdentity = wireIdentity;
|
|
681
|
-
originClient = peerIdentity ?? unknownIdentity;
|
|
682
|
-
} else {
|
|
683
|
-
cuid = corrToCuid.get(corr)?.value ?? nanoid();
|
|
684
|
-
if (payloadType === "result") corrToCuid.delete(corr);
|
|
685
|
-
originClient = selfIdentity ?? unknownIdentity;
|
|
686
|
-
}
|
|
687
|
-
return assembleWireJson(routeMeta, payloadType, time, {
|
|
688
|
-
cuid,
|
|
689
|
-
timeCreated: time,
|
|
690
|
-
routing: [],
|
|
691
|
-
originClient
|
|
692
|
-
}, envelope[ENVELOPE$1.payload]);
|
|
693
|
-
} catch (e) {
|
|
694
|
-
console.error("[binary-wire] Failed to unpack binary action session frame", e);
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
//#endregion
|
|
702
|
-
//#region src/ActionRuntime/Channel/secureChannel.ts
|
|
703
|
-
/**
|
|
704
|
-
* Derive a stable wire-dictionary version from the ordered route list (FNV-1a over `domain:id,…`), so
|
|
705
|
-
* the version moves automatically whenever the transported domains change — a stale peer is then
|
|
706
|
-
* rejected by the handshake instead of silently misrouting a positionally-packed frame.
|
|
707
|
-
*/
|
|
708
|
-
function deriveDictionaryVersion(domains) {
|
|
709
|
-
const { intToRoute } = buildActionRouteDictionary(domains);
|
|
710
|
-
const signature = intToRoute.map((route) => `${route.domain}:${route.id}`).join(",");
|
|
711
|
-
let hash = 2166136261;
|
|
712
|
-
for (let i = 0; i < signature.length; i++) {
|
|
713
|
-
hash ^= signature.charCodeAt(i);
|
|
714
|
-
hash = Math.imul(hash, 16777619);
|
|
715
|
-
}
|
|
716
|
-
return `auto:${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Bundle a secure channel's shared identity from its transported domains. Both ends MUST call this
|
|
720
|
-
* with the same domains in the same order (the binary wire dictionary is positional). The
|
|
721
|
-
* `dictionaryVersion` is derived from those domains unless you pin an explicit one.
|
|
722
|
-
*
|
|
723
|
-
* Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`
|
|
724
|
-
* (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see
|
|
725
|
-
* {@link connectChannel} and `acceptChannelConnections`) instead of being restated at each end. The
|
|
726
|
-
* wire dictionary spans `[...toAcceptor, ...toConnector]` in that order; add new domains to the end of
|
|
727
|
-
* their list to keep older peers compatible. (`domains` is still accepted as a legacy alias for
|
|
728
|
-
* `toAcceptor`.)
|
|
729
|
-
*/
|
|
730
|
-
function defineSecureChannel(options) {
|
|
731
|
-
const base = defineChannel({
|
|
732
|
-
toAcceptor: options.toAcceptor,
|
|
733
|
-
toConnector: options.toConnector
|
|
734
|
-
});
|
|
735
|
-
const allDomains = [...base.toAcceptorDomains, ...base.toConnectorDomains];
|
|
736
|
-
return {
|
|
737
|
-
...base,
|
|
738
|
-
dictionaryVersion: options.dictionaryVersion ?? deriveDictionaryVersion(allDomains),
|
|
739
|
-
createCodec: createBinaryWireSessionFactory(allDomains, options.sessionOptions)
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
//#endregion
|
|
743
474
|
//#region src/ActionRuntime/Transport/Carrier/duplex/inMemory/createInMemoryChannel.ts
|
|
744
475
|
/**
|
|
745
476
|
* Two cross-wired in-process byte channels — a loopback carrier with no socket. The client end is a
|
|
@@ -797,9 +528,8 @@ function createInMemoryChannelPair() {
|
|
|
797
528
|
//#region src/ActionRuntime/Transport/Carrier/duplex/inMemory/inMemoryCarrier.ts
|
|
798
529
|
/**
|
|
799
530
|
* A loopback duplex carrier with no socket — two cross-wired in-process ends. The connector end is an
|
|
800
|
-
* {@link IDuplexCarrierSource} for
|
|
801
|
-
*
|
|
802
|
-
* non-WS carrier end to end.
|
|
531
|
+
* {@link IDuplexCarrierSource} for `connectChannel`; the acceptor end plugs into an `AcceptorHandler`.
|
|
532
|
+
* Ideal for tests and for running two runtimes in one process, or proving a non-WS carrier end to end.
|
|
803
533
|
*/
|
|
804
534
|
function inMemoryCarrier() {
|
|
805
535
|
const { clientChannel, serverEndpoint } = createInMemoryChannelPair();
|
|
@@ -885,8 +615,8 @@ async function normalizeFrame$1(data) {
|
|
|
885
615
|
//#region src/ActionRuntime/Transport/Carrier/duplex/rtc/rtcCarrier.ts
|
|
886
616
|
/**
|
|
887
617
|
* A WebRTC {@link IDuplexCarrierSource} over an already-negotiated `RTCDataChannel` (signaling is the
|
|
888
|
-
* app's concern).
|
|
889
|
-
* identical secure session as a WebSocket.
|
|
618
|
+
* app's concern). Pass it as a `carrier` to `connectChannel` so two browsers/apps linked peer-to-peer run
|
|
619
|
+
* the identical secure session as a WebSocket.
|
|
890
620
|
*/
|
|
891
621
|
function rtcCarrier(dataChannel, options = {}) {
|
|
892
622
|
return {
|
|
@@ -1004,8 +734,8 @@ async function normalizeFrame(data) {
|
|
|
1004
734
|
//#region src/ActionRuntime/Transport/Carrier/duplex/ws/wsCarrier.ts
|
|
1005
735
|
/**
|
|
1006
736
|
* A WebSocket {@link IDuplexCarrierSource}: opens an `arraybuffer` socket (cached per endpoint) and adapts
|
|
1007
|
-
* it to a carrier.
|
|
1008
|
-
*
|
|
737
|
+
* it to a carrier. Pass it as a `carrier` to `connectChannel` — the WebSocket is now "just another
|
|
738
|
+
* carrier" under the shared secure session, with no WS-specific transport class.
|
|
1009
739
|
*
|
|
1010
740
|
* `createRequest` derives the socket URL per action (keep it simple with `() => ({ url })`), so dynamic
|
|
1011
741
|
* endpoints (e.g. a per-run query param) need no `createWebSocket` escape hatch.
|
|
@@ -1041,9 +771,10 @@ function shortPath(url) {
|
|
|
1041
771
|
}
|
|
1042
772
|
/**
|
|
1043
773
|
* An HTTP {@link IExchangeCarrierSource}: each `exchange` POSTs one frame body to the action endpoint and
|
|
1044
|
-
* resolves with the response body as the single correlated reply.
|
|
1045
|
-
* HTTP then runs the *same* secure session as a duplex carrier
|
|
1046
|
-
* the request/reply correlation provided for free by the HTTP
|
|
774
|
+
* resolves with the response body as the single correlated reply. Pass it as a `carrier` to
|
|
775
|
+
* `connectChannel` — a secure HTTP transport then runs the *same* secure session as a duplex carrier
|
|
776
|
+
* (handshake → token → encrypted frames), the request/reply correlation provided for free by the HTTP
|
|
777
|
+
* transaction.
|
|
1047
778
|
*
|
|
1048
779
|
* `createRequest` derives the URL/headers per action (keep it simple with `() => ({ url })`). The body is
|
|
1049
780
|
* the session's responsibility, so it is never built here.
|
|
@@ -1083,89 +814,6 @@ function httpCarrier(createRequest, options = {}) {
|
|
|
1083
814
|
};
|
|
1084
815
|
}
|
|
1085
816
|
//#endregion
|
|
1086
|
-
|
|
1087
|
-
/**
|
|
1088
|
-
* Positional layout of the stateless binary envelope. A flat tuple (rather than an object) strips the
|
|
1089
|
-
* repeated `domain`/`id`/`form`/`type` and context key names from every frame, and we carry only the
|
|
1090
|
-
* context fields the receiver can't recompute: `cuid` (correlation) and `originClient` (return
|
|
1091
|
-
* routing).
|
|
1092
|
-
*
|
|
1093
|
-
* [ routeInt, typeInt, time, cuid, originClient, payloadData ]
|
|
1094
|
-
*
|
|
1095
|
-
* Dropped vs the JSON wire: `form`/`type` strings, `inputHash`/`outputHash` (recomputed on hydrate),
|
|
1096
|
-
* `context.timeCreated` (reconstructed from `time`) and `context.routing` (rebuilt empty — the
|
|
1097
|
-
* receiver re-stamps its own route items as it handles the action). For the leanest possible frames
|
|
1098
|
-
* (integer correlation, identity dropped after a handshake), use `createBinaryWireSessionFactory`.
|
|
1099
|
-
*/
|
|
1100
|
-
const ENVELOPE = {
|
|
1101
|
-
route: 0,
|
|
1102
|
-
type: 1,
|
|
1103
|
-
time: 2,
|
|
1104
|
-
cuid: 3,
|
|
1105
|
-
originClient: 4,
|
|
1106
|
-
payload: 5
|
|
1107
|
-
};
|
|
1108
|
-
const ENVELOPE_LENGTH = 6;
|
|
1109
|
-
/**
|
|
1110
|
-
* Builds a *stateless* `formatMessage` pipeline for {@link LinkTransport}, packing action
|
|
1111
|
-
* payloads into a compact msgpackr binary frame instead of JSON. The `domain`/`id` route collapses to
|
|
1112
|
-
* a single integer drawn from a shared dictionary; `form`/`type`, the recomputable
|
|
1113
|
-
* `inputHash`/`outputHash`, and the per-frame `context.routing`/`context.timeCreated` are all dropped
|
|
1114
|
-
* (see {@link ENVELOPE}).
|
|
1115
|
-
*
|
|
1116
|
-
* No validation runs here: `incoming` blindly reconstructs the wire JSON shape and hands it back to
|
|
1117
|
-
* the connection, which flows into `ActionRuntime` → `domain.hydrateAnyAction()` where the Valibot
|
|
1118
|
-
* schemas validate it exactly as they would for a JSON frame.
|
|
1119
|
-
*
|
|
1120
|
-
* Both ends of the socket MUST construct the adapter with the same domains in the same order — the
|
|
1121
|
-
* integer dictionary is positional. Mismatched dictionaries will route to the wrong action.
|
|
1122
|
-
*
|
|
1123
|
-
* Because `incoming` returns `undefined` for text frames, a binary server can still serve plain-JSON
|
|
1124
|
-
* clients on the same runtime (the connection falls back to its built-in JSON parser).
|
|
1125
|
-
*/
|
|
1126
|
-
function createBinaryWireAdapter(domains) {
|
|
1127
|
-
const { routeToInt, intToRoute } = buildActionRouteDictionary(domains);
|
|
1128
|
-
return {
|
|
1129
|
-
outgoing: (input) => {
|
|
1130
|
-
const json = input.action.toJsonObject();
|
|
1131
|
-
const routeKey = `${json.domain}:${json.id}`;
|
|
1132
|
-
const routeInt = routeToInt.get(routeKey);
|
|
1133
|
-
if (routeInt == null) throw new Error(`[binary-wire] Cannot pack unregistered action route: ${routeKey}`);
|
|
1134
|
-
const envelope = new Array(ENVELOPE_LENGTH);
|
|
1135
|
-
envelope[ENVELOPE.route] = routeInt;
|
|
1136
|
-
envelope[ENVELOPE.type] = PayloadTypeToInt[json.type];
|
|
1137
|
-
envelope[ENVELOPE.time] = json.time;
|
|
1138
|
-
envelope[ENVELOPE.cuid] = json.context.cuid;
|
|
1139
|
-
envelope[ENVELOPE.originClient] = json.context.originClient;
|
|
1140
|
-
envelope[ENVELOPE.payload] = extractWirePayload(json);
|
|
1141
|
-
return pack(envelope);
|
|
1142
|
-
},
|
|
1143
|
-
incoming: (frame) => {
|
|
1144
|
-
let buffer;
|
|
1145
|
-
if (frame instanceof ArrayBuffer) buffer = new Uint8Array(frame);
|
|
1146
|
-
else if (frame instanceof Uint8Array) buffer = frame;
|
|
1147
|
-
else return;
|
|
1148
|
-
try {
|
|
1149
|
-
const envelope = unpack(buffer);
|
|
1150
|
-
if (!Array.isArray(envelope) || envelope.length !== ENVELOPE_LENGTH) return void 0;
|
|
1151
|
-
const routeMeta = intToRoute[envelope[ENVELOPE.route]];
|
|
1152
|
-
const payloadType = ReversePayloadType[envelope[ENVELOPE.type]];
|
|
1153
|
-
if (routeMeta == null || payloadType == null) return void 0;
|
|
1154
|
-
const time = envelope[ENVELOPE.time];
|
|
1155
|
-
return assembleWireJson(routeMeta, payloadType, time, {
|
|
1156
|
-
cuid: envelope[ENVELOPE.cuid],
|
|
1157
|
-
timeCreated: time,
|
|
1158
|
-
routing: [],
|
|
1159
|
-
originClient: envelope[ENVELOPE.originClient]
|
|
1160
|
-
}, envelope[ENVELOPE.payload]);
|
|
1161
|
-
} catch (e) {
|
|
1162
|
-
console.error("[binary-wire] Failed to unpack binary action frame", e);
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
};
|
|
1167
|
-
}
|
|
1168
|
-
//#endregion
|
|
1169
|
-
export { AcceptorHandler, ActionCore, ActionDomain, ActionLocalHandler, ActionRootDomain, ActionRuntime, ActionSchema, ConnectionStateStore, ConnectorHandler, EActionPayloadType, EActionProgressType, EActionResponseMode, EErrId_NiceAction, EErrId_NiceTransport, EErrId_NiceTransport_WebSocket, EHandshakeMessageType, ERunningActionFinishedType, ERunningActionState, ERunningActionUpdateType, ESecurityLevel, ETransportShape, ETransportStatus, ExchangeAcceptor, ExchangeTransport, LinkTransport, PeerLinkHandler, RunningAction, RuntimeCoordinate, Transport, acceptChannel, acceptChannelConnections, actionSchema, connectChannel, createAcceptorHandler, createActionFetchHandler, createActionFrameCrypto, createActionRootDomain, createBinaryWireAdapter, createBinaryWireSessionFactory, createClientHandshake, createConnectionStateStore, createConnectorHandler, createHibernatableWsServerAdapter, createInMemoryChannelPair, createInMemoryTofuVerifyKeyResolver, createLocalHandler, createSecureAcceptorHandler, createServerHandshake, createStorageTofuVerifyKeyResolver, decodeActionFrame, decodeExchangeReply, decodeExchangeRequest, decodeHandshakeMessage, defineChannel, defineSecureChannel, encodeExchange, encodeHandshakeMessage, err_nice_action, err_nice_external_client, err_nice_transport, err_nice_transport_ws, httpAcceptorCarrier, httpCarrier, inMemoryCarrier, isActionPayload_Any_JsonObject, isActionPayload_Request_JsonObject, isActionPayload_Result_JsonObject, isExchangeAcceptorCarrier, rtcCarrier, rtcDataChannelByteChannel, runtimeLinkId, serveChannel, serveHost, wsAcceptorCarrier, wsCarrier };
|
|
817
|
+
export { ActionCore, ActionDomain, ActionLocalHandler, ActionRootDomain, ActionRuntime, ActionSchema, EActionPayloadType, EActionProgressType, EActionResponseMode, EErrId_NiceAction, EErrId_NiceTransport, EErrId_NiceTransport_WebSocket, ERunningActionFinishedType, ERunningActionState, ERunningActionUpdateType, ESecurityLevel, ExchangeAcceptor, RunningAction, RuntimeCoordinate, acceptChannel, acceptChannelConnections, actionSchema, connectChannel, createActionRootDomain, createInMemoryChannelPair, createInMemoryTofuVerifyKeyResolver, createLocalHandler, createStorageTofuVerifyKeyResolver, decodeActionFrame, decodeExchangeReply, decodeExchangeRequest, defineChannel, encodeExchange, err_nice_action, err_nice_external_client, err_nice_transport, err_nice_transport_ws, httpAcceptorCarrier, httpCarrier, inMemoryCarrier, isActionPayload_Any_JsonObject, isActionPayload_Request_JsonObject, isActionPayload_Result_JsonObject, isExchangeAcceptorCarrier, rtcCarrier, rtcDataChannelByteChannel, runtimeLinkId, serveChannel, serveHost, wsAcceptorCarrier, wsCarrier };
|
|
1170
818
|
|
|
1171
819
|
//# sourceMappingURL=index.mjs.map
|