@nice-code/action 0.22.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 +22 -25
- package/build/{ActionPayload.types-Dx1JPyfs.d.mts → AcceptorHandler-11-QMdx2.d.mts} +977 -1351
- package/build/{ActionPayload.types-L9k0LyBd.d.cts → AcceptorHandler-CxD0c1BE.d.cts} +977 -1351
- package/build/{ActionDevtoolsCore-CQ0vrvPD.d.cts → ActionDevtoolsCore-37JP4bOG.d.cts} +2 -2
- package/build/{ActionDevtoolsCore-CiLBYC3K.d.mts → 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-OnJxzsAD.cjs → createHibernatableWsServerAdapter-BNi4k9j3.cjs} +258 -470
- package/build/createHibernatableWsServerAdapter-BNi4k9j3.cjs.map +1 -0
- package/build/{httpAcceptorCarrier-DL8lf0xB.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 +84 -458
- 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 +28 -374
- 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-DL8lf0xB.mjs.map +0 -1
- package/build/httpAcceptorCarrier-OnJxzsAD.cjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, s as TDevtoolsPosition, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-
|
|
1
|
+
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, s as TDevtoolsPosition, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-37JP4bOG.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/devtools/browser/NiceActionDevtools.d.ts
|
|
4
4
|
interface INiceActionDevtoolsProps {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, s as TDevtoolsPosition, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-
|
|
1
|
+
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, s as TDevtoolsPosition, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-Cgq-go1R.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/devtools/browser/NiceActionDevtools.d.ts
|
|
4
4
|
interface INiceActionDevtoolsProps {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-
|
|
1
|
+
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-37JP4bOG.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/devtools/server/NiceActionServerDevtools.d.ts
|
|
4
4
|
type TServerDevtoolsLogFn = (message: string, data?: Record<string, unknown>) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-
|
|
1
|
+
import { a as TDevtoolsActionStatus, i as IDevtoolsObservableDomain, n as IActionDevtoolsCoreOptions, o as TDevtoolsListener, r as IDevtoolsActionEntry, t as ActionDevtoolsCore } from "../../ActionDevtoolsCore-Cgq-go1R.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/devtools/server/NiceActionServerDevtools.d.ts
|
|
4
4
|
type TServerDevtoolsLogFn = (message: string, data?: Record<string, unknown>) => void;
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
const require_createHibernatableWsServerAdapter = require("./createHibernatableWsServerAdapter-BNi4k9j3.cjs");
|
|
2
|
+
let _nice_code_util = require("@nice-code/util");
|
|
3
|
+
//#region src/ActionRuntime/Transport/Carrier/Carrier.types.ts
|
|
4
|
+
/**
|
|
5
|
+
* Narrow a carrier source to the exchange shape via its `shape` discriminant — the one branch the
|
|
6
|
+
* internal `transport()` factory uses to pick the duplex vs exchange transport. A duplex source carries
|
|
7
|
+
* no `shape`, so the `else` branch is the duplex one.
|
|
8
|
+
*/
|
|
9
|
+
function isExchangeCarrierSource(carrier) {
|
|
10
|
+
return "shape" in carrier && carrier.shape === "exchange";
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/ActionRuntime/Transport/createTransport.ts
|
|
14
|
+
function transport(options) {
|
|
15
|
+
const { carrier, channel, available, label } = options;
|
|
16
|
+
const labelFor = label ?? carrier.carrierLabel;
|
|
17
|
+
let security;
|
|
18
|
+
if (options.secure) {
|
|
19
|
+
const link = options.link ?? (options.storage != null ? new _nice_code_util.ClientCryptoKeyLink({ storageAdapter: options.storage }) : void 0);
|
|
20
|
+
if (link == null) throw new Error("transport: a secure transport requires `link` or `storage` for the crypto identity.");
|
|
21
|
+
security = {
|
|
22
|
+
securityLevel: options.securityLevel ?? "authenticated",
|
|
23
|
+
link,
|
|
24
|
+
localCoordinate: options.runtime.coordinate.toJsonObject(),
|
|
25
|
+
dictionaryVersion: channel.dictionaryVersion
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (isExchangeCarrierSource(carrier)) return require_createHibernatableWsServerAdapter.ExchangeTransport.create({
|
|
29
|
+
openCarrier: carrier.open,
|
|
30
|
+
getTransportCacheKey: carrier.getCacheKey,
|
|
31
|
+
available,
|
|
32
|
+
getRouteInfo: carrier.getRouteInfo,
|
|
33
|
+
label: labelFor,
|
|
34
|
+
security
|
|
35
|
+
});
|
|
36
|
+
return require_createHibernatableWsServerAdapter.LinkTransport.create({
|
|
37
|
+
openChannel: carrier.open,
|
|
38
|
+
createFormatMessage: channel.createCodec,
|
|
39
|
+
getTransportCacheKey: carrier.getCacheKey,
|
|
40
|
+
available,
|
|
41
|
+
getRouteInfo: carrier.getRouteInfo,
|
|
42
|
+
label: labelFor,
|
|
43
|
+
security
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/ActionRuntime/Channel/ActionChannel.ts
|
|
48
|
+
/**
|
|
49
|
+
* Derive a stable wire-dictionary version from the ordered route list (FNV-1a over `domain:id,…`), so
|
|
50
|
+
* the version moves automatically whenever the transported domains change — a stale peer is then
|
|
51
|
+
* rejected by the handshake instead of silently misrouting a positionally-packed frame.
|
|
52
|
+
*/
|
|
53
|
+
function deriveDictionaryVersion(domains) {
|
|
54
|
+
const { intToRoute } = require_createHibernatableWsServerAdapter.buildActionRouteDictionary(domains);
|
|
55
|
+
const signature = intToRoute.map((route) => `${route.domain}:${route.id}`).join(",");
|
|
56
|
+
let hash = 2166136261;
|
|
57
|
+
for (let i = 0; i < signature.length; i++) {
|
|
58
|
+
hash ^= signature.charCodeAt(i);
|
|
59
|
+
hash = Math.imul(hash, 16777619);
|
|
60
|
+
}
|
|
61
|
+
return `auto:${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Declare a transport-agnostic channel by role — the single source of truth both peers share. Each end
|
|
65
|
+
* MUST call this with the same domains in the same order (the binary wire dictionary is positional); the
|
|
66
|
+
* `dictionaryVersion` is derived from those domains unless you pin an explicit one. The wire dictionary
|
|
67
|
+
* spans `[...toAcceptor, ...toConnector]` in that order, so add new domains to the end of their list to
|
|
68
|
+
* keep older peers compatible.
|
|
69
|
+
*
|
|
70
|
+
* Declare the domains *by role* — `toAcceptor` (connector→acceptor requests) and `toConnector`
|
|
71
|
+
* (acceptor→connector pushes) — so the routing for both ends is derived from the channel (see
|
|
72
|
+
* {@link connectChannel} and {@link serveChannel}) instead of being restated at each end. Security is a
|
|
73
|
+
* per-transport concern, not a channel one, so this same definition is used whether a transport runs
|
|
74
|
+
* plain or encrypted.
|
|
75
|
+
*/
|
|
76
|
+
function defineChannel(options) {
|
|
77
|
+
const allDomains = [...options.toAcceptor, ...options.toConnector];
|
|
78
|
+
return {
|
|
79
|
+
toAcceptorDomains: options.toAcceptor,
|
|
80
|
+
toConnectorDomains: options.toConnector,
|
|
81
|
+
dictionaryVersion: options.dictionaryVersion ?? deriveDictionaryVersion(allDomains),
|
|
82
|
+
createCodec: require_createHibernatableWsServerAdapter.createBinaryWireSessionFactory(allDomains, options.sessionOptions)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Open a connection to a peer from a single call — the dial-out dual of `serveChannel`. The channel is
|
|
87
|
+
* the single source of truth for *what* is routed (`toAcceptor` domains forwarded to the peer,
|
|
88
|
+
* `toConnector` pushes handled locally from `onPush`); the call binds the shared facts — the channel's
|
|
89
|
+
* codec/dictionary version, the runtime, and one crypto identity (a {@link ClientCryptoKeyLink} over
|
|
90
|
+
* `storage`) — into every transport in `transports`, so none of them restate the channel or runtime.
|
|
91
|
+
* List several transports to make the path transport-agnostic (secure WS preferred, HTTP fallback):
|
|
92
|
+
* ```ts
|
|
93
|
+
* const handler = connectChannel(runtime, lobbyChannel, {
|
|
94
|
+
* peer: runtime_coordinate_lobby_do,
|
|
95
|
+
* storage,
|
|
96
|
+
* transports: [{ carrier: wsCarrier(() => ({ url })) }, { carrier: httpCarrier(...), secure: false }],
|
|
97
|
+
* onPush: { player_joined: (p) => { … } },
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
* Returns the {@link ConnectorHandler} so the caller can later `clearTransportCache()` it.
|
|
101
|
+
*/
|
|
102
|
+
function connectChannel(runtime, channel, options) {
|
|
103
|
+
const securityLevel = options.securityLevel ?? "authenticated";
|
|
104
|
+
const anySecure = options.transports.some((transport) => transport.secure ?? true);
|
|
105
|
+
let link = options.link;
|
|
106
|
+
if (anySecure && link == null) {
|
|
107
|
+
if (options.storage == null) throw new Error("connectChannel: a secure transport requires `storage` (or `link`). Pass it, or set `secure: false` on the transport for a plain connection.");
|
|
108
|
+
link = new _nice_code_util.ClientCryptoKeyLink({ storageAdapter: options.storage });
|
|
109
|
+
}
|
|
110
|
+
const transports = options.transports.map((descriptor) => transport({
|
|
111
|
+
carrier: descriptor.carrier,
|
|
112
|
+
channel,
|
|
113
|
+
runtime,
|
|
114
|
+
secure: descriptor.secure ?? true,
|
|
115
|
+
link,
|
|
116
|
+
securityLevel: descriptor.securityLevel ?? securityLevel,
|
|
117
|
+
available: descriptor.available,
|
|
118
|
+
label: descriptor.label
|
|
119
|
+
}));
|
|
120
|
+
const pushHandlers = options.onPush != null ? channel.toConnectorDomains.map((domain) => domain.wrapAsPartialLocalHandler(options.onPush)) : [];
|
|
121
|
+
return runtime.connectTo(options.peer, {
|
|
122
|
+
transports,
|
|
123
|
+
domains: [...channel.toAcceptorDomains],
|
|
124
|
+
localHandlers: pushHandlers,
|
|
125
|
+
defaultTimeout: options.defaultTimeout
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Register an acceptor handler's execution for a channel straight from its definition: the channel's
|
|
130
|
+
* `toAcceptor` domains are served together with one merged, connection-aware case map (each case gets
|
|
131
|
+
* the primed request + the originating connection, as with
|
|
132
|
+
* {@link AcceptorHandler.forConnectionDomainCases}). The domain list is taken from the channel,
|
|
133
|
+
* never restated. Add the returned handler to the runtime alongside the acceptor handler:
|
|
134
|
+
* ```ts
|
|
135
|
+
* runtime.addHandlers([acceptChannelConnections(serverHandler, channel, { … }), serverHandler]);
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* The case's second argument is the raw connection (`TConn | undefined`). For the richer state +
|
|
139
|
+
* broadcast + pushBack context, serve the channel through `serveChannel`'s `channelCases` instead.
|
|
140
|
+
*/
|
|
141
|
+
function acceptChannelConnections(serverHandler, channel, cases) {
|
|
142
|
+
return serverHandler.forConnectionDomainCasesMulti(channel.toAcceptorDomains, cases, (connection) => connection);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build the secure {@link AcceptorHandler} for a channel — the accept-in counterpart to
|
|
146
|
+
* {@link connectChannel}. It folds in the boilerplate of {@link createSecureAcceptorHandler} (the
|
|
147
|
+
* `ClientCryptoKeyLink` + storage-backed TOFU resolver from one `storage`, the channel's codec +
|
|
148
|
+
* dictionary version, the `security` block from the runtime coordinate) but takes the `(runtime, channel,
|
|
149
|
+
* options)` shape of the channel family. Pair it with {@link acceptChannelConnections} for execution:
|
|
150
|
+
* ```ts
|
|
151
|
+
* const acceptor = acceptChannel(runtime, gameChannel, { clientEnv, storage, send });
|
|
152
|
+
* runtime.addHandlers([acceptChannelConnections(acceptor, gameChannel, { … }), acceptor]);
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
function acceptChannel(runtime, channel, options) {
|
|
156
|
+
return require_createHibernatableWsServerAdapter.createSecureAcceptorHandler({
|
|
157
|
+
...options,
|
|
158
|
+
channel,
|
|
159
|
+
runtime
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/ActionRuntime/Transport/Carrier/AcceptorCarrier.types.ts
|
|
164
|
+
/**
|
|
165
|
+
* Build the inert lifecycle slot a duplex carrier factory spreads into its handle: `receive`/`drop` throw
|
|
166
|
+
* (or no-op) until `serveChannel` calls `_activate` with the carrier's live router. Shared by every duplex
|
|
167
|
+
* carrier factory (`wsAcceptorCarrier`, a WebRTC carrier, the Cloudflare DO helper, …) so the
|
|
168
|
+
* stateful-handle wiring lives in exactly one place.
|
|
169
|
+
*/
|
|
170
|
+
function createDuplexCarrierLifecycle() {
|
|
171
|
+
let router;
|
|
172
|
+
return {
|
|
173
|
+
receive(connection, frame) {
|
|
174
|
+
if (router == null) throw new Error("acceptor carrier not served yet — pass it to serveChannel() before feeding frames");
|
|
175
|
+
router.receive(connection, frame);
|
|
176
|
+
},
|
|
177
|
+
drop(connection) {
|
|
178
|
+
router?.drop(connection);
|
|
179
|
+
},
|
|
180
|
+
_activate(liveRouter) {
|
|
181
|
+
router = liveRouter;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Narrow an acceptor carrier to the exchange shape via its `shape` discriminant — the one branch
|
|
187
|
+
* `serveChannel` uses to pick the duplex (push-capable) vs exchange (request/reply) wiring. A duplex
|
|
188
|
+
* carrier carries `shape: ETransportShape.duplex`, so the `else` branch is the duplex one.
|
|
189
|
+
*/
|
|
190
|
+
function isExchangeAcceptorCarrier(carrier) {
|
|
191
|
+
return carrier.shape === "exchange";
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/ActionRuntime/Channel/serveChannel.ts
|
|
195
|
+
/** Default accepted set, shared by every carrier: negotiate per connection to whatever the client picks. */
|
|
196
|
+
const DEFAULT_SERVER_SECURITY_LEVELS = [
|
|
197
|
+
"none",
|
|
198
|
+
"authenticated",
|
|
199
|
+
"encrypted"
|
|
200
|
+
];
|
|
201
|
+
function serveChannel(runtime, channel, options) {
|
|
202
|
+
const duplexCarriers = options.carriers.filter((carrier) => !isExchangeAcceptorCarrier(carrier));
|
|
203
|
+
const exchangeCarriers = options.carriers.filter(isExchangeAcceptorCarrier);
|
|
204
|
+
if (exchangeCarriers.length > 1) throw new Error("serveChannel: at most one exchange carrier is supported");
|
|
205
|
+
const exchangeCarrier = exchangeCarriers[0];
|
|
206
|
+
const singleDuplex = duplexCarriers.length === 1;
|
|
207
|
+
if (options.connectionState != null && !singleDuplex) throw new Error("serveChannel: `connectionState` requires exactly one duplex carrier");
|
|
208
|
+
if (options.channelCases != null && !singleDuplex) throw new Error("serveChannel: `channelCases` requires exactly one duplex carrier");
|
|
209
|
+
const exchangeSecure = exchangeCarrier != null && (exchangeCarrier.secure ?? true);
|
|
210
|
+
const anyDuplexSecure = duplexCarriers.some((carrier) => carrier.secure ?? true);
|
|
211
|
+
const securityLevel = options.securityLevel ?? DEFAULT_SERVER_SECURITY_LEVELS;
|
|
212
|
+
let secure;
|
|
213
|
+
if (anyDuplexSecure || exchangeSecure) {
|
|
214
|
+
const storage = options.storage;
|
|
215
|
+
if (storage == null) throw new Error("serveChannel: a secure carrier requires `storage`. Pass it, or set `secure: false` on the carrier for a plain endpoint.");
|
|
216
|
+
secure = {
|
|
217
|
+
storage,
|
|
218
|
+
link: options.link ?? new _nice_code_util.ClientCryptoKeyLink({ storageAdapter: storage }),
|
|
219
|
+
verifyKeyResolver: options.verifyKeyResolver ?? require_createHibernatableWsServerAdapter.createStorageTofuVerifyKeyResolver(storage)
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const plainRouter = (handler) => ({
|
|
223
|
+
receive: (connection, frame) => handler.receive(connection, frame),
|
|
224
|
+
drop: (connection) => handler.dropConnection(connection)
|
|
225
|
+
});
|
|
226
|
+
const asObject = (value) => typeof value === "object" && value != null ? value : {};
|
|
227
|
+
const handlers = [];
|
|
228
|
+
let connections;
|
|
229
|
+
for (const carrier of duplexCarriers) {
|
|
230
|
+
const handler = (carrier.secure ?? true) && secure != null ? acceptChannel(runtime, channel, {
|
|
231
|
+
clientEnv: options.clientEnv,
|
|
232
|
+
storage: secure.storage,
|
|
233
|
+
link: secure.link,
|
|
234
|
+
verifyKeyResolver: secure.verifyKeyResolver,
|
|
235
|
+
securityLevel,
|
|
236
|
+
send: carrier.send,
|
|
237
|
+
defaultTimeout: options.defaultTimeout
|
|
238
|
+
}) : require_createHibernatableWsServerAdapter.createAcceptorHandler({
|
|
239
|
+
clientEnv: options.clientEnv,
|
|
240
|
+
createFormatMessage: channel.createCodec,
|
|
241
|
+
send: carrier.send,
|
|
242
|
+
runtime,
|
|
243
|
+
defaultTimeout: options.defaultTimeout
|
|
244
|
+
});
|
|
245
|
+
const attach = carrier.attachmentStore;
|
|
246
|
+
let router;
|
|
247
|
+
if (attach == null) router = plainRouter(handler);
|
|
248
|
+
else if (options.connectionState != null) {
|
|
249
|
+
connections = require_createHibernatableWsServerAdapter.createConnectionStateStore(handler, {
|
|
250
|
+
schema: options.connectionState.schema,
|
|
251
|
+
getConnections: attach.getConnections,
|
|
252
|
+
read: attach.read,
|
|
253
|
+
write: attach.write
|
|
254
|
+
});
|
|
255
|
+
router = plainRouter(handler);
|
|
256
|
+
} else router = require_createHibernatableWsServerAdapter.createHibernatableWsServerAdapter({
|
|
257
|
+
handler,
|
|
258
|
+
getConnections: attach.getConnections,
|
|
259
|
+
getAttachment: (connection) => attach.read(connection)?.binding,
|
|
260
|
+
setAttachment: (connection, binding) => attach.write(connection, {
|
|
261
|
+
...asObject(attach.read(connection)),
|
|
262
|
+
binding
|
|
263
|
+
})
|
|
264
|
+
});
|
|
265
|
+
carrier._activate(router);
|
|
266
|
+
handlers.push(handler);
|
|
267
|
+
}
|
|
268
|
+
runtime.addHandlers([...options.handlers ?? [], ...handlers]);
|
|
269
|
+
const soleDuplex = singleDuplex ? duplexCarriers[0] : void 0;
|
|
270
|
+
const receive = (connection, frame) => {
|
|
271
|
+
if (soleDuplex == null) throw new Error(duplexCarriers.length === 0 ? "serveChannel: no duplex carrier to receive on (this server has no socket transport)" : "serveChannel: several duplex carriers — feed each carrier handle's receive() directly");
|
|
272
|
+
soleDuplex.receive(connection, frame);
|
|
273
|
+
};
|
|
274
|
+
const drop = (connection) => {
|
|
275
|
+
soleDuplex?.drop(connection);
|
|
276
|
+
};
|
|
277
|
+
const pushToClient = (target, request, pushOptions) => {
|
|
278
|
+
const owner = target instanceof require_createHibernatableWsServerAdapter.RuntimeCoordinate ? handlers.find((handler) => handler.ownsLiveConnectionFor(target)) : handlers.find((handler) => handler.hasConnection(target));
|
|
279
|
+
if (owner == null) throw new Error("serveChannel: no duplex carrier holds a connection for the push target");
|
|
280
|
+
return owner.pushToClient(runtime, target, request, pushOptions);
|
|
281
|
+
};
|
|
282
|
+
const broadcast = (makeRequest, broadcastOptions) => {
|
|
283
|
+
if (!singleDuplex) throw new Error("serveChannel: broadcast requires exactly one duplex carrier — broadcast over a specific handlers[i] instead");
|
|
284
|
+
handlers[0].broadcast(makeRequest, {
|
|
285
|
+
runtime,
|
|
286
|
+
...broadcastOptions
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
const makeConnectionContext = (connection, request) => ({
|
|
290
|
+
connection: connection ?? null,
|
|
291
|
+
origin: request.context.originClient,
|
|
292
|
+
get state() {
|
|
293
|
+
return connection != null && connections != null ? connections.get(connection) : null;
|
|
294
|
+
},
|
|
295
|
+
setState(value) {
|
|
296
|
+
if (connection != null && connections != null) connections.set(connection, value);
|
|
297
|
+
},
|
|
298
|
+
clearState() {
|
|
299
|
+
if (connection != null && connections != null) connections.clearApp(connection);
|
|
300
|
+
},
|
|
301
|
+
broadcast(makeRequest, contextOptions) {
|
|
302
|
+
broadcast(makeRequest, {
|
|
303
|
+
except: contextOptions?.exceptSelf ? connection ?? null : null,
|
|
304
|
+
where: contextOptions?.where,
|
|
305
|
+
timeout: contextOptions?.timeout,
|
|
306
|
+
onError: contextOptions?.onError
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
pushBack(pushRequest, pushOptions) {
|
|
310
|
+
if (connection == null) throw new Error("serveChannel: connection context has no live socket to push back to (HTTP-exchange path)");
|
|
311
|
+
return pushToClient(connection, pushRequest, pushOptions);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
if (options.channelCases != null) runtime.addHandlers([handlers[0].forConnectionDomainCasesMulti(channel.toAcceptorDomains, options.channelCases, makeConnectionContext)]);
|
|
315
|
+
const exchangeSecurity = exchangeSecure && secure != null ? {
|
|
316
|
+
link: secure.link,
|
|
317
|
+
verifyKeyResolver: secure.verifyKeyResolver,
|
|
318
|
+
localCoordinate: runtime.coordinate.toJsonObject(),
|
|
319
|
+
dictionaryVersion: channel.dictionaryVersion,
|
|
320
|
+
securityLevel
|
|
321
|
+
} : void 0;
|
|
322
|
+
const defaultIsUpgrade = (request) => request.headers.get("Upgrade") === "websocket";
|
|
323
|
+
const upgraders = [];
|
|
324
|
+
for (const carrier of duplexCarriers) {
|
|
325
|
+
if (carrier.upgrade == null) continue;
|
|
326
|
+
upgraders.push({
|
|
327
|
+
isUpgrade: carrier.isUpgrade ?? defaultIsUpgrade,
|
|
328
|
+
upgrade: carrier.upgrade
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
handlers,
|
|
333
|
+
fetch: require_createHibernatableWsServerAdapter.createActionFetchHandler(runtime, {
|
|
334
|
+
cors: exchangeCarrier?.cors,
|
|
335
|
+
onWebSocketUpgrade: upgraders.length === 0 ? void 0 : (request, url) => (upgraders.find((u) => u.isUpgrade(request, url)) ?? upgraders[0]).upgrade(request, url),
|
|
336
|
+
isWebSocketUpgrade: upgraders.length === 0 ? void 0 : (request, url) => upgraders.some((u) => u.isUpgrade(request, url)),
|
|
337
|
+
isActionPath: exchangeCarrier != null ? exchangeCarrier.isActionPath ?? (() => true) : () => false,
|
|
338
|
+
security: exchangeSecurity,
|
|
339
|
+
useErrorStatus: exchangeCarrier?.useErrorStatus
|
|
340
|
+
}),
|
|
341
|
+
receive,
|
|
342
|
+
drop,
|
|
343
|
+
pushToClient,
|
|
344
|
+
broadcast,
|
|
345
|
+
connections
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/ActionRuntime/Channel/serveHost.ts
|
|
350
|
+
function serveHost(runtime, channel, host, options) {
|
|
351
|
+
const server = serveChannel(runtime, channel, {
|
|
352
|
+
...options,
|
|
353
|
+
carriers: host.carriers,
|
|
354
|
+
storage: host.storage
|
|
355
|
+
});
|
|
356
|
+
host.onServed?.(server);
|
|
357
|
+
return server;
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/ActionRuntime/Transport/Carrier/duplex/ws/wsAcceptorCarrier.ts
|
|
361
|
+
/**
|
|
362
|
+
* A WebSocket {@link IDuplexAcceptorCarrier}: the accept-in dual of {@link wsCarrier}. It describes how to
|
|
363
|
+
* write frames back to a live socket, how to upgrade an inbound request into one, and (optionally) how to
|
|
364
|
+
* persist bindings across hibernation. Hand it to `serveChannel`'s `carriers` list — the secure session,
|
|
365
|
+
* codec, and crypto identity are supplied centrally there, so this only carries the WS-specific surface.
|
|
366
|
+
*/
|
|
367
|
+
function wsAcceptorCarrier(options) {
|
|
368
|
+
return {
|
|
369
|
+
...createDuplexCarrierLifecycle(),
|
|
370
|
+
shape: "duplex",
|
|
371
|
+
carrierLabel: options.carrierLabel ?? "ws",
|
|
372
|
+
secure: options.secure,
|
|
373
|
+
send: options.send,
|
|
374
|
+
upgrade: options.upgrade,
|
|
375
|
+
isUpgrade: options.isUpgrade ?? ((request) => request.headers.get("Upgrade") === "websocket"),
|
|
376
|
+
attachmentStore: options.attachmentStore
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region src/ActionRuntime/Transport/Carrier/exchange/http/httpAcceptorCarrier.ts
|
|
381
|
+
/**
|
|
382
|
+
* An HTTP {@link IExchangeAcceptorCarrier}: the accept-in dual of {@link httpCarrier}. It serves the
|
|
383
|
+
* secure exchange protocol (handshake → token session → encrypted frames) over web-standard
|
|
384
|
+
* `Request`/`Response`. The crypto identity, runtime coordinate, dictionary version, and accepted security
|
|
385
|
+
* levels are all supplied centrally by `serveChannel`, so this only needs to say which requests carry an
|
|
386
|
+
* action envelope and how to answer CORS.
|
|
387
|
+
*/
|
|
388
|
+
function httpAcceptorCarrier(options = {}) {
|
|
389
|
+
return {
|
|
390
|
+
shape: "exchange",
|
|
391
|
+
carrierLabel: options.carrierLabel ?? "http",
|
|
392
|
+
secure: options.secure,
|
|
393
|
+
isActionPath: options.isActionPath,
|
|
394
|
+
cors: options.cors,
|
|
395
|
+
useErrorStatus: options.useErrorStatus
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
//#endregion
|
|
399
|
+
Object.defineProperty(exports, "acceptChannel", {
|
|
400
|
+
enumerable: true,
|
|
401
|
+
get: function() {
|
|
402
|
+
return acceptChannel;
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
Object.defineProperty(exports, "acceptChannelConnections", {
|
|
406
|
+
enumerable: true,
|
|
407
|
+
get: function() {
|
|
408
|
+
return acceptChannelConnections;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
Object.defineProperty(exports, "connectChannel", {
|
|
412
|
+
enumerable: true,
|
|
413
|
+
get: function() {
|
|
414
|
+
return connectChannel;
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
Object.defineProperty(exports, "defineChannel", {
|
|
418
|
+
enumerable: true,
|
|
419
|
+
get: function() {
|
|
420
|
+
return defineChannel;
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
Object.defineProperty(exports, "httpAcceptorCarrier", {
|
|
424
|
+
enumerable: true,
|
|
425
|
+
get: function() {
|
|
426
|
+
return httpAcceptorCarrier;
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
Object.defineProperty(exports, "isExchangeAcceptorCarrier", {
|
|
430
|
+
enumerable: true,
|
|
431
|
+
get: function() {
|
|
432
|
+
return isExchangeAcceptorCarrier;
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
Object.defineProperty(exports, "serveChannel", {
|
|
436
|
+
enumerable: true,
|
|
437
|
+
get: function() {
|
|
438
|
+
return serveChannel;
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
Object.defineProperty(exports, "serveHost", {
|
|
442
|
+
enumerable: true,
|
|
443
|
+
get: function() {
|
|
444
|
+
return serveHost;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
Object.defineProperty(exports, "wsAcceptorCarrier", {
|
|
448
|
+
enumerable: true,
|
|
449
|
+
get: function() {
|
|
450
|
+
return wsAcceptorCarrier;
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
//# sourceMappingURL=httpAcceptorCarrier-C3S_bDkL.cjs.map
|