@api.global/typedsocket 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/classes.clienttagreconciler.d.ts +51 -0
  3. package/dist_ts/classes.clienttagreconciler.js +290 -0
  4. package/dist_ts/classes.nativebyteerror.js +26 -0
  5. package/dist_ts/{nativebytes.manager.d.ts → classes.nativebytemanager.d.ts} +8 -3
  6. package/dist_ts/classes.nativebytemanager.js +2343 -0
  7. package/dist_ts/{typedsocket.classes.typedsocket.d.ts → classes.typedsocket.d.ts} +21 -21
  8. package/dist_ts/classes.typedsocket.js +1733 -0
  9. package/dist_ts/{typedsocket.tags.d.ts → classes.typedsockettagpolicymanager.d.ts} +9 -2
  10. package/dist_ts/classes.typedsockettagpolicymanager.js +549 -0
  11. package/dist_ts/{nativebytes.constants.js → constants.nativebytes.js} +1 -1
  12. package/dist_ts/{nativebytes.codec.d.ts → helpers.nativebytecodec.d.ts} +1 -1
  13. package/dist_ts/helpers.nativebytecodec.js +328 -0
  14. package/dist_ts/helpers.websocket.d.ts +8 -0
  15. package/dist_ts/helpers.websocket.js +13 -0
  16. package/dist_ts/index.d.ts +9 -8
  17. package/dist_ts/index.js +6 -6
  18. package/dist_ts/interfaces.diagnostics.d.ts +73 -0
  19. package/dist_ts/interfaces.diagnostics.js +2 -0
  20. package/dist_ts/{nativebytes.types.d.ts → interfaces.nativebytes.d.ts} +2 -2
  21. package/dist_ts/interfaces.nativebytes.js +2 -0
  22. package/dist_ts/plugins.js +14 -0
  23. package/package.json +1 -1
  24. package/readme.hints.md +26 -1
  25. package/readme.md +120 -55
  26. package/dist_ts/nativebytes.codec.js +0 -328
  27. package/dist_ts/nativebytes.errors.js +0 -26
  28. package/dist_ts/nativebytes.manager.js +0 -2308
  29. package/dist_ts/nativebytes.types.js +0 -2
  30. package/dist_ts/typedsocket.classes.typedsocket.js +0 -1874
  31. package/dist_ts/typedsocket.plugins.js +0 -14
  32. package/dist_ts/typedsocket.tags.js +0 -521
  33. /package/dist_ts/{nativebytes.errors.d.ts → classes.nativebyteerror.d.ts} +0 -0
  34. /package/dist_ts/{nativebytes.constants.d.ts → constants.nativebytes.d.ts} +0 -0
  35. /package/dist_ts/{typedsocket.plugins.d.ts → plugins.d.ts} +0 -0
@@ -0,0 +1,1733 @@
1
+ import * as plugins from './plugins.js';
2
+ import { NATIVE_BYTE_PROTOCOL, NATIVE_BYTE_PROTOCOL_MAJOR } from './constants.nativebytes.js';
3
+ import { NativeByteCapabilityError } from './classes.nativebyteerror.js';
4
+ import { NativeByteManager } from './classes.nativebytemanager.js';
5
+ import { assertBoundedTextIdentifier, TYPEDSOCKET_MAX_TAG_NAME_BYTES, TypedSocketClientTagDeniedError, TypedSocketTagPolicyManager, } from './classes.typedsockettagpolicymanager.js';
6
+ import { ClientTagReconciler } from './classes.clienttagreconciler.js';
7
+ import { toClientWebSocketCloseCode } from './helpers.websocket.js';
8
+ export { toClientWebSocketCloseCode } from './helpers.websocket.js';
9
+ export { TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS, TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS_PER_NAME, } from './classes.clienttagreconciler.js';
10
+ const TAG_PREFIX = '__typedsocket_tag__';
11
+ const textEncoder = new TextEncoder();
12
+ export const TYPEDSOCKET_MAX_TEXT_FRAME_BYTES = 1024 * 1024;
13
+ export const TYPEDSOCKET_MAX_QUEUED_TEXT_FRAMES = 64;
14
+ export const TYPEDSOCKET_MAX_QUEUED_TEXT_BYTES = 4 * 1024 * 1024;
15
+ export const TYPEDSOCKET_MAX_CONCURRENT_CLIENT_HANDLERS = 16;
16
+ export const TYPEDSOCKET_MAX_RETAINED_CLIENT_CALLBACKS = 64;
17
+ export const TYPEDSOCKET_MAX_PENDING_CLIENT_REQUESTS = 1024;
18
+ export const TYPEDSOCKET_MAX_OUTBOUND_BUFFERED_BYTES = 4 * 1024 * 1024;
19
+ export const TYPEDSOCKET_MAX_METHOD_NAME_BYTES = 256;
20
+ export const TYPEDSOCKET_MAX_CORRELATION_ID_BYTES = 256;
21
+ export const TYPEDSOCKET_MAX_REQUEST_TIMEOUT_MS = 5 * 60 * 1000;
22
+ export const TYPEDSOCKET_MAX_CONNECTION_RESTORE_TIMEOUT_MS = 10_000;
23
+ export const TYPEDSOCKET_MAX_RECONNECT_RETRIES = 100;
24
+ export const TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS = 60_000;
25
+ export const TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS_PER_PEER = 64;
26
+ export const TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS = 1024;
27
+ export const TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS_PER_PEER = 8;
28
+ export const TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS = 64;
29
+ export class TypedSocketConnectionRestoreDeniedError extends Error {
30
+ constructor(messageArg) {
31
+ super(messageArg);
32
+ this.name = 'TypedSocketConnectionRestoreDeniedError';
33
+ }
34
+ }
35
+ /**
36
+ * Creates a typed connection wrapper around one IWebSocketPeer.
37
+ */
38
+ function wrapSmartServePeer(peer) {
39
+ return {
40
+ peer,
41
+ async getTagById(tagId) {
42
+ if (!peer.tags.has(tagId)) {
43
+ return undefined;
44
+ }
45
+ const payload = peer.data.get(`${TAG_PREFIX}${tagId}`);
46
+ return { id: tagId, payload };
47
+ },
48
+ };
49
+ }
50
+ function composeAbortSignals(configuredSignalArg, requestSignalArg) {
51
+ if (!configuredSignalArg || configuredSignalArg === requestSignalArg) {
52
+ return {
53
+ signal: requestSignalArg ?? configuredSignalArg,
54
+ cleanup: () => { },
55
+ };
56
+ }
57
+ if (!requestSignalArg) {
58
+ return {
59
+ signal: configuredSignalArg,
60
+ cleanup: () => { },
61
+ };
62
+ }
63
+ const abortController = new AbortController();
64
+ const configuredAbortListener = () => {
65
+ abortController.abort(configuredSignalArg.reason);
66
+ };
67
+ const requestAbortListener = () => {
68
+ abortController.abort(requestSignalArg.reason);
69
+ };
70
+ const cleanup = () => {
71
+ configuredSignalArg.removeEventListener('abort', configuredAbortListener);
72
+ requestSignalArg.removeEventListener('abort', requestAbortListener);
73
+ };
74
+ if (configuredSignalArg.aborted) {
75
+ configuredAbortListener();
76
+ }
77
+ else if (requestSignalArg.aborted) {
78
+ requestAbortListener();
79
+ }
80
+ else {
81
+ configuredSignalArg.addEventListener('abort', configuredAbortListener, { once: true });
82
+ requestSignalArg.addEventListener('abort', requestAbortListener, { once: true });
83
+ }
84
+ return {
85
+ signal: abortController.signal,
86
+ cleanup,
87
+ };
88
+ }
89
+ const packageClientLimits = Object.freeze({
90
+ textFrameBytes: TYPEDSOCKET_MAX_TEXT_FRAME_BYTES,
91
+ queuedTextFrames: TYPEDSOCKET_MAX_QUEUED_TEXT_FRAMES,
92
+ queuedTextBytes: TYPEDSOCKET_MAX_QUEUED_TEXT_BYTES,
93
+ concurrentHandlers: TYPEDSOCKET_MAX_CONCURRENT_CLIENT_HANDLERS,
94
+ retainedCallbacks: TYPEDSOCKET_MAX_RETAINED_CLIENT_CALLBACKS,
95
+ pendingRequests: TYPEDSOCKET_MAX_PENDING_CLIENT_REQUESTS,
96
+ outboundBufferedBytes: TYPEDSOCKET_MAX_OUTBOUND_BUFFERED_BYTES,
97
+ requestTimeoutMs: TYPEDSOCKET_MAX_REQUEST_TIMEOUT_MS,
98
+ connectionRestoreTimeoutMs: TYPEDSOCKET_MAX_CONNECTION_RESTORE_TIMEOUT_MS,
99
+ });
100
+ function normalizeClientLimits(limitsArg) {
101
+ const lower = (nameArg, valueArg, maximumArg) => {
102
+ const value = valueArg ?? maximumArg;
103
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximumArg) {
104
+ throw new RangeError(`TypedSocket client limit ${nameArg} must be a positive safe integer no greater than ${maximumArg}.`);
105
+ }
106
+ return value;
107
+ };
108
+ const normalized = {
109
+ textFrameBytes: lower('textFrameBytes', limitsArg?.textFrameBytes, packageClientLimits.textFrameBytes),
110
+ queuedTextFrames: lower('queuedTextFrames', limitsArg?.queuedTextFrames, packageClientLimits.queuedTextFrames),
111
+ queuedTextBytes: lower('queuedTextBytes', limitsArg?.queuedTextBytes, packageClientLimits.queuedTextBytes),
112
+ concurrentHandlers: lower('concurrentHandlers', limitsArg?.concurrentHandlers, packageClientLimits.concurrentHandlers),
113
+ retainedCallbacks: lower('retainedCallbacks', limitsArg?.retainedCallbacks, packageClientLimits.retainedCallbacks),
114
+ pendingRequests: lower('pendingRequests', limitsArg?.pendingRequests, packageClientLimits.pendingRequests),
115
+ outboundBufferedBytes: lower('outboundBufferedBytes', limitsArg?.outboundBufferedBytes, packageClientLimits.outboundBufferedBytes),
116
+ requestTimeoutMs: lower('requestTimeoutMs', limitsArg?.requestTimeoutMs, packageClientLimits.requestTimeoutMs),
117
+ connectionRestoreTimeoutMs: lower('connectionRestoreTimeoutMs', limitsArg?.connectionRestoreTimeoutMs, packageClientLimits.connectionRestoreTimeoutMs),
118
+ };
119
+ if (normalized.queuedTextBytes < normalized.textFrameBytes) {
120
+ throw new RangeError('TypedSocket queuedTextBytes must be at least textFrameBytes.');
121
+ }
122
+ return Object.freeze(normalized);
123
+ }
124
+ function normalizeReconnectInteger(nameArg, valueArg, defaultArg, maximumArg, allowZeroArg) {
125
+ const value = valueArg ?? defaultArg;
126
+ if (!Number.isSafeInteger(value)
127
+ || value < (allowZeroArg ? 0 : 1)
128
+ || value > maximumArg) {
129
+ throw new RangeError(`TypedSocket ${nameArg} must be ${allowZeroArg ? 'a non-negative' : 'a positive'} safe integer no greater than ${maximumArg}.`);
130
+ }
131
+ return value;
132
+ }
133
+ function isPlainRecord(valueArg) {
134
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg))
135
+ return false;
136
+ const prototype = Object.getPrototypeOf(valueArg);
137
+ return prototype === Object.prototype || prototype === null;
138
+ }
139
+ function isLoopbackHostname(hostnameArg) {
140
+ const hostname = hostnameArg.toLowerCase().replace(/^\[(.*)\]$/, '$1');
141
+ if (hostname === 'localhost' || hostname.endsWith('.localhost') || hostname === '::1') {
142
+ return true;
143
+ }
144
+ const octets = hostname.split('.');
145
+ return octets.length === 4
146
+ && octets.every((octetArg) => /^\d{1,3}$/.test(octetArg) && Number(octetArg) <= 255)
147
+ && Number(octets[0]) === 127;
148
+ }
149
+ export class TypedSocket {
150
+ // ============================================================================
151
+ // STATIC METHODS
152
+ // ============================================================================
153
+ /**
154
+ * Creates a TypedSocket client using native WebSocket.
155
+ * Works in both browser and Node.js environments.
156
+ *
157
+ * @param typedrouterArg - TypedRouter for handling server-initiated requests
158
+ * @param serverUrlArg - Server URL (e.g., 'http://localhost:3000' or 'wss://example.com')
159
+ * @param options - Connection options
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * const typedRouter = new TypedRouter();
164
+ * const client = await TypedSocket.createClient(
165
+ * typedRouter,
166
+ * 'http://localhost:3000',
167
+ * { autoReconnect: true }
168
+ * );
169
+ * ```
170
+ */
171
+ static async createClient(typedrouterArg, serverUrlArg, options = {}) {
172
+ if (options.autoReconnect !== undefined && typeof options.autoReconnect !== 'boolean') {
173
+ throw new TypeError('TypedSocket autoReconnect must be a boolean.');
174
+ }
175
+ const maxRetries = normalizeReconnectInteger('maxRetries', options.maxRetries, TYPEDSOCKET_MAX_RECONNECT_RETRIES, TYPEDSOCKET_MAX_RECONNECT_RETRIES, true);
176
+ const initialBackoffMs = normalizeReconnectInteger('initialBackoffMs', options.initialBackoffMs, 1000, TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS, false);
177
+ const maxBackoffMs = normalizeReconnectInteger('maxBackoffMs', options.maxBackoffMs, TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS, TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS, false);
178
+ if (initialBackoffMs > maxBackoffMs) {
179
+ throw new RangeError('TypedSocket initialBackoffMs must not exceed maxBackoffMs.');
180
+ }
181
+ const opts = {
182
+ autoReconnect: options.autoReconnect ?? true,
183
+ maxRetries,
184
+ initialBackoffMs,
185
+ maxBackoffMs,
186
+ abortSignal: options.abortSignal,
187
+ nativeByteCapabilityMode: options.nativeByteCapabilityMode ?? 'optional',
188
+ limits: normalizeClientLimits(options.limits),
189
+ restoreConnection: options.restoreConnection,
190
+ };
191
+ const typedSocket = new TypedSocket('client', typedrouterArg, opts.nativeByteCapabilityMode);
192
+ typedSocket.clientOptions = opts;
193
+ typedSocket.serverUrl = serverUrlArg;
194
+ typedSocket.currentBackoff = opts.initialBackoffMs;
195
+ if (opts.abortSignal?.aborted) {
196
+ await typedSocket.stop();
197
+ throw typedSocket.createAbortError();
198
+ }
199
+ if (opts.abortSignal) {
200
+ typedSocket.abortSignalListener = () => {
201
+ void typedSocket.stop();
202
+ };
203
+ opts.abortSignal.addEventListener('abort', typedSocket.abortSignalListener, { once: true });
204
+ }
205
+ try {
206
+ await typedSocket.connect();
207
+ }
208
+ catch (error) {
209
+ await typedSocket.stop();
210
+ throw error;
211
+ }
212
+ return typedSocket;
213
+ }
214
+ /**
215
+ * Returns the current window location origin URL.
216
+ * Useful in browser environments for connecting to the same origin.
217
+ */
218
+ static { this.useWindowLocationOriginUrl = () => {
219
+ return plugins.smarturl.Smarturl.createFromUrl(globalThis.location.origin).toString();
220
+ }; }
221
+ /**
222
+ * Creates a server-side TypedSocket and composes its private protocol
223
+ * handlers into one or more isolated application routers.
224
+ *
225
+ * Call attachSmartServe() after constructing the SmartServe transport.
226
+ */
227
+ static createServer(typedRouterOrRoutersArg, optionsArg = {}) {
228
+ const typedRouters = Array.isArray(typedRouterOrRoutersArg)
229
+ ? [...typedRouterOrRoutersArg]
230
+ : [typedRouterOrRoutersArg];
231
+ if (typedRouters.length === 0) {
232
+ throw new Error('TypedSocket.createServer requires at least one TypedRouter.');
233
+ }
234
+ if (new Set(typedRouters).size !== typedRouters.length) {
235
+ throw new Error('TypedSocket.createServer received the same TypedRouter more than once.');
236
+ }
237
+ const typedSocket = new TypedSocket('server', typedRouters[0], optionsArg.nativeByteCapabilityMode ?? 'optional', optionsArg.nativeByteAuthorizationAdapter, optionsArg.clientTagPolicy);
238
+ const protocolRouter = new plugins.typedrequest.TypedRouter();
239
+ TypedSocket.registerProtocolHandlers(protocolRouter, typedSocket);
240
+ const protocolMethods = new Set(protocolRouter.getMethodNames());
241
+ for (const typedRouter of typedRouters) {
242
+ const collision = typedRouter
243
+ .getMethodNames()
244
+ .find((methodArg) => protocolMethods.has(methodArg));
245
+ if (collision) {
246
+ throw new Error(`TypedSocket protocol handler collides with application method "${collision}".`);
247
+ }
248
+ }
249
+ const detachProtocolRouters = [];
250
+ const detachLegacyPolicies = [];
251
+ try {
252
+ for (const typedRouter of typedRouters) {
253
+ detachProtocolRouters.push(typedRouter.addFallbackRouter(protocolRouter));
254
+ detachLegacyPolicies.push(typedRouter.registerLegacyVirtualStreamPolicy('deny'));
255
+ }
256
+ }
257
+ catch (error) {
258
+ for (const detachLegacyPolicy of detachLegacyPolicies.reverse()) {
259
+ detachLegacyPolicy();
260
+ }
261
+ for (const detachProtocolRouter of detachProtocolRouters.reverse()) {
262
+ detachProtocolRouter();
263
+ }
264
+ throw error;
265
+ }
266
+ typedSocket.serverTypedRouters = typedRouters;
267
+ typedSocket.detachProtocolRouters = detachProtocolRouters;
268
+ typedSocket.detachLegacyVirtualStreamPolicies = detachLegacyPolicies;
269
+ return typedSocket;
270
+ }
271
+ /**
272
+ * Creates and attaches a TypedSocket server to an existing SmartServe
273
+ * instance. Prefer createServer() plus attachSmartServe() when transport
274
+ * construction needs the composed routers first.
275
+ *
276
+ * @param smartServeArg - SmartServe instance configured with the application router
277
+ * @param typedRouterArg - Application TypedRouter used by SmartServe
278
+ *
279
+ * @example
280
+ * ```typescript
281
+ * const typedRouter = new TypedRouter();
282
+ * const smartServe = new SmartServe({
283
+ * port: 3000,
284
+ * websocket: {
285
+ * typedRouter
286
+ * }
287
+ * });
288
+ * await smartServe.start();
289
+ * const typedSocket = TypedSocket.fromSmartServe(smartServe, typedRouter);
290
+ * // Authenticated server handlers assign protected connection metadata with:
291
+ * // typedSocket.setServerTag(peer, 'authenticated', { userId });
292
+ * ```
293
+ */
294
+ static fromSmartServe(smartServeArg, typedRouterArg, optionsArg = {}) {
295
+ const typedSocket = TypedSocket.createServer(typedRouterArg, optionsArg);
296
+ try {
297
+ return typedSocket.attachSmartServe(smartServeArg);
298
+ }
299
+ catch (errorArg) {
300
+ typedSocket.releaseServerComposition();
301
+ throw errorArg;
302
+ }
303
+ }
304
+ /**
305
+ * Registers built-in TypedHandlers for tag management
306
+ */
307
+ static registerProtocolHandlers(typedRouter, typedSocketArg) {
308
+ typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_setTag', async (data, meta) => {
309
+ const peer = typedSocketArg.findServerPeerFromRequest(meta);
310
+ const response = await typedSocketArg.tagPolicyManager.setClientTag(peer, data?.name, data?.payload);
311
+ typedSocketArg.emitTagDenialDiagnostic('set', data?.name, response);
312
+ return response;
313
+ }));
314
+ typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_removeTag', async (data, meta) => {
315
+ const peer = typedSocketArg.findServerPeerFromRequest(meta);
316
+ const response = await typedSocketArg.tagPolicyManager.removeClientTag(peer, data?.name);
317
+ typedSocketArg.emitTagDenialDiagnostic('remove', data?.name, response);
318
+ return response;
319
+ }));
320
+ typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_negotiateCapabilities', async (data, meta) => {
321
+ const peer = typedSocketArg.findServerPeerFromRequest(meta);
322
+ if (!peer || !Array.isArray(data.capabilities)) {
323
+ return {
324
+ protocolMajor: NATIVE_BYTE_PROTOCOL_MAJOR,
325
+ capabilities: [],
326
+ required: false,
327
+ };
328
+ }
329
+ const response = typedSocketArg.nativeBytes.negotiateServerPeer(peer, {
330
+ protocolMajor: data.protocolMajor,
331
+ capabilities: data.capabilities,
332
+ });
333
+ return {
334
+ protocolMajor: response.protocolMajor,
335
+ capabilities: [...response.capabilities],
336
+ required: response.required,
337
+ };
338
+ }));
339
+ }
340
+ // ============================================================================
341
+ // CONSTRUCTOR
342
+ // ============================================================================
343
+ constructor(sideArg, typedrouterArg, nativeByteCapabilityModeArg = 'optional', nativeByteAuthorizationAdapterArg, clientTagPolicyArg) {
344
+ // Connection status observable
345
+ this.statusSubject = new plugins.smartrx.rxjs.Subject();
346
+ /**
347
+ * Structured diagnostics: why a connection was closed, denied, or retried.
348
+ * Never completes, mirroring statusSubject; subscribers own unsubscription.
349
+ */
350
+ this.diagnosticsSubject = new plugins.smartrx.rxjs.Subject();
351
+ this.connectionStatus = 'new';
352
+ this.reconnectExhaustedReported = false;
353
+ // Client-specific properties
354
+ this.websocket = null;
355
+ this.connectionGeneration = 0;
356
+ this.clientConnectionState = null;
357
+ this.retainedClientCallbacks = 0;
358
+ this.clientOptions = null;
359
+ this.serverUrl = '';
360
+ this.retryCount = 0;
361
+ this.currentBackoff = 1000;
362
+ this.stopped = false;
363
+ this.stopListeners = new Set();
364
+ this.pendingRequests = new Map();
365
+ this.clientTagReconciler = new ClientTagReconciler({
366
+ isCurrentConnection: (stateArg) => this.isCurrentClientConnection(stateArg),
367
+ getCurrentConnectionState: () => this.clientConnectionState,
368
+ getConnectionGeneration: (stateArg) => stateArg.generation,
369
+ getCurrentGeneration: () => this.connectionGeneration,
370
+ fireSetTag: async (nameArg, payloadArg) => await this
371
+ .createTypedRequest('__typedsocket_setTag')
372
+ .fire({ name: nameArg, payload: payloadArg }),
373
+ fireRemoveTag: async (nameArg) => await this
374
+ .createTypedRequest('__typedsocket_removeTag')
375
+ .fire({ name: nameArg }),
376
+ emitDiagnostic: (eventArg) => this.emitDiagnostic(eventArg),
377
+ });
378
+ // Server-specific properties (SmartServe mode)
379
+ this.smartServeRef = null;
380
+ this.serverTypedRouters = [];
381
+ this.detachProtocolRouters = [];
382
+ this.detachLegacyVirtualStreamPolicies = [];
383
+ this.serverStopping = false;
384
+ this.serverLifecycleGeneration = 0;
385
+ this.unsubscribeSmartServeConnectionClose = null;
386
+ this.detachNativeStreamResolvers = [];
387
+ this.detachResponseAuthorityGuards = [];
388
+ this.pendingServerRequests = new Map();
389
+ this.pendingServerRequestIdsByPeer = new Map();
390
+ this.retainedServerInterests = 0;
391
+ this.retainedServerInterestsByPeer = new Map();
392
+ this.side = sideArg;
393
+ this.typedrouter = typedrouterArg;
394
+ this.nativeBytes = new NativeByteManager({
395
+ side: sideArg,
396
+ capabilityMode: nativeByteCapabilityModeArg,
397
+ onDiagnostic: (eventArg) => this.emitDiagnostic(eventArg),
398
+ });
399
+ this.nativeByteAuthorizationAdapter = nativeByteAuthorizationAdapterArg;
400
+ this.tagPolicyManager = new TypedSocketTagPolicyManager(clientTagPolicyArg);
401
+ this.webSocketTransportOwner = this.nativeBytes.webSocketTransportOwner;
402
+ if (sideArg === 'client') {
403
+ let detachLegacyPolicy;
404
+ let detachNativeStreamResolver;
405
+ try {
406
+ detachLegacyPolicy = typedrouterArg.registerLegacyVirtualStreamPolicy('deny');
407
+ detachNativeStreamResolver = typedrouterArg.registerNativeStreamTransportResolver(() => this.nativeBytes.getClientNativeStreamTransport());
408
+ this.detachLegacyVirtualStreamPolicies.push(detachLegacyPolicy);
409
+ this.detachNativeStreamResolvers.push(detachNativeStreamResolver);
410
+ }
411
+ catch (errorArg) {
412
+ detachNativeStreamResolver?.();
413
+ detachLegacyPolicy?.();
414
+ throw errorArg;
415
+ }
416
+ }
417
+ }
418
+ /**
419
+ * Attaches the SmartServe transport after server router composition.
420
+ */
421
+ attachSmartServe(smartServeArg) {
422
+ if (this.side !== 'server') {
423
+ throw new Error('attachSmartServe is only available on servers.');
424
+ }
425
+ if (this.serverStopping) {
426
+ throw new Error('Cannot attach SmartServe after the TypedSocket server has stopped.');
427
+ }
428
+ if (this.smartServeRef) {
429
+ if (this.smartServeRef === smartServeArg) {
430
+ return this;
431
+ }
432
+ throw new Error('TypedSocket server is already attached to a SmartServe instance.');
433
+ }
434
+ const detachResolvers = [];
435
+ const detachResponseGuards = [];
436
+ let unsubscribe;
437
+ let nativeServerAttached = false;
438
+ try {
439
+ for (const typedRouter of this.serverTypedRouters) {
440
+ detachResponseGuards.push(typedRouter.registerIncomingResponseAuthorityGuard((responseArg, contextArg) => {
441
+ return this.authorizeIncomingServerResponse(responseArg, contextArg.typedRouter, contextArg.trustedLocalData);
442
+ }));
443
+ detachResolvers.push(typedRouter.registerNativeStreamTransportResolver((trustedLocalDataArg) => {
444
+ const peer = this.smartServeRef
445
+ ?.getWebSocketConnections()
446
+ .find((peerArg) => peerArg === trustedLocalDataArg.peer);
447
+ return peer ? this.nativeBytes.getServerNativeStreamTransport(peer) : undefined;
448
+ }));
449
+ }
450
+ unsubscribe = smartServeArg.subscribeWebSocketConnectionClose((peerArg) => {
451
+ this.tagPolicyManager.handlePeerClose(peerArg);
452
+ this.cancelPendingServerRequestsForPeer(peerArg, new Error(`TypedSocket target connection closed: ${peerArg.id}`));
453
+ });
454
+ this.nativeBytes.attachServer();
455
+ nativeServerAttached = true;
456
+ this.serverLifecycleGeneration++;
457
+ this.tagPolicyManager.setAttachedPeersProvider(() => smartServeArg.getWebSocketConnections().filter((peerArg) => {
458
+ const routingSurface = peerArg.routingSurface;
459
+ return Boolean(routingSurface && this.serverTypedRouters.includes(routingSurface));
460
+ }));
461
+ this.smartServeRef = smartServeArg;
462
+ this.detachNativeStreamResolvers = detachResolvers;
463
+ this.detachResponseAuthorityGuards = detachResponseGuards;
464
+ this.unsubscribeSmartServeConnectionClose = unsubscribe;
465
+ return this;
466
+ }
467
+ catch (errorArg) {
468
+ unsubscribe?.();
469
+ if (nativeServerAttached) {
470
+ this.nativeBytes.detachServer();
471
+ }
472
+ this.tagPolicyManager.setAttachedPeersProvider(undefined);
473
+ for (const detachResponseGuard of detachResponseGuards.reverse())
474
+ detachResponseGuard();
475
+ for (const detachResolver of detachResolvers.reverse())
476
+ detachResolver();
477
+ throw errorArg;
478
+ }
479
+ }
480
+ // ============================================================================
481
+ // CLIENT METHODS
482
+ // ============================================================================
483
+ /**
484
+ * Connects the client to the server using native WebSocket
485
+ */
486
+ async connect() {
487
+ if (this.stopped || this.clientOptions?.abortSignal?.aborted) {
488
+ throw this.createAbortError();
489
+ }
490
+ const done = plugins.smartpromise.defer();
491
+ let connectionSettled = false;
492
+ let connectionTimeout;
493
+ let abortConnection;
494
+ const settleConnection = (errorArg) => {
495
+ if (connectionSettled) {
496
+ return;
497
+ }
498
+ connectionSettled = true;
499
+ if (connectionTimeout) {
500
+ clearTimeout(connectionTimeout);
501
+ }
502
+ if (abortConnection) {
503
+ this.stopListeners.delete(abortConnection);
504
+ this.clientOptions?.abortSignal?.removeEventListener('abort', abortConnection);
505
+ }
506
+ if (errorArg) {
507
+ done.reject(errorArg);
508
+ }
509
+ else {
510
+ done.resolve();
511
+ }
512
+ };
513
+ this.updateStatus('connecting');
514
+ const wsUrl = this.toWebSocketUrl(this.serverUrl);
515
+ const logEndpoint = this.toRedactedLogEndpoint(wsUrl);
516
+ this.logDebug(`TypedSocket connecting to ${logEndpoint}...`);
517
+ if (this.clientConnectionState) {
518
+ this.abortClientConnectionState(this.clientConnectionState, new Error('TypedSocket connection replaced'));
519
+ }
520
+ const generation = ++this.connectionGeneration;
521
+ const websocket = new WebSocket(wsUrl);
522
+ websocket.binaryType = 'arraybuffer';
523
+ this.websocket = websocket;
524
+ const connectionState = {
525
+ generation,
526
+ connectionId: plugins.smartstring.create.createCryptoRandomString(),
527
+ websocket,
528
+ abortController: new AbortController(),
529
+ queuedTextFrames: [],
530
+ queuedTextBytes: 0,
531
+ activeHandlers: 0,
532
+ };
533
+ this.clientConnectionState = connectionState;
534
+ this.nativeBytes.bindClientConnection(websocket, generation);
535
+ abortConnection = () => {
536
+ if (this.websocket === websocket && this.connectionGeneration === generation) {
537
+ websocket.close();
538
+ }
539
+ settleConnection(this.createAbortError());
540
+ };
541
+ this.stopListeners.add(abortConnection);
542
+ this.clientOptions?.abortSignal?.addEventListener('abort', abortConnection, { once: true });
543
+ connectionTimeout = setTimeout(() => {
544
+ if (this.connectionStatus !== 'connected') {
545
+ this.logTransient(`TypedSocket connection timeout for ${logEndpoint}`);
546
+ if (this.websocket === websocket && this.connectionGeneration === generation) {
547
+ websocket.close();
548
+ }
549
+ settleConnection(new Error('Connection timeout'));
550
+ }
551
+ }, 10000);
552
+ websocket.onopen = async () => {
553
+ try {
554
+ if (this.websocket !== websocket || this.connectionGeneration !== generation)
555
+ return;
556
+ await this.negotiateClientCapabilities(websocket, generation);
557
+ if (this.websocket !== websocket || this.connectionGeneration !== generation)
558
+ return;
559
+ await this.restoreClientConnection(connectionState);
560
+ if (this.websocket !== websocket || this.connectionGeneration !== generation)
561
+ return;
562
+ await this.reapplyClientTags(connectionState);
563
+ if (this.websocket !== websocket
564
+ || this.connectionGeneration !== generation
565
+ || websocket.readyState !== WebSocket.OPEN) {
566
+ throw new Error('TypedSocket connection changed while restoring client tags');
567
+ }
568
+ this.logDebug('TypedSocket connected and client registration restored!');
569
+ this.retryCount = 0;
570
+ this.reconnectExhaustedReported = false;
571
+ this.currentBackoff = this.clientOptions?.initialBackoffMs ?? 1000;
572
+ this.updateStatus('connected');
573
+ settleConnection();
574
+ }
575
+ catch (error) {
576
+ const restorationError = error instanceof Error
577
+ ? error
578
+ : new Error(String(error));
579
+ this.logTransient('TypedSocket client registration restoration failed.');
580
+ settleConnection(restorationError);
581
+ websocket.close();
582
+ }
583
+ };
584
+ websocket.onmessage = (event) => {
585
+ if (this.websocket !== websocket || this.connectionGeneration !== generation)
586
+ return;
587
+ if (typeof event.data === 'string') {
588
+ this.enqueueClientTextFrame(connectionState, event.data);
589
+ return;
590
+ }
591
+ if (event.data instanceof ArrayBuffer || ArrayBuffer.isView(event.data)) {
592
+ this.nativeBytes.enqueueClientRawFrame(websocket, generation, event.data);
593
+ return;
594
+ }
595
+ this.emitConnectionClosedDiagnostic(1003, 'Unsupported WebSocket payload');
596
+ websocket.close(toClientWebSocketCloseCode(1003), 'Unsupported WebSocket payload');
597
+ };
598
+ websocket.onclose = () => {
599
+ if (this.websocket !== websocket || this.connectionGeneration !== generation)
600
+ return;
601
+ this.abortClientConnectionState(connectionState, new Error('TypedSocket disconnected'));
602
+ this.nativeBytes.unbindClientConnection(websocket, generation, new Error('TypedSocket disconnected'));
603
+ if (this.connectionStatus === 'connected') {
604
+ this.handleDisconnect();
605
+ }
606
+ else {
607
+ this.rejectPendingClientRequests(new Error('TypedSocket disconnected'));
608
+ settleConnection(this.stopped || this.clientOptions?.abortSignal?.aborted
609
+ ? this.createAbortError()
610
+ : new Error('TypedSocket connection closed before it opened'));
611
+ }
612
+ };
613
+ websocket.onerror = () => {
614
+ if (this.websocket !== websocket || this.connectionGeneration !== generation)
615
+ return;
616
+ // transient socket errors (network blips, proxy TLS hiccups) are expected
617
+ // and handled by reconnection; only exhausted retries surface as errors
618
+ this.logTransient(`TypedSocket websocket error on ${logEndpoint}`);
619
+ };
620
+ try {
621
+ await done.promise;
622
+ }
623
+ catch (err) {
624
+ if (connectionTimeout) {
625
+ clearTimeout(connectionTimeout);
626
+ }
627
+ if (!(err instanceof NativeByteCapabilityError)
628
+ && !(err instanceof TypedSocketClientTagDeniedError)
629
+ && !(err instanceof TypedSocketConnectionRestoreDeniedError)
630
+ && this.shouldReconnect()) {
631
+ await this.scheduleReconnect();
632
+ if (this.connectionStatus !== 'connected') {
633
+ throw this.stopped || this.clientOptions?.abortSignal?.aborted ? this.createAbortError() : err;
634
+ }
635
+ }
636
+ else {
637
+ throw err;
638
+ }
639
+ }
640
+ }
641
+ async negotiateClientCapabilities(websocketArg, generationArg) {
642
+ const advertisement = this.nativeBytes.getClientNegotiationAdvertisement();
643
+ let negotiatedResponse;
644
+ try {
645
+ const request = {
646
+ method: '__typedsocket_negotiateCapabilities',
647
+ request: {
648
+ protocolMajor: advertisement.protocolMajor,
649
+ capabilities: [...advertisement.capabilities],
650
+ },
651
+ response: {
652
+ protocolMajor: 0,
653
+ capabilities: [],
654
+ required: false,
655
+ },
656
+ };
657
+ const response = await this.sendRequest(request, {
658
+ timeoutMs: Math.min(10_000, this.requireClientOptions().limits.requestTimeoutMs),
659
+ });
660
+ if (response.error)
661
+ throw new NativeByteCapabilityError(response.error.text);
662
+ if (!response.response
663
+ || !Number.isSafeInteger(response.response.protocolMajor)
664
+ || !Array.isArray(response.response.capabilities)
665
+ || response.response.capabilities.some((capabilityArg) => typeof capabilityArg !== 'string')
666
+ || typeof response.response.required !== 'boolean') {
667
+ throw new NativeByteCapabilityError('TypedSocket server returned malformed capabilities');
668
+ }
669
+ negotiatedResponse = response.response;
670
+ }
671
+ catch (errorArg) {
672
+ if (this.clientOptions?.nativeByteCapabilityMode === 'required') {
673
+ throw errorArg instanceof NativeByteCapabilityError
674
+ ? errorArg
675
+ : new NativeByteCapabilityError('Required native-byte-v1 negotiation failed', {
676
+ cause: errorArg,
677
+ });
678
+ }
679
+ this.nativeBytes.failOptionalClientNegotiation(websocketArg, generationArg);
680
+ return;
681
+ }
682
+ if (negotiatedResponse.required
683
+ && (negotiatedResponse.protocolMajor !== NATIVE_BYTE_PROTOCOL_MAJOR
684
+ || negotiatedResponse.capabilities.length !== 1
685
+ || negotiatedResponse.capabilities[0] !== NATIVE_BYTE_PROTOCOL
686
+ || this.clientOptions?.nativeByteCapabilityMode === 'disabled')) {
687
+ throw new NativeByteCapabilityError('TypedSocket server requires native-byte-v1');
688
+ }
689
+ this.nativeBytes.completeClientNegotiation(websocketArg, generationArg, negotiatedResponse);
690
+ }
691
+ async restoreClientConnection(stateArg) {
692
+ const restoreConnection = this.clientOptions?.restoreConnection;
693
+ if (!restoreConnection)
694
+ return;
695
+ const limits = this.requireClientOptions().limits;
696
+ if (this.retainedClientCallbacks >= limits.retainedCallbacks) {
697
+ throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration callback capacity exhausted.');
698
+ }
699
+ const timeoutMs = limits.connectionRestoreTimeoutMs;
700
+ const deadline = Date.now() + timeoutMs;
701
+ const restorationAbortController = new AbortController();
702
+ const interruptRestoration = () => {
703
+ restorationAbortController.abort(new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration was interrupted.'));
704
+ };
705
+ stateArg.abortController.signal.addEventListener('abort', interruptRestoration, { once: true });
706
+ if (stateArg.abortController.signal.aborted)
707
+ interruptRestoration();
708
+ const createTypedRequest = (methodNameArg) => {
709
+ if (restorationAbortController.signal.aborted) {
710
+ throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration request was interrupted.');
711
+ }
712
+ const remainingMs = deadline - Date.now();
713
+ if (!Number.isSafeInteger(remainingMs) || remainingMs < 1) {
714
+ throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration request exceeded its deadline.');
715
+ }
716
+ return this.createTypedRequest(methodNameArg, undefined, {
717
+ timeoutMs: Math.min(remainingMs + 1, limits.requestTimeoutMs),
718
+ abortSignal: restorationAbortController.signal,
719
+ });
720
+ };
721
+ this.retainedClientCallbacks++;
722
+ const callbackOutcome = Promise.resolve().then(() => restoreConnection(Object.freeze({
723
+ connectionId: stateArg.connectionId,
724
+ abortSignal: restorationAbortController.signal,
725
+ deadline,
726
+ createTypedRequest,
727
+ })));
728
+ void callbackOutcome.then(() => { this.retainedClientCallbacks--; }, () => { this.retainedClientCallbacks--; });
729
+ let timeout;
730
+ let abortListener;
731
+ const interrupted = new Promise((_resolveArg, rejectArg) => {
732
+ timeout = setTimeout(() => {
733
+ const error = new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration timed out.');
734
+ restorationAbortController.abort(error);
735
+ rejectArg(error);
736
+ }, timeoutMs);
737
+ abortListener = () => {
738
+ const reason = restorationAbortController.signal.reason;
739
+ rejectArg(reason instanceof TypedSocketConnectionRestoreDeniedError
740
+ ? reason
741
+ : new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration was interrupted.'));
742
+ };
743
+ restorationAbortController.signal.addEventListener('abort', abortListener, { once: true });
744
+ if (restorationAbortController.signal.aborted)
745
+ abortListener();
746
+ });
747
+ try {
748
+ await Promise.race([callbackOutcome, interrupted]);
749
+ }
750
+ catch (errorArg) {
751
+ if (errorArg instanceof TypedSocketConnectionRestoreDeniedError)
752
+ throw errorArg;
753
+ throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration was denied.');
754
+ }
755
+ finally {
756
+ if (timeout)
757
+ clearTimeout(timeout);
758
+ if (abortListener) {
759
+ restorationAbortController.signal.removeEventListener('abort', abortListener);
760
+ }
761
+ stateArg.abortController.signal.removeEventListener('abort', interruptRestoration);
762
+ restorationAbortController.abort(new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration callback completed.'));
763
+ }
764
+ if (!this.isCurrentClientConnection(stateArg)) {
765
+ throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection changed during restoration.');
766
+ }
767
+ }
768
+ /**
769
+ * Converts an HTTP(S) URL to a WebSocket URL
770
+ */
771
+ toWebSocketUrl(url) {
772
+ const parsed = new URL(url);
773
+ if (parsed.username || parsed.password) {
774
+ throw new Error('TypedSocket server URL must not contain userinfo.');
775
+ }
776
+ if (parsed.hash) {
777
+ throw new Error('TypedSocket server URL must not contain a fragment.');
778
+ }
779
+ const wsProtocol = (() => {
780
+ switch (parsed.protocol) {
781
+ case 'http:':
782
+ case 'ws:':
783
+ return 'ws:';
784
+ case 'https:':
785
+ case 'wss:':
786
+ return 'wss:';
787
+ default:
788
+ throw new Error('TypedSocket server URL must use http, https, ws, or wss.');
789
+ }
790
+ })();
791
+ if (wsProtocol === 'ws:' && !isLoopbackHostname(parsed.hostname)) {
792
+ throw new Error('TypedSocket insecure WebSocket transport is restricted to loopback hosts.');
793
+ }
794
+ parsed.protocol = wsProtocol;
795
+ return parsed.toString();
796
+ }
797
+ toRedactedLogEndpoint(urlArg) {
798
+ const parsed = new URL(urlArg);
799
+ return `${parsed.protocol}//${parsed.host}`;
800
+ }
801
+ enqueueClientTextFrame(stateArg, textArg) {
802
+ if (!this.isCurrentClientConnection(stateArg))
803
+ return;
804
+ const limits = this.requireClientOptions().limits;
805
+ const byteLength = textEncoder.encode(textArg).byteLength;
806
+ if (byteLength > limits.textFrameBytes) {
807
+ this.emitConnectionClosedDiagnostic(1009, 'TypedSocket text frame exceeds package limit');
808
+ stateArg.websocket.close(toClientWebSocketCloseCode(1009), 'TypedSocket text frame exceeds package limit');
809
+ return;
810
+ }
811
+ if (stateArg.queuedTextFrames.length >= limits.queuedTextFrames
812
+ || stateArg.queuedTextBytes + byteLength > limits.queuedTextBytes) {
813
+ this.emitConnectionClosedDiagnostic(1008, 'TypedSocket text queue exceeds package limit');
814
+ stateArg.websocket.close(toClientWebSocketCloseCode(1008), 'TypedSocket text queue exceeds package limit');
815
+ return;
816
+ }
817
+ stateArg.queuedTextFrames.push({ text: textArg, byteLength });
818
+ stateArg.queuedTextBytes += byteLength;
819
+ this.drainClientTextFrames(stateArg);
820
+ }
821
+ drainClientTextFrames(stateArg) {
822
+ const limits = this.requireClientOptions().limits;
823
+ while (this.isCurrentClientConnection(stateArg)
824
+ && !stateArg.abortController.signal.aborted
825
+ && stateArg.queuedTextFrames.length > 0
826
+ && stateArg.activeHandlers < limits.concurrentHandlers) {
827
+ if (this.retainedClientCallbacks >= limits.retainedCallbacks) {
828
+ this.emitConnectionClosedDiagnostic(1013, 'TypedSocket callback capacity exhausted');
829
+ stateArg.websocket.close(toClientWebSocketCloseCode(1013), 'TypedSocket callback capacity exhausted');
830
+ return;
831
+ }
832
+ const frame = stateArg.queuedTextFrames.shift();
833
+ if (!frame)
834
+ return;
835
+ stateArg.queuedTextBytes -= frame.byteLength;
836
+ stateArg.activeHandlers++;
837
+ this.retainedClientCallbacks++;
838
+ void this.handleMessage(frame.text, stateArg)
839
+ .catch(() => {
840
+ if (this.isCurrentClientConnection(stateArg)) {
841
+ this.emitConnectionClosedDiagnostic(1008, 'TypedSocket rejected malformed text envelope');
842
+ stateArg.websocket.close(toClientWebSocketCloseCode(1008), 'TypedSocket rejected malformed text envelope');
843
+ }
844
+ })
845
+ .finally(() => {
846
+ stateArg.activeHandlers--;
847
+ this.retainedClientCallbacks--;
848
+ this.drainClientTextFrames(stateArg);
849
+ });
850
+ }
851
+ }
852
+ assertClientEnvelope(valueArg) {
853
+ if (!isPlainRecord(valueArg) || Object.hasOwn(valueArg, 'localData')) {
854
+ throw new Error('TypedSocket received an invalid text envelope.');
855
+ }
856
+ assertBoundedTextIdentifier(valueArg.method, 'method', TYPEDSOCKET_MAX_METHOD_NAME_BYTES);
857
+ const correlation = valueArg.correlation;
858
+ if (!isPlainRecord(correlation)) {
859
+ throw new Error('TypedSocket received an invalid correlation envelope.');
860
+ }
861
+ assertBoundedTextIdentifier(correlation.id, 'correlation ID', TYPEDSOCKET_MAX_CORRELATION_ID_BYTES);
862
+ if (correlation.phase !== 'request' && correlation.phase !== 'response') {
863
+ throw new Error('TypedSocket received an invalid correlation phase.');
864
+ }
865
+ if (correlation.phase === 'request' && !Object.hasOwn(valueArg, 'request')) {
866
+ throw new Error('TypedSocket request envelope has no request payload.');
867
+ }
868
+ if (correlation.phase === 'response'
869
+ && !Object.hasOwn(valueArg, 'response')
870
+ && !Object.hasOwn(valueArg, 'error')) {
871
+ throw new Error('TypedSocket response envelope has no response or error payload.');
872
+ }
873
+ }
874
+ async handleMessage(dataArg, stateArg = this.clientConnectionState) {
875
+ if (!stateArg || !this.isCurrentClientConnection(stateArg))
876
+ return;
877
+ const message = plugins.smartjson.parse(dataArg);
878
+ this.assertClientEnvelope(message);
879
+ const correlation = message.correlation;
880
+ if (correlation.phase === 'response') {
881
+ const pending = this.pendingRequests.get(correlation.id);
882
+ if (!pending)
883
+ return;
884
+ if (pending.connectionGeneration !== stateArg.generation
885
+ || pending.expectedMethod !== message.method) {
886
+ throw new Error('TypedSocket response authority mismatch.');
887
+ }
888
+ this.pendingRequests.delete(correlation.id);
889
+ pending.resolve(message);
890
+ return;
891
+ }
892
+ const response = await this.typedrouter.routeAndAddResponse(message);
893
+ if (!response || !this.isCurrentClientConnection(stateArg))
894
+ return;
895
+ this.sendClientTextEnvelope(response, stateArg);
896
+ }
897
+ sendClientTextEnvelope(envelopeArg, stateArg) {
898
+ if (!this.isCurrentClientConnection(stateArg)) {
899
+ throw new Error('TypedSocket connection changed before text send.');
900
+ }
901
+ const encoded = plugins.smartjson.stringify(envelopeArg);
902
+ const byteLength = textEncoder.encode(encoded).byteLength;
903
+ const limits = this.requireClientOptions().limits;
904
+ if (byteLength > limits.textFrameBytes) {
905
+ throw new Error(`TypedSocket outbound envelope exceeds ${limits.textFrameBytes} UTF-8 bytes.`);
906
+ }
907
+ if (stateArg.websocket.bufferedAmount + byteLength > limits.outboundBufferedBytes) {
908
+ throw new Error('TypedSocket outbound WebSocket buffer capacity exceeded.');
909
+ }
910
+ stateArg.websocket.send(encoded);
911
+ }
912
+ isCurrentClientConnection(stateArg) {
913
+ return Boolean(this.clientConnectionState === stateArg
914
+ && this.websocket === stateArg.websocket
915
+ && this.connectionGeneration === stateArg.generation
916
+ && stateArg.websocket.readyState === WebSocket.OPEN);
917
+ }
918
+ abortClientConnectionState(stateArg, reasonArg) {
919
+ if (!stateArg.abortController.signal.aborted) {
920
+ stateArg.abortController.abort(reasonArg);
921
+ }
922
+ stateArg.queuedTextFrames.length = 0;
923
+ stateArg.queuedTextBytes = 0;
924
+ if (this.clientConnectionState === stateArg) {
925
+ this.clientConnectionState = null;
926
+ }
927
+ }
928
+ /**
929
+ * Handles WebSocket disconnection
930
+ */
931
+ handleDisconnect() {
932
+ if (this.connectionStatus === 'disconnected') {
933
+ return; // Already handled
934
+ }
935
+ this.updateStatus('disconnected');
936
+ // Reject all pending requests — the connection is gone and they'll never receive a response
937
+ this.rejectPendingClientRequests(new Error('TypedSocket disconnected'));
938
+ if (this.shouldReconnect()) {
939
+ this.scheduleReconnect();
940
+ }
941
+ }
942
+ /**
943
+ * Schedules a reconnection attempt with exponential backoff
944
+ */
945
+ async scheduleReconnect() {
946
+ if (!this.shouldReconnect())
947
+ return;
948
+ const clientOptions = this.requireClientOptions();
949
+ this.updateStatus('reconnecting');
950
+ this.retryCount++;
951
+ // Exponential backoff with jitter
952
+ const jitter = this.currentBackoff * 0.2 * (Math.random() * 2 - 1);
953
+ const delay = Math.min(this.currentBackoff + jitter, clientOptions.maxBackoffMs);
954
+ this.logDebug(`TypedSocket reconnecting in ${Math.round(delay)}ms (attempt ${this.retryCount}/${clientOptions.maxRetries})`);
955
+ this.emitDiagnostic({
956
+ kind: 'reconnectScheduled',
957
+ side: 'client',
958
+ attempt: this.retryCount,
959
+ maxRetries: clientOptions.maxRetries,
960
+ delayMs: Math.round(delay),
961
+ endpoint: this.toRedactedLogEndpoint(this.toWebSocketUrl(this.serverUrl)),
962
+ });
963
+ await this.waitForReconnectDelay(delay);
964
+ if (!this.shouldReconnect())
965
+ return;
966
+ // Increase backoff for next time
967
+ this.currentBackoff = Math.min(this.currentBackoff * 2, clientOptions.maxBackoffMs);
968
+ try {
969
+ await this.connect();
970
+ }
971
+ catch {
972
+ if (this.shouldReconnect()) {
973
+ this.logDebug('TypedSocket reconnection attempt failed.');
974
+ }
975
+ else if (!this.stopped && !this.clientOptions?.abortSignal?.aborted) {
976
+ const endpoint = this.toRedactedLogEndpoint(this.toWebSocketUrl(this.serverUrl));
977
+ console.error(`TypedSocket giving up on ${endpoint} after ${this.retryCount} attempts.`);
978
+ if (!this.reconnectExhaustedReported) {
979
+ this.reconnectExhaustedReported = true;
980
+ this.emitDiagnostic({
981
+ kind: 'reconnectExhausted',
982
+ side: 'client',
983
+ attempts: this.retryCount,
984
+ endpoint,
985
+ });
986
+ }
987
+ }
988
+ }
989
+ }
990
+ /**
991
+ * Lifecycle chatter: hidden by default in browser devtools (verbose level)
992
+ * and irrelevant for servers, but available when debugging.
993
+ */
994
+ logDebug(messageArg) {
995
+ console.debug(messageArg);
996
+ }
997
+ /**
998
+ * Failures that reconnection is expected to recover from. Logged as debug
999
+ * while retries remain; the final failure is reported by scheduleReconnect.
1000
+ */
1001
+ logTransient(messageArg) {
1002
+ if (this.shouldReconnect()) {
1003
+ this.logDebug(messageArg);
1004
+ }
1005
+ else if (!this.stopped && !this.clientOptions?.abortSignal?.aborted) {
1006
+ console.warn(messageArg);
1007
+ }
1008
+ }
1009
+ shouldReconnect() {
1010
+ return Boolean(this.clientOptions?.autoReconnect &&
1011
+ !this.stopped &&
1012
+ !this.clientOptions.abortSignal?.aborted &&
1013
+ this.retryCount < this.clientOptions.maxRetries);
1014
+ }
1015
+ async waitForReconnectDelay(delayMsArg) {
1016
+ await new Promise((resolve) => {
1017
+ let timeout;
1018
+ let finished = false;
1019
+ const finish = () => {
1020
+ if (finished)
1021
+ return;
1022
+ finished = true;
1023
+ if (timeout) {
1024
+ clearTimeout(timeout);
1025
+ }
1026
+ this.stopListeners.delete(finish);
1027
+ this.clientOptions?.abortSignal?.removeEventListener('abort', finish);
1028
+ resolve();
1029
+ };
1030
+ if (this.clientOptions?.abortSignal?.aborted) {
1031
+ finish();
1032
+ return;
1033
+ }
1034
+ if (this.stopped) {
1035
+ finish();
1036
+ return;
1037
+ }
1038
+ timeout = setTimeout(finish, delayMsArg);
1039
+ this.stopListeners.add(finish);
1040
+ this.clientOptions?.abortSignal?.addEventListener('abort', finish, { once: true });
1041
+ });
1042
+ }
1043
+ createAbortError() {
1044
+ return new Error('TypedSocket client startup aborted');
1045
+ }
1046
+ rejectPendingClientRequests(errorArg) {
1047
+ for (const pending of this.pendingRequests.values()) {
1048
+ pending.reject(errorArg);
1049
+ }
1050
+ this.pendingRequests.clear();
1051
+ }
1052
+ /**
1053
+ * Updates connection status and notifies subscribers
1054
+ */
1055
+ updateStatus(status) {
1056
+ if (this.connectionStatus !== status) {
1057
+ this.connectionStatus = status;
1058
+ this.statusSubject.next(status);
1059
+ }
1060
+ }
1061
+ /**
1062
+ * Diagnostics must never disturb transport code paths: subscriber errors
1063
+ * are swallowed here.
1064
+ */
1065
+ emitDiagnostic(eventArg) {
1066
+ try {
1067
+ this.diagnosticsSubject.next(eventArg);
1068
+ }
1069
+ catch { }
1070
+ }
1071
+ emitConnectionClosedDiagnostic(closeCodeArg, reasonArg) {
1072
+ this.emitDiagnostic({
1073
+ kind: 'connectionClosed',
1074
+ side: this.side,
1075
+ scope: 'text',
1076
+ closeCode: closeCodeArg,
1077
+ reason: reasonArg,
1078
+ });
1079
+ }
1080
+ emitTagDenialDiagnostic(operationArg, nameArg, responseArg) {
1081
+ if (responseArg.success !== false)
1082
+ return;
1083
+ let name = '';
1084
+ try {
1085
+ assertBoundedTextIdentifier(nameArg, 'tag name', TYPEDSOCKET_MAX_TAG_NAME_BYTES);
1086
+ name = nameArg;
1087
+ }
1088
+ catch { }
1089
+ this.emitDiagnostic({
1090
+ kind: 'tagMutationDenied',
1091
+ side: 'server',
1092
+ operation: operationArg,
1093
+ name,
1094
+ code: responseArg.code,
1095
+ });
1096
+ }
1097
+ /**
1098
+ * Sends a request to the server and waits for response (client-side)
1099
+ */
1100
+ async sendRequest(request, optionsArg = {}) {
1101
+ if (request.method === '##VirtualStream##') {
1102
+ throw new Error('Legacy VirtualStream control request rejected by transport policy');
1103
+ }
1104
+ const state = this.clientConnectionState;
1105
+ if (!state || !this.isCurrentClientConnection(state)) {
1106
+ throw new Error('WebSocket not connected');
1107
+ }
1108
+ const timeoutMs = this.normalizeRequestTimeout(optionsArg.timeoutMs);
1109
+ if (optionsArg.abortSignal?.aborted) {
1110
+ throw new Error('TypedSocket request aborted');
1111
+ }
1112
+ request.correlation ||= {
1113
+ id: plugins.smartstring.create.createCryptoRandomString(),
1114
+ phase: 'request',
1115
+ };
1116
+ assertBoundedTextIdentifier(request.method, 'method', TYPEDSOCKET_MAX_METHOD_NAME_BYTES);
1117
+ assertBoundedTextIdentifier(request.correlation.id, 'correlation ID', TYPEDSOCKET_MAX_CORRELATION_ID_BYTES);
1118
+ if (request.correlation.phase !== 'request') {
1119
+ throw new Error('TypedSocket outbound requests require request correlation phase.');
1120
+ }
1121
+ const correlationId = request.correlation.id;
1122
+ if (this.pendingRequests.has(correlationId)) {
1123
+ throw new Error(`Duplicate in-flight TypedSocket correlation ID: ${correlationId}`);
1124
+ }
1125
+ if (this.pendingRequests.size >= this.requireClientOptions().limits.pendingRequests) {
1126
+ throw new Error('TypedSocket pending client request capacity exceeded.');
1127
+ }
1128
+ return new Promise((resolve, reject) => {
1129
+ let settled = false;
1130
+ const cleanup = () => {
1131
+ clearTimeout(timeout);
1132
+ optionsArg.abortSignal?.removeEventListener('abort', onAbort);
1133
+ this.pendingRequests.delete(correlationId);
1134
+ };
1135
+ const settle = (errorArg, responseArg) => {
1136
+ if (settled) {
1137
+ return;
1138
+ }
1139
+ settled = true;
1140
+ cleanup();
1141
+ if (errorArg) {
1142
+ reject(errorArg);
1143
+ }
1144
+ else if (!responseArg) {
1145
+ reject(new Error('TypedSocket request settled without a response.'));
1146
+ }
1147
+ else {
1148
+ resolve(responseArg);
1149
+ }
1150
+ };
1151
+ const onAbort = () => settle(new Error('TypedSocket request aborted'));
1152
+ const timeout = setTimeout(() => {
1153
+ settle(new Error('TypedSocket request timed out'));
1154
+ }, timeoutMs);
1155
+ this.pendingRequests.set(correlationId, {
1156
+ expectedMethod: request.method,
1157
+ connectionGeneration: state.generation,
1158
+ resolve: (response) => {
1159
+ request.response = response.response;
1160
+ request.correlation = response.correlation;
1161
+ if (response.error)
1162
+ request.error = response.error;
1163
+ else
1164
+ delete request.error;
1165
+ if (response.retry)
1166
+ request.retry = response.retry;
1167
+ else
1168
+ delete request.retry;
1169
+ settle(undefined, request);
1170
+ },
1171
+ reject: (error) => {
1172
+ settle(error);
1173
+ },
1174
+ });
1175
+ optionsArg.abortSignal?.addEventListener('abort', onAbort, { once: true });
1176
+ if (optionsArg.abortSignal?.aborted) {
1177
+ onAbort();
1178
+ return;
1179
+ }
1180
+ try {
1181
+ this.sendClientTextEnvelope(request, state);
1182
+ }
1183
+ catch (error) {
1184
+ settle(error instanceof Error ? error : new Error(String(error)));
1185
+ }
1186
+ });
1187
+ }
1188
+ normalizeRequestTimeout(timeoutMsArg) {
1189
+ const maximum = this.clientOptions?.limits.requestTimeoutMs
1190
+ ?? TYPEDSOCKET_MAX_REQUEST_TIMEOUT_MS;
1191
+ const timeoutMs = timeoutMsArg ?? Math.min(30_000, maximum);
1192
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > maximum) {
1193
+ throw new Error(`TypedSocket request timeout must be a positive safe integer no greater than ${maximum}.`);
1194
+ }
1195
+ return timeoutMs;
1196
+ }
1197
+ requireClientOptions() {
1198
+ if (!this.clientOptions) {
1199
+ throw new Error('TypedSocket client options are unavailable on this instance.');
1200
+ }
1201
+ return this.clientOptions;
1202
+ }
1203
+ cancelPendingServerRequestsForPeer(peerArg, errorArg) {
1204
+ const correlationIds = this.pendingServerRequestIdsByPeer.get(peerArg);
1205
+ if (!correlationIds) {
1206
+ return;
1207
+ }
1208
+ for (const correlationId of Array.from(correlationIds)) {
1209
+ this.pendingServerRequests.get(correlationId)?.cancel(errorArg);
1210
+ }
1211
+ }
1212
+ retainServerInterestRegistration(peerArg) {
1213
+ const retainedForPeer = this.retainedServerInterestsByPeer.get(peerArg) ?? 0;
1214
+ if (retainedForPeer >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS_PER_PEER
1215
+ || this.retainedServerInterests >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS) {
1216
+ throw new Error('TypedSocket server interest registration capacity exceeded.');
1217
+ }
1218
+ this.retainedServerInterests++;
1219
+ this.retainedServerInterestsByPeer.set(peerArg, retainedForPeer + 1);
1220
+ let released = false;
1221
+ return () => {
1222
+ if (released)
1223
+ return;
1224
+ released = true;
1225
+ this.retainedServerInterests--;
1226
+ const currentForPeer = this.retainedServerInterestsByPeer.get(peerArg);
1227
+ if (currentForPeer === undefined || currentForPeer < 1) {
1228
+ throw new Error('TypedSocket server interest registration accounting underflow.');
1229
+ }
1230
+ if (currentForPeer === 1) {
1231
+ this.retainedServerInterestsByPeer.delete(peerArg);
1232
+ }
1233
+ else {
1234
+ this.retainedServerInterestsByPeer.set(peerArg, currentForPeer - 1);
1235
+ }
1236
+ };
1237
+ }
1238
+ authorizeIncomingServerResponse(responseArg, routingSurfaceArg, trustedLocalDataArg) {
1239
+ if (this.serverStopping
1240
+ || !this.smartServeRef
1241
+ || responseArg.correlation?.phase !== 'response'
1242
+ || typeof responseArg.correlation.id !== 'string'
1243
+ || typeof responseArg.method !== 'string') {
1244
+ return false;
1245
+ }
1246
+ const peer = trustedLocalDataArg.peer;
1247
+ if (!peer || typeof peer !== 'object')
1248
+ return false;
1249
+ const pending = this.pendingServerRequests.get(responseArg.correlation.id);
1250
+ return Boolean(pending
1251
+ && pending.peer === peer
1252
+ && pending.routingSurface === routingSurfaceArg
1253
+ && pending.expectedMethod === responseArg.method
1254
+ && pending.lifecycleGeneration === this.serverLifecycleGeneration
1255
+ && pending.peer.routingSurface === routingSurfaceArg
1256
+ && this.isAttachedServerPeer(pending.peer));
1257
+ }
1258
+ isAttachedServerPeer(peerArg) {
1259
+ return Boolean(!this.serverStopping
1260
+ && this.smartServeRef
1261
+ && peerArg.readyState === 1
1262
+ && peerArg.routingSurface
1263
+ && this.serverTypedRouters.includes(peerArg.routingSurface)
1264
+ && this.smartServeRef.getWebSocketConnections().includes(peerArg));
1265
+ }
1266
+ findServerPeerFromRequest(typedToolsArg) {
1267
+ const candidate = typedToolsArg?.localData?.peer;
1268
+ const peer = this.smartServeRef
1269
+ ?.getWebSocketConnections()
1270
+ .find((peerArg) => peerArg === candidate);
1271
+ return peer && this.isAttachedServerPeer(peer) ? peer : undefined;
1272
+ }
1273
+ async sendServerRequest(typedRequestDataArg, targetArg, optionsArg) {
1274
+ const timeoutMs = this.normalizeRequestTimeout(optionsArg.timeoutMs);
1275
+ if (this.serverStopping || !this.smartServeRef) {
1276
+ throw new Error('TypedSocket server stopped');
1277
+ }
1278
+ if (optionsArg.abortSignal?.aborted) {
1279
+ throw new Error('TypedSocket request aborted');
1280
+ }
1281
+ typedRequestDataArg.correlation ||= {
1282
+ id: plugins.smartstring.create.createCryptoRandomString(),
1283
+ phase: 'request',
1284
+ };
1285
+ assertBoundedTextIdentifier(typedRequestDataArg.method, 'method', TYPEDSOCKET_MAX_METHOD_NAME_BYTES);
1286
+ assertBoundedTextIdentifier(typedRequestDataArg.correlation.id, 'correlation ID', TYPEDSOCKET_MAX_CORRELATION_ID_BYTES);
1287
+ if (typedRequestDataArg.correlation.phase !== 'request') {
1288
+ throw new Error('TypedSocket outbound requests require request correlation phase.');
1289
+ }
1290
+ const correlationId = typedRequestDataArg.correlation.id;
1291
+ const peer = targetArg.peer;
1292
+ const peerId = targetArg.peer.id;
1293
+ const routingSurface = peer.routingSurface;
1294
+ if (!routingSurface || !this.serverTypedRouters.includes(routingSurface)) {
1295
+ throw new Error('TypedSocket target connection is not bound to this server routing surface');
1296
+ }
1297
+ if (!this.isAttachedServerPeer(peer)) {
1298
+ throw new Error(`TypedSocket target connection is detached or closed: ${peerId}`);
1299
+ }
1300
+ if (this.pendingServerRequests.has(correlationId)) {
1301
+ throw new Error(`Duplicate in-flight TypedSocket correlation ID: ${correlationId}`);
1302
+ }
1303
+ const requestsForPeer = this.pendingServerRequestIdsByPeer.get(peer) ?? new Set();
1304
+ if (requestsForPeer.size >= TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS_PER_PEER
1305
+ || this.pendingServerRequests.size >= TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS) {
1306
+ throw new Error('TypedSocket pending server request capacity exceeded.');
1307
+ }
1308
+ if ((this.retainedServerInterestsByPeer.get(peer) ?? 0)
1309
+ >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS_PER_PEER
1310
+ || this.retainedServerInterests >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS) {
1311
+ throw new Error('TypedSocket server interest registration capacity exceeded.');
1312
+ }
1313
+ const cancellation = plugins.smartpromise.defer();
1314
+ // A stop/abort may happen while InterestMap.addInterest is yielding. Attach
1315
+ // a rejection handler immediately; Promise.race below still receives the
1316
+ // original rejection once the interest exists.
1317
+ void cancellation.promise.catch(() => { });
1318
+ const cleanup = plugins.smartpromise.defer();
1319
+ let cancellationRequested = false;
1320
+ const cancel = (errorArg) => {
1321
+ if (cancellationRequested) {
1322
+ return;
1323
+ }
1324
+ cancellationRequested = true;
1325
+ cancellation.reject(errorArg);
1326
+ };
1327
+ const pendingRequest = {
1328
+ peer,
1329
+ peerId,
1330
+ routingSurface,
1331
+ expectedMethod: typedRequestDataArg.method,
1332
+ lifecycleGeneration: this.serverLifecycleGeneration,
1333
+ cancel,
1334
+ cleanupComplete: cleanup.promise,
1335
+ };
1336
+ this.pendingServerRequests.set(correlationId, pendingRequest);
1337
+ requestsForPeer.add(correlationId);
1338
+ this.pendingServerRequestIdsByPeer.set(peer, requestsForPeer);
1339
+ const onAbort = () => cancel(new Error('TypedSocket request aborted'));
1340
+ const timeout = setTimeout(() => cancel(new Error(`TypedSocket request timed out after ${timeoutMs}ms`)), timeoutMs);
1341
+ optionsArg.abortSignal?.addEventListener('abort', onAbort, { once: true });
1342
+ if (optionsArg.abortSignal?.aborted) {
1343
+ onAbort();
1344
+ }
1345
+ const destroyInterests = [];
1346
+ try {
1347
+ const releaseInterestRegistration = this.retainServerInterestRegistration(peer);
1348
+ const interestRegistration = Promise.resolve()
1349
+ .then(() => routingSurface.fireEventInterestMap.addInterest(correlationId, typedRequestDataArg))
1350
+ .then((interestArg) => {
1351
+ if (cancellationRequested || this.serverStopping) {
1352
+ interestArg.destroy();
1353
+ }
1354
+ return interestArg;
1355
+ })
1356
+ .finally(releaseInterestRegistration);
1357
+ const interest = await Promise.race([
1358
+ interestRegistration,
1359
+ cancellation.promise,
1360
+ ]);
1361
+ if (cancellationRequested || this.serverStopping) {
1362
+ interest.destroy();
1363
+ await cancellation.promise;
1364
+ }
1365
+ destroyInterests.push(() => interest.destroy());
1366
+ // Establish the rejecting race before send so synchronous close/abort and
1367
+ // send failures all use the same cleanup path.
1368
+ const response = Promise.race([
1369
+ interest.interestFullfilled,
1370
+ cancellation.promise,
1371
+ ]);
1372
+ const targetIsStillConnected = this.smartServeRef
1373
+ ?.getWebSocketConnections()
1374
+ .some((peerArg) => peerArg === peer) ?? false;
1375
+ if (!targetIsStillConnected) {
1376
+ cancel(new Error(`TypedSocket target connection closed: ${peerId}`));
1377
+ }
1378
+ if (this.serverStopping) {
1379
+ cancel(new Error('TypedSocket server stopped'));
1380
+ }
1381
+ if (!cancellationRequested && targetIsStillConnected && !this.serverStopping) {
1382
+ targetArg.peer.send(plugins.smartjson.stringify(typedRequestDataArg));
1383
+ }
1384
+ const routedResponse = await response;
1385
+ typedRequestDataArg.response = routedResponse.response;
1386
+ typedRequestDataArg.correlation = routedResponse.correlation;
1387
+ if (routedResponse.error)
1388
+ typedRequestDataArg.error = routedResponse.error;
1389
+ else
1390
+ delete typedRequestDataArg.error;
1391
+ if (routedResponse.retry)
1392
+ typedRequestDataArg.retry = routedResponse.retry;
1393
+ else
1394
+ delete typedRequestDataArg.retry;
1395
+ return typedRequestDataArg;
1396
+ }
1397
+ finally {
1398
+ clearTimeout(timeout);
1399
+ optionsArg.abortSignal?.removeEventListener('abort', onAbort);
1400
+ this.pendingServerRequests.delete(correlationId);
1401
+ const remainingRequestsForPeer = this.pendingServerRequestIdsByPeer.get(peer);
1402
+ remainingRequestsForPeer?.delete(correlationId);
1403
+ if (remainingRequestsForPeer?.size === 0) {
1404
+ this.pendingServerRequestIdsByPeer.delete(peer);
1405
+ }
1406
+ for (const destroyInterest of destroyInterests) {
1407
+ destroyInterest();
1408
+ }
1409
+ cleanup.resolve();
1410
+ }
1411
+ }
1412
+ // ============================================================================
1413
+ // PUBLIC API - SHARED
1414
+ // ============================================================================
1415
+ /**
1416
+ * Creates a TypedRequest for the specified method.
1417
+ * On clients, sends to the server.
1418
+ * On servers, sends to the specified target connection.
1419
+ */
1420
+ createTypedRequest(methodName, targetConnection, optionsArg = {}) {
1421
+ let implicitTargetingReported = false;
1422
+ const postMethod = async (requestDataArg, postOptionsArg = {}) => {
1423
+ const composedAbortSignal = composeAbortSignals(optionsArg.abortSignal, postOptionsArg.signal);
1424
+ const requestOptions = {
1425
+ ...optionsArg,
1426
+ abortSignal: composedAbortSignal.signal,
1427
+ };
1428
+ try {
1429
+ if (this.side === 'client') {
1430
+ return await this.sendRequest(requestDataArg, requestOptions);
1431
+ }
1432
+ // Server-side: send to target connection
1433
+ if (!this.smartServeRef) {
1434
+ throw new Error('Server not initialized');
1435
+ }
1436
+ let target = targetConnection;
1437
+ if (!target) {
1438
+ if (this.serverTypedRouters.length > 1) {
1439
+ throw new Error('TypedSocket multi-router servers require an explicit targetConnection');
1440
+ }
1441
+ const routingSurface = this.serverTypedRouters[0];
1442
+ const allConnections = this.smartServeRef.getWebSocketConnections().filter((peerArg) => peerArg.routingSurface === routingSurface);
1443
+ if (allConnections.length === 1) {
1444
+ const peer = allConnections[0];
1445
+ target = wrapSmartServePeer(peer);
1446
+ // Deprecated: implicit single-connection targeting is slated for
1447
+ // removal in the next major; it also disables native-byte
1448
+ // transport for the request because no peer was known at
1449
+ // createTypedRequest() time.
1450
+ if (!implicitTargetingReported) {
1451
+ implicitTargetingReported = true;
1452
+ this.emitDiagnostic({
1453
+ kind: 'implicitTargetingUsed',
1454
+ side: 'server',
1455
+ method: methodName,
1456
+ });
1457
+ }
1458
+ }
1459
+ else if (allConnections.length === 0) {
1460
+ throw new Error('No WebSocket connections available');
1461
+ }
1462
+ else {
1463
+ throw new Error('Multiple connections available - specify targetConnection');
1464
+ }
1465
+ }
1466
+ return await this.sendServerRequest(requestDataArg, target, requestOptions);
1467
+ }
1468
+ finally {
1469
+ composedAbortSignal.cleanup();
1470
+ }
1471
+ };
1472
+ const nativeStreamTransport = this.side === 'client'
1473
+ ? this.nativeBytes.getClientNativeStreamTransport()
1474
+ : targetConnection
1475
+ ? this.nativeBytes.getServerNativeStreamTransport(targetConnection.peer)
1476
+ : undefined;
1477
+ return new plugins.typedrequest.TypedRequest(new plugins.typedrequest.TypedTarget({
1478
+ postMethod,
1479
+ supportsAbortSignal: true,
1480
+ nativeStreamTransport,
1481
+ legacyVirtualStreams: 'deny',
1482
+ }), methodName);
1483
+ }
1484
+ /**
1485
+ * Creates an exact authorized native-byte receive facade for one server peer.
1486
+ * TypedRequest carries its opaque descriptor when the facade enters a DTO.
1487
+ */
1488
+ createVirtualStream(optionsArg) {
1489
+ if (this.side !== 'server') {
1490
+ throw new Error('createVirtualStream is only available on servers');
1491
+ }
1492
+ if (optionsArg.protocol !== NATIVE_BYTE_PROTOCOL
1493
+ || optionsArg.direction !== 'receive') {
1494
+ throw new TypeError('createVirtualStream requires native-byte-v1 receive direction');
1495
+ }
1496
+ const authorizationAdapter = this.nativeByteAuthorizationAdapter;
1497
+ if (!authorizationAdapter) {
1498
+ throw new NativeByteCapabilityError('createVirtualStream requires a nativeByteAuthorizationAdapter');
1499
+ }
1500
+ const peer = 'peer' in optionsArg.target
1501
+ ? optionsArg.target.peer
1502
+ : optionsArg.target;
1503
+ const transport = this.nativeBytes.getServerNativeStreamTransport(peer);
1504
+ if (!transport) {
1505
+ throw new NativeByteCapabilityError('createVirtualStream target is not an active native-byte-v1 peer');
1506
+ }
1507
+ transport.requireCapability({ capability: NATIVE_BYTE_PROTOCOL });
1508
+ const manifest = this.nativeBytes.normalizeManifest({
1509
+ byteLength: optionsArg.byteLength,
1510
+ sha256: optionsArg.sha256,
1511
+ contentType: optionsArg.contentType,
1512
+ });
1513
+ const authorizationBinding = authorizationAdapter.bind(optionsArg.authorization, Object.freeze({ target: peer, manifest }));
1514
+ if (!authorizationBinding
1515
+ || typeof authorizationBinding !== 'object'
1516
+ || typeof Reflect.get(authorizationBinding, 'then') === 'function') {
1517
+ throw new TypeError('nativeByteAuthorizationAdapter.bind() must return a synchronous binding');
1518
+ }
1519
+ const registration = this.nativeBytes.createReceiveRegistration({
1520
+ target: peer,
1521
+ ...manifest,
1522
+ initialWindowBytes: optionsArg.initialWindowBytes,
1523
+ principalId: authorizationBinding.principalId,
1524
+ credentialRevision: authorizationBinding.credentialRevision,
1525
+ configRevision: authorizationBinding.configRevision,
1526
+ bindingRevision: authorizationBinding.bindingRevision,
1527
+ revalidate: authorizationBinding.revalidate,
1528
+ });
1529
+ return plugins.typedrequest.VirtualStream.fromNativeByteRegistration({
1530
+ transport,
1531
+ registration,
1532
+ });
1533
+ }
1534
+ /**
1535
+ * Gets the current connection status
1536
+ */
1537
+ getStatus() {
1538
+ return this.connectionStatus;
1539
+ }
1540
+ /**
1541
+ * Stops the TypedSocket client or cleans up server state
1542
+ */
1543
+ async stop() {
1544
+ if (this.side === 'client') {
1545
+ this.stopped = true;
1546
+ for (const stopListener of Array.from(this.stopListeners)) {
1547
+ stopListener();
1548
+ }
1549
+ this.stopListeners.clear();
1550
+ if (this.clientOptions) {
1551
+ this.clientOptions.autoReconnect = false;
1552
+ if (this.clientOptions.abortSignal && this.abortSignalListener) {
1553
+ this.clientOptions.abortSignal.removeEventListener('abort', this.abortSignalListener);
1554
+ }
1555
+ }
1556
+ this.abortSignalListener = undefined;
1557
+ if (this.websocket) {
1558
+ const websocket = this.websocket;
1559
+ const generation = this.connectionGeneration;
1560
+ if (this.clientConnectionState) {
1561
+ this.abortClientConnectionState(this.clientConnectionState, new Error('TypedSocket stopped'));
1562
+ }
1563
+ this.nativeBytes.unbindClientConnection(websocket, generation, new Error('TypedSocket stopped'));
1564
+ websocket.close();
1565
+ this.websocket = null;
1566
+ }
1567
+ for (const pendingRequest of this.pendingRequests.values()) {
1568
+ pendingRequest.reject(new Error('TypedSocket stopped'));
1569
+ }
1570
+ this.pendingRequests.clear();
1571
+ }
1572
+ else {
1573
+ this.serverStopping = true;
1574
+ this.serverLifecycleGeneration++;
1575
+ this.tagPolicyManager.stop(this.smartServeRef?.getWebSocketConnections() ?? []);
1576
+ const pendingRequests = Array.from(this.pendingServerRequests.values());
1577
+ for (const pendingRequest of pendingRequests) {
1578
+ pendingRequest.cancel(new Error('TypedSocket server stopped'));
1579
+ }
1580
+ await Promise.all(pendingRequests.map((pendingRequest) => pendingRequest.cleanupComplete));
1581
+ this.unsubscribeSmartServeConnectionClose?.();
1582
+ this.unsubscribeSmartServeConnectionClose = null;
1583
+ this.nativeBytes.detachServer();
1584
+ this.tagPolicyManager.setAttachedPeersProvider(undefined);
1585
+ this.smartServeRef = null;
1586
+ this.pendingServerRequestIdsByPeer.clear();
1587
+ }
1588
+ for (const detachNativeStreamResolver of this.detachNativeStreamResolvers.reverse()) {
1589
+ detachNativeStreamResolver();
1590
+ }
1591
+ this.detachNativeStreamResolvers = [];
1592
+ for (const detachResponseAuthorityGuard of this.detachResponseAuthorityGuards.reverse()) {
1593
+ detachResponseAuthorityGuard();
1594
+ }
1595
+ this.detachResponseAuthorityGuards = [];
1596
+ if (this.side === 'server') {
1597
+ this.releaseServerComposition();
1598
+ }
1599
+ }
1600
+ releaseServerComposition() {
1601
+ for (const detachLegacyPolicy of this.detachLegacyVirtualStreamPolicies.reverse()) {
1602
+ detachLegacyPolicy();
1603
+ }
1604
+ this.detachLegacyVirtualStreamPolicies = [];
1605
+ for (const detachProtocolRouter of this.detachProtocolRouters.reverse()) {
1606
+ detachProtocolRouter();
1607
+ }
1608
+ this.detachProtocolRouters = [];
1609
+ }
1610
+ // ============================================================================
1611
+ // CLIENT-ONLY METHODS
1612
+ // ============================================================================
1613
+ /**
1614
+ * Sets a tag on this client connection.
1615
+ * Tags are stored on the server and can be used for filtering.
1616
+ * @client-only
1617
+ */
1618
+ async setTag(name, payload) {
1619
+ if (this.side !== 'client') {
1620
+ throw new Error('setTag is only available on clients');
1621
+ }
1622
+ return await this.clientTagReconciler.setTag(name, payload);
1623
+ }
1624
+ /**
1625
+ * Re-applies all client tags after a reconnect, since server-side tags are
1626
+ * bound to the previous connection.
1627
+ */
1628
+ async reapplyClientTags(stateArg = this.clientConnectionState) {
1629
+ await this.clientTagReconciler.reapplyTags(stateArg);
1630
+ }
1631
+ /**
1632
+ * Removes a tag from this client connection.
1633
+ * @client-only
1634
+ */
1635
+ async removeTag(name) {
1636
+ if (this.side !== 'client') {
1637
+ throw new Error('removeTag is only available on clients');
1638
+ }
1639
+ return await this.clientTagReconciler.removeTag(name);
1640
+ }
1641
+ // ============================================================================
1642
+ // SERVER-ONLY METHODS
1643
+ // ============================================================================
1644
+ /**
1645
+ * Resolves the exact SmartServe transport peer for one incoming TypedRequest.
1646
+ * Server handlers can pass their TypedTools argument without type assertions.
1647
+ */
1648
+ getServerConnectionForRequest(typedToolsArg) {
1649
+ if (this.side !== 'server') {
1650
+ throw new Error('getServerConnectionForRequest is only available on servers');
1651
+ }
1652
+ const peer = this.findServerPeerFromRequest(typedToolsArg);
1653
+ if (!peer) {
1654
+ throw new Error('TypedSocket request is not bound to an attached transport peer');
1655
+ }
1656
+ return wrapSmartServePeer(peer);
1657
+ }
1658
+ /** Assigns a protected server-owned tag to one connection. */
1659
+ setServerTag(connectionArg, nameArg, payloadArg) {
1660
+ if (this.side !== 'server') {
1661
+ throw new Error('setServerTag is only available on servers');
1662
+ }
1663
+ this.tagPolicyManager.setServerTag('peer' in connectionArg ? connectionArg.peer : connectionArg, nameArg, payloadArg);
1664
+ }
1665
+ /** Removes a server-owned tag while keeping its name protected from clients. */
1666
+ removeServerTag(connectionArg, nameArg) {
1667
+ if (this.side !== 'server') {
1668
+ throw new Error('removeServerTag is only available on servers');
1669
+ }
1670
+ this.tagPolicyManager.removeServerTag('peer' in connectionArg ? connectionArg.peer : connectionArg, nameArg);
1671
+ }
1672
+ /**
1673
+ * Finds all connections matching the filter function.
1674
+ * @server-only
1675
+ */
1676
+ async findAllTargetConnections(asyncFindFuncArg) {
1677
+ if (this.side !== 'server' || !this.smartServeRef) {
1678
+ throw new Error('findAllTargetConnections is only available on servers');
1679
+ }
1680
+ const matchingConnections = [];
1681
+ for (const peer of this.smartServeRef.getWebSocketConnections()) {
1682
+ if (!this.isAttachedServerPeer(peer))
1683
+ continue;
1684
+ const wrapper = wrapSmartServePeer(peer);
1685
+ if (await asyncFindFuncArg(wrapper)) {
1686
+ matchingConnections.push(wrapper);
1687
+ }
1688
+ }
1689
+ return matchingConnections;
1690
+ }
1691
+ /**
1692
+ * Finds the first connection matching the filter function.
1693
+ * @server-only
1694
+ */
1695
+ async findTargetConnection(asyncFindFuncArg) {
1696
+ const allMatching = await this.findAllTargetConnections(asyncFindFuncArg);
1697
+ return allMatching[0];
1698
+ }
1699
+ /**
1700
+ * Finds all connections with the specified tag.
1701
+ * @server-only
1702
+ */
1703
+ async findAllTargetConnectionsByTag(keyArg, payloadArg) {
1704
+ if (this.side !== 'server' || !this.smartServeRef) {
1705
+ throw new Error('findAllTargetConnectionsByTag is only available on servers');
1706
+ }
1707
+ const peers = this.smartServeRef
1708
+ .getWebSocketConnectionsByTag(keyArg)
1709
+ .filter((peerArg) => this.isAttachedServerPeer(peerArg));
1710
+ const results = [];
1711
+ for (const peer of peers) {
1712
+ const wrapper = wrapSmartServePeer(peer);
1713
+ // If payload specified, also filter by payload
1714
+ if (payloadArg !== undefined) {
1715
+ const tag = await wrapper.getTagById(keyArg);
1716
+ if (plugins.smartjson.stringify(tag?.payload) !== plugins.smartjson.stringify(payloadArg)) {
1717
+ continue;
1718
+ }
1719
+ }
1720
+ results.push(wrapper);
1721
+ }
1722
+ return results;
1723
+ }
1724
+ /**
1725
+ * Finds the first connection with the specified tag.
1726
+ * @server-only
1727
+ */
1728
+ async findTargetConnectionByTag(keyArg, payloadArg) {
1729
+ const allResults = await this.findAllTargetConnectionsByTag(keyArg, payloadArg);
1730
+ return allResults[0];
1731
+ }
1732
+ }
1733
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50eXBlZHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMudHlwZWRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLDBCQUEwQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDOUYsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDekUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbkUsT0FBTyxFQUNMLDJCQUEyQixFQUMzQiw4QkFBOEIsRUFDOUIsK0JBQStCLEVBQy9CLDJCQUEyQixHQUM1QixNQUFNLDBDQUEwQyxDQUFDO0FBQ2xELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3BFLE9BQU8sRUFDTCw2Q0FBNkMsRUFDN0Msc0RBQXNELEdBQ3ZELE1BQU0sa0NBQWtDLENBQUM7QUFtQjFDLE1BQU0sVUFBVSxHQUFHLHFCQUFxQixDQUFDO0FBQ3pDLE1BQU0sV0FBVyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7QUFFdEMsTUFBTSxDQUFDLE1BQU0sZ0NBQWdDLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUM1RCxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxFQUFFLENBQUM7QUFDckQsTUFBTSxDQUFDLE1BQU0saUNBQWlDLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDakUsTUFBTSxDQUFDLE1BQU0sMENBQTBDLEdBQUcsRUFBRSxDQUFDO0FBQzdELE1BQU0sQ0FBQyxNQUFNLHlDQUF5QyxHQUFHLEVB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