@api.global/typedsocket 7.1.0 → 8.0.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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@api.global/typedsocket',
6
- version: '7.1.0',
6
+ version: '8.0.0',
7
7
  description: 'A library for creating typed WebSocket connections, supporting bi-directional communication with type safety.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLCtHQUErRztDQUM3SCxDQUFBIn0=
@@ -0,0 +1,61 @@
1
+ import * as plugins from './plugins.js';
2
+ export declare const TYPEDSOCKET_MAX_ACTIVE_REQUEST_HANDLERS_PER_CONNECTION = 64;
3
+ export declare const TYPEDSOCKET_MAX_ACTIVE_REQUEST_HANDLERS = 1024;
4
+ export declare const TYPEDSOCKET_MAX_REQUEST_CANCELLATION_TOMBSTONES_PER_CONNECTION = 1024;
5
+ export declare const TYPEDSOCKET_MAX_REQUEST_CANCELLATION_TOMBSTONES = 16384;
6
+ export declare const TYPEDSOCKET_REQUEST_HANDLER_MAX_LIFETIME_MS: number;
7
+ export declare const TYPEDSOCKET_REQUEST_CANCELLATION_TOMBSTONE_RETENTION_MS = 10000;
8
+ /** Internal control-flow error for an authenticated remote cancellation. */
9
+ export declare class TypedSocketRemoteRequestCancellationError extends plugins.typedrequest.TypedResponseError {
10
+ constructor();
11
+ }
12
+ export interface IRequestCancellationIdentity {
13
+ readonly method: string;
14
+ readonly correlationId: string;
15
+ readonly requestInstanceId: string;
16
+ }
17
+ export interface IRequestCancellationContext {
18
+ readonly connection: object;
19
+ readonly routingSurface: object;
20
+ readonly generation: number;
21
+ close(reasonArg: string): void;
22
+ }
23
+ export type TRequestSignalRegistration = plugins.typedrequest.ITypedRouterRequestSignalRegistration;
24
+ export interface IRequestCancellationManagerOptions {
25
+ readonly maxActivePerConnection?: number;
26
+ readonly maxActive?: number;
27
+ readonly maxTombstonesPerConnection?: number;
28
+ readonly maxTombstones?: number;
29
+ readonly activeLifetimeMs?: number;
30
+ readonly tombstoneRetentionMs?: number;
31
+ }
32
+ export declare class RequestCancellationManager {
33
+ private readonly states;
34
+ private readonly limits;
35
+ private activeCount;
36
+ private detachedActiveCount;
37
+ private tombstoneCount;
38
+ private stopped;
39
+ constructor(optionsArg?: IRequestCancellationManagerOptions);
40
+ register(contextArg: IRequestCancellationContext, identityArg: IRequestCancellationIdentity): TRequestSignalRegistration;
41
+ cancel(contextArg: IRequestCancellationContext, identityArg: IRequestCancellationIdentity): void;
42
+ closeConnection(connectionArg: object, reasonArg: unknown): void;
43
+ stop(reasonArg: unknown): void;
44
+ getStats(): Readonly<{
45
+ /** Registrations that have not called complete(), including detached work. */
46
+ active: number;
47
+ /** Aborted registrations detached from their connection but not yet complete. */
48
+ detachedActive: number;
49
+ tombstones: number;
50
+ /** Cancellation states still attached to a physical connection. */
51
+ connections: number;
52
+ }>;
53
+ private getState;
54
+ private completeActive;
55
+ private addTombstone;
56
+ private deleteTombstone;
57
+ private reclaimGlobalTombstoneCapacity;
58
+ private failConnection;
59
+ private createKey;
60
+ private getValidatedKey;
61
+ }
@@ -0,0 +1,234 @@
1
+ import * as plugins from './plugins.js';
2
+ export const TYPEDSOCKET_MAX_ACTIVE_REQUEST_HANDLERS_PER_CONNECTION = 64;
3
+ export const TYPEDSOCKET_MAX_ACTIVE_REQUEST_HANDLERS = 1024;
4
+ export const TYPEDSOCKET_MAX_REQUEST_CANCELLATION_TOMBSTONES_PER_CONNECTION = 1024;
5
+ export const TYPEDSOCKET_MAX_REQUEST_CANCELLATION_TOMBSTONES = 16_384;
6
+ export const TYPEDSOCKET_REQUEST_HANDLER_MAX_LIFETIME_MS = 5 * 60 * 1000;
7
+ export const TYPEDSOCKET_REQUEST_CANCELLATION_TOMBSTONE_RETENTION_MS = 10_000;
8
+ /** Internal control-flow error for an authenticated remote cancellation. */
9
+ export class TypedSocketRemoteRequestCancellationError extends plugins.typedrequest.TypedResponseError {
10
+ constructor() {
11
+ super('TypedSocket remote request cancelled');
12
+ this.name = 'TypedSocketRemoteRequestCancellationError';
13
+ }
14
+ }
15
+ export class RequestCancellationManager {
16
+ constructor(optionsArg = {}) {
17
+ this.states = new Map();
18
+ this.activeCount = 0;
19
+ this.detachedActiveCount = 0;
20
+ this.tombstoneCount = 0;
21
+ this.stopped = false;
22
+ this.limits = {
23
+ maxActivePerConnection: optionsArg.maxActivePerConnection
24
+ ?? TYPEDSOCKET_MAX_ACTIVE_REQUEST_HANDLERS_PER_CONNECTION,
25
+ maxActive: optionsArg.maxActive ?? TYPEDSOCKET_MAX_ACTIVE_REQUEST_HANDLERS,
26
+ maxTombstonesPerConnection: optionsArg.maxTombstonesPerConnection
27
+ ?? TYPEDSOCKET_MAX_REQUEST_CANCELLATION_TOMBSTONES_PER_CONNECTION,
28
+ maxTombstones: optionsArg.maxTombstones
29
+ ?? TYPEDSOCKET_MAX_REQUEST_CANCELLATION_TOMBSTONES,
30
+ activeLifetimeMs: optionsArg.activeLifetimeMs
31
+ ?? TYPEDSOCKET_REQUEST_HANDLER_MAX_LIFETIME_MS,
32
+ tombstoneRetentionMs: optionsArg.tombstoneRetentionMs
33
+ ?? TYPEDSOCKET_REQUEST_CANCELLATION_TOMBSTONE_RETENTION_MS,
34
+ };
35
+ for (const [name, value] of Object.entries(this.limits)) {
36
+ if (!Number.isSafeInteger(value) || value < 1) {
37
+ throw new RangeError(`Request cancellation limit ${name} must be a positive safe integer`);
38
+ }
39
+ }
40
+ }
41
+ register(contextArg, identityArg) {
42
+ const state = this.getState(contextArg);
43
+ const key = this.getValidatedKey(state, identityArg);
44
+ if (state.active.has(key) || state.tombstones.get(key)?.kind === 'terminal') {
45
+ this.failConnection(state, 'TypedSocket request instance was replayed');
46
+ throw new Error('TypedSocket request instance was replayed');
47
+ }
48
+ if (state.active.size >= this.limits.maxActivePerConnection
49
+ || this.activeCount >= this.limits.maxActive) {
50
+ this.failConnection(state, 'TypedSocket active request handler capacity exhausted');
51
+ throw new Error('TypedSocket active request handler capacity exhausted');
52
+ }
53
+ const earlyCancel = state.tombstones.get(key)?.kind === 'early-cancel';
54
+ if (earlyCancel)
55
+ this.deleteTombstone(state, key);
56
+ const abortController = new AbortController();
57
+ const activeRequest = {
58
+ key,
59
+ context: state.context,
60
+ abortController,
61
+ completed: false,
62
+ timeout: setTimeout(() => {
63
+ this.failConnection(state, 'TypedSocket request handler lifetime exceeded');
64
+ }, this.limits.activeLifetimeMs),
65
+ };
66
+ activeRequest.timeout.unref?.();
67
+ state.active.set(key, activeRequest);
68
+ this.activeCount++;
69
+ if (earlyCancel) {
70
+ abortController.abort(new TypedSocketRemoteRequestCancellationError());
71
+ }
72
+ return Object.freeze({
73
+ abortSignal: abortController.signal,
74
+ complete: () => this.completeActive(state, activeRequest),
75
+ });
76
+ }
77
+ cancel(contextArg, identityArg) {
78
+ const state = this.getState(contextArg);
79
+ const key = this.getValidatedKey(state, identityArg);
80
+ const activeRequest = state.active.get(key);
81
+ if (activeRequest) {
82
+ activeRequest.abortController.abort(new TypedSocketRemoteRequestCancellationError());
83
+ return;
84
+ }
85
+ if (state.tombstones.has(key))
86
+ return;
87
+ this.addTombstone(state, key, 'early-cancel');
88
+ }
89
+ closeConnection(connectionArg, reasonArg) {
90
+ const state = this.states.get(connectionArg);
91
+ if (!state)
92
+ return;
93
+ state.closed = true;
94
+ this.states.delete(connectionArg);
95
+ for (const activeRequest of state.active.values()) {
96
+ clearTimeout(activeRequest.timeout);
97
+ this.detachedActiveCount++;
98
+ activeRequest.abortController.abort(reasonArg);
99
+ }
100
+ for (const key of Array.from(state.tombstones.keys())) {
101
+ this.deleteTombstone(state, key);
102
+ }
103
+ }
104
+ stop(reasonArg) {
105
+ if (this.stopped)
106
+ return;
107
+ this.stopped = true;
108
+ for (const connection of Array.from(this.states.keys())) {
109
+ this.closeConnection(connection, reasonArg);
110
+ }
111
+ }
112
+ getStats() {
113
+ return Object.freeze({
114
+ active: this.activeCount,
115
+ detachedActive: this.detachedActiveCount,
116
+ tombstones: this.tombstoneCount,
117
+ connections: this.states.size,
118
+ });
119
+ }
120
+ getState(contextArg) {
121
+ if (this.stopped)
122
+ throw new Error('TypedSocket request cancellation manager stopped');
123
+ const existing = this.states.get(contextArg.connection);
124
+ if (existing) {
125
+ if (existing.closed
126
+ || existing.context.routingSurface !== contextArg.routingSurface
127
+ || existing.context.generation !== contextArg.generation) {
128
+ this.failConnection(existing, 'TypedSocket request cancellation authority mismatch');
129
+ throw new Error('TypedSocket request cancellation authority mismatch');
130
+ }
131
+ return existing;
132
+ }
133
+ const state = {
134
+ context: Object.freeze({ ...contextArg }),
135
+ active: new Map(),
136
+ tombstones: new Map(),
137
+ closed: false,
138
+ };
139
+ this.states.set(contextArg.connection, state);
140
+ return state;
141
+ }
142
+ completeActive(stateArg, activeRequestArg) {
143
+ if (activeRequestArg.completed)
144
+ return;
145
+ activeRequestArg.completed = true;
146
+ clearTimeout(activeRequestArg.timeout);
147
+ if (stateArg.active.get(activeRequestArg.key) === activeRequestArg) {
148
+ stateArg.active.delete(activeRequestArg.key);
149
+ this.activeCount--;
150
+ if (stateArg.closed)
151
+ this.detachedActiveCount--;
152
+ }
153
+ if (!stateArg.closed) {
154
+ this.addTombstone(stateArg, activeRequestArg.key, 'terminal');
155
+ }
156
+ }
157
+ addTombstone(stateArg, keyArg, kindArg) {
158
+ if (stateArg.closed)
159
+ return;
160
+ if (stateArg.tombstones.size >= this.limits.maxTombstonesPerConnection) {
161
+ this.failConnection(stateArg, 'TypedSocket per-connection request cancellation tombstone capacity exhausted');
162
+ return;
163
+ }
164
+ if (this.tombstoneCount >= this.limits.maxTombstones
165
+ && !this.reclaimGlobalTombstoneCapacity()) {
166
+ this.failConnection(stateArg, 'TypedSocket global request cancellation tombstone capacity exhausted');
167
+ return;
168
+ }
169
+ if (stateArg.closed)
170
+ return;
171
+ const timeout = setTimeout(() => {
172
+ this.deleteTombstone(stateArg, keyArg);
173
+ }, this.limits.tombstoneRetentionMs);
174
+ timeout.unref?.();
175
+ stateArg.tombstones.set(keyArg, { kind: kindArg, timeout });
176
+ this.tombstoneCount++;
177
+ }
178
+ deleteTombstone(stateArg, keyArg) {
179
+ const tombstone = stateArg.tombstones.get(keyArg);
180
+ if (!tombstone)
181
+ return;
182
+ clearTimeout(tombstone.timeout);
183
+ stateArg.tombstones.delete(keyArg);
184
+ this.tombstoneCount--;
185
+ }
186
+ reclaimGlobalTombstoneCapacity() {
187
+ let largestConsumer;
188
+ // Map iteration is insertion ordered, so equal shares evict the oldest state.
189
+ for (const state of this.states.values()) {
190
+ if (state.closed
191
+ || state.tombstones.size === 0
192
+ || (largestConsumer
193
+ && state.tombstones.size <= largestConsumer.tombstones.size))
194
+ continue;
195
+ largestConsumer = state;
196
+ }
197
+ if (!largestConsumer)
198
+ return false;
199
+ this.failConnection(largestConsumer, 'TypedSocket global request cancellation tombstone capacity exhausted');
200
+ return this.tombstoneCount < this.limits.maxTombstones;
201
+ }
202
+ failConnection(stateArg, reasonArg) {
203
+ if (stateArg.closed)
204
+ return;
205
+ try {
206
+ stateArg.context.close(reasonArg);
207
+ }
208
+ finally {
209
+ this.closeConnection(stateArg.context.connection, new Error(reasonArg));
210
+ }
211
+ }
212
+ createKey(identityArg) {
213
+ return JSON.stringify([
214
+ identityArg.method,
215
+ identityArg.correlationId,
216
+ identityArg.requestInstanceId,
217
+ ]);
218
+ }
219
+ getValidatedKey(stateArg, identityArg) {
220
+ const values = [
221
+ identityArg.method,
222
+ identityArg.correlationId,
223
+ identityArg.requestInstanceId,
224
+ ];
225
+ if (values.some((valueArg) => (typeof valueArg !== 'string'
226
+ || valueArg.length === 0
227
+ || new TextEncoder().encode(valueArg).byteLength > 256))) {
228
+ this.failConnection(stateArg, 'TypedSocket request cancellation identity is malformed');
229
+ throw new Error('TypedSocket request cancellation identity is malformed');
230
+ }
231
+ return this.createKey(identityArg);
232
+ }
233
+ }
234
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yZXF1ZXN0Y2FuY2VsbGF0aW9ubWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMucmVxdWVzdGNhbmNlbGxhdGlvbm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFFeEMsTUFBTSxDQUFDLE1BQU0sc0RBQXNELEdBQUcsRUFBRSxDQUFDO0FBQ3pFLE1BQU0sQ0FBQyxNQUFNLHVDQUF1QyxHQUFHLElBQUksQ0FBQztBQUM1RCxNQUFNLENBQUMsTUFBTSw4REFBOEQsR0FBRyxJQUFJLENBQUM7QUFDbkYsTUFBTSxDQUFDLE1BQU0sK0NBQStDLEdBQUcsTUFBTSxDQUFDO0FBQ3RFLE1BQU0sQ0FBQyxNQUFNLDJDQUEyQyxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ3pFLE1BQU0sQ0FBQyxNQUFNLHVEQUF1RCxHQUFHLE1BQU0sQ0FBQztBQUU5RSw0RUFBNEU7QUFDNUUsTUFBTSxPQUFPLHlDQUNYLFNBQVEsT0FBTyxDQUFDLFlBQVksQ0FBQyxrQkFBa0I7SUFDL0M7UUFDRSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztRQUM5QyxJQUFJLENBQUMsSUFBSSxHQUFHLDJDQUEyQyxDQUFDO0lBQzFELENBQUM7Q0FDRjtBQStDRCxNQUFNLE9BQU8sMEJBQTBCO0lBUXJDLFlBQVksYUFBaUQsRUFBRTtRQVA5QyxXQUFNLEdBQUcsSUFBSSxHQUFHLEVBQXdDLENBQUM7UUFFbEUsZ0JBQVcsR0FBRyxDQUFDLENBQUM7UUFDaEIsd0JBQW1CLEdBQUcsQ0FBQyxDQUFDO1FBQ3hCLG1CQUFjLEdBQUcsQ0FBQyxDQUFDO1FBQ25CLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFHdEIsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLHNCQUFzQixFQUFFLFVBQVUsQ0FBQyxzQkFBc0I7bUJBQ3BELHNEQUFzRDtZQUMzRCxTQUFTLEVBQUUsVUFBVSxDQUFDLFNBQVMsSUFBSSx1Q0FBdUM7WUFDMUUsMEJBQTBCLEVBQUUsVUFBVSxDQUFDLDBCQUEwQjttQkFDNUQsOERBQThEO1lBQ25FLGFBQWEsRUFBRSxVQUFVLENBQUMsYUFBYTttQkFDbEMsK0NBQStDO1lBQ3BELGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxnQkFBZ0I7bUJBQ3hDLDJDQUEyQztZQUNoRCxvQkFBb0IsRUFBRSxVQUFVLENBQUMsb0JBQW9CO21CQUNoRCx1REFBdUQ7U0FDN0QsQ0FBQztRQUNGLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ3hELElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDOUMsTUFBTSxJQUFJLFVBQVUsQ0FBQyw4QkFBOEIsSUFBSSxrQ0FBa0MsQ0FBQyxDQUFDO1lBQzdGLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVNLFFBQVEsQ0FDYixVQUF1QyxFQUN2QyxXQUF5QztRQUV6QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3JELElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQzVFLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLDJDQUEyQyxDQUFDLENBQUM7WUFDeEUsTUFBTSxJQUFJLEtBQUssQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFDRCxJQUNFLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsc0JBQXNCO2VBQ3BELElBQUksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQzVDLENBQUM7WUFDRCxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSx1REFBdUQsQ0FBQyxDQUFDO1lBQ3BGLE1BQU0sSUFBSSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUMzRSxDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsSUFBSSxLQUFLLGNBQWMsQ0FBQztRQUN2RSxJQUFJLFdBQVc7WUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNsRCxNQUFNLGVBQWUsR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1FBQzlDLE1BQU0sYUFBYSxHQUFtQjtZQUNwQyxHQUFHO1lBQ0gsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1lBQ3RCLGVBQWU7WUFDZixTQUFTLEVBQUUsS0FBSztZQUNoQixPQUFPLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDdkIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsK0NBQStDLENBQUMsQ0FBQztZQUM5RSxDQUFDLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztTQUNqQyxDQUFDO1FBQ0YsYUFBYSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ2hDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxhQUFhLENBQUMsQ0FBQztRQUNyQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkIsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNoQixlQUFlLENBQUMsS0FBSyxDQUFDLElBQUkseUNBQXlDLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDbkIsV0FBVyxFQUFFLGVBQWUsQ0FBQyxNQUFNO1lBQ25DLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxhQUFhLENBQUM7U0FDMUQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLE1BQU0sQ0FDWCxVQUF1QyxFQUN2QyxXQUF5QztRQUV6QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3JELE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzVDLElBQUksYUFBYSxFQUFFLENBQUM7WUFDbEIsYUFBYSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsSUFBSSx5Q0FBeUMsRUFBRSxDQUFDLENBQUM7WUFDckYsT0FBTztRQUNULENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztZQUFFLE9BQU87UUFDdEMsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFTSxlQUFlLENBQUMsYUFBcUIsRUFBRSxTQUFrQjtRQUM5RCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsS0FBSztZQUFFLE9BQU87UUFDbkIsS0FBSyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDcEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDbEMsS0FBSyxNQUFNLGFBQWEsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7WUFDbEQsWUFBWSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNwQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUMzQixhQUFhLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNqRCxDQUFDO1FBQ0QsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3RELElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ25DLENBQUM7SUFDSCxDQUFDO0lBRU0sSUFBSSxDQUFDLFNBQWtCO1FBQzVCLElBQUksSUFBSSxDQUFDLE9BQU87WUFBRSxPQUFPO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLEtBQUssTUFBTSxVQUFVLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUN4RCxJQUFJLENBQUMsZUFBZSxDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUM5QyxDQUFDO0lBQ0gsQ0FBQztJQUVNLFFBQVE7UUFTYixPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDbkIsTUFBTSxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQ3hCLGNBQWMsRUFBRSxJQUFJLENBQUMsbUJBQW1CO1lBQ3hDLFVBQVUsRUFBRSxJQUFJLENBQUMsY0FBYztZQUMvQixXQUFXLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJO1NBQzlCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxRQUFRLENBQUMsVUFBdUM7UUFDdEQsSUFBSSxJQUFJLENBQUMsT0FBTztZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztRQUN0RixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEQsSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUNiLElBQ0UsUUFBUSxDQUFDLE1BQU07bUJBQ1osUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEtBQUssVUFBVSxDQUFDLGNBQWM7bUJBQzdELFFBQVEsQ0FBQyxPQUFPLENBQUMsVUFBVSxLQUFLLFVBQVUsQ0FBQyxVQUFVLEVBQ3hELENBQUM7Z0JBQ0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUscURBQXFELENBQUMsQ0FBQztnQkFDckYsTUFBTSxJQUFJLEtBQUssQ0FBQyxxREFBcUQsQ0FBQyxDQUFDO1lBQ3pFLENBQUM7WUFDRCxPQUFPLFFBQVEsQ0FBQztRQUNsQixDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQWlDO1lBQzFDLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsR0FBRyxVQUFVLEVBQUUsQ0FBQztZQUN6QyxNQUFNLEVBQUUsSUFBSSxHQUFHLEVBQUU7WUFDakIsVUFBVSxFQUFFLElBQUksR0FBRyxFQUFFO1lBQ3JCLE1BQU0sRUFBRSxLQUFLO1NBQ2QsQ0FBQztRQUNGLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDOUMsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRU8sY0FBYyxDQUNwQixRQUFzQyxFQUN0QyxnQkFBZ0M7UUFFaEMsSUFBSSxnQkFBZ0IsQ0FBQyxTQUFTO1lBQUUsT0FBTztRQUN2QyxnQkFBZ0IsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO1FBQ2xDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2QyxJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxLQUFLLGdCQUFnQixFQUFFLENBQUM7WUFDbkUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ25CLElBQUksUUFBUSxDQUFDLE1BQU07Z0JBQUUsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFDbEQsQ0FBQztRQUNELElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsZ0JBQWdCLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2hFLENBQUM7SUFDSCxDQUFDO0lBRU8sWUFBWSxDQUNsQixRQUFzQyxFQUN0QyxNQUFjLEVBQ2QsT0FBMkI7UUFFM0IsSUFBSSxRQUFRLENBQUMsTUFBTTtZQUFFLE9BQU87UUFDNUIsSUFBSSxRQUFRLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLDBCQUEwQixFQUFFLENBQUM7WUFDdkUsSUFBSSxDQUFDLGNBQWMsQ0FDakIsUUFBUSxFQUNSLDhFQUE4RSxDQUMvRSxDQUFDO1lBQ0YsT0FBTztRQUNULENBQUM7UUFDRCxJQUNFLElBQUksQ0FBQyxjQUFjLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhO2VBQzdDLENBQUMsSUFBSSxDQUFDLDhCQUE4QixFQUFFLEVBQ3pDLENBQUM7WUFDRCxJQUFJLENBQUMsY0FBYyxDQUNqQixRQUFRLEVBQ1Isc0VBQXNFLENBQ3ZFLENBQUM7WUFDRixPQUFPO1FBQ1QsQ0FBQztRQUNELElBQUksUUFBUSxDQUFDLE1BQU07WUFBRSxPQUFPO1FBQzVCLE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDOUIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDekMsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNyQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUNsQixRQUFRLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDNUQsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFTyxlQUFlLENBQ3JCLFFBQXNDLEVBQ3RDLE1BQWM7UUFFZCxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsU0FBUztZQUFFLE9BQU87UUFDdkIsWUFBWSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoQyxRQUFRLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVPLDhCQUE4QjtRQUNwQyxJQUFJLGVBQXlELENBQUM7UUFDOUQsOEVBQThFO1FBQzlFLEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3pDLElBQ0UsS0FBSyxDQUFDLE1BQU07bUJBQ1QsS0FBSyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEtBQUssQ0FBQzttQkFDM0IsQ0FDRCxlQUFlO3VCQUNaLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLGVBQWUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUM1RDtnQkFDRCxTQUFTO1lBQ1gsZUFBZSxHQUFHLEtBQUssQ0FBQztRQUMxQixDQUFDO1FBQ0QsSUFBSSxDQUFDLGVBQWU7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUNuQyxJQUFJLENBQUMsY0FBYyxDQUNqQixlQUFlLEVBQ2Ysc0VBQXNFLENBQ3ZFLENBQUM7UUFDRixPQUFPLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUM7SUFDekQsQ0FBQztJQUVPLGNBQWMsQ0FDcEIsUUFBc0MsRUFDdEMsU0FBaUI7UUFFakIsSUFBSSxRQUFRLENBQUMsTUFBTTtZQUFFLE9BQU87UUFDNUIsSUFBSSxDQUFDO1lBQ0gsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDcEMsQ0FBQztnQkFBUyxDQUFDO1lBQ1QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQzFFLENBQUM7SUFDSCxDQUFDO0lBRU8sU0FBUyxDQUFDLFdBQXlDO1FBQ3pELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUNwQixXQUFXLENBQUMsTUFBTTtZQUNsQixXQUFXLENBQUMsYUFBYTtZQUN6QixXQUFXLENBQUMsaUJBQWlCO1NBQzlCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxlQUFlLENBQ3JCLFFBQXNDLEVBQ3RDLFdBQXlDO1FBRXpDLE1BQU0sTUFBTSxHQUFHO1lBQ2IsV0FBVyxDQUFDLE1BQU07WUFDbEIsV0FBVyxDQUFDLGFBQWE7WUFDekIsV0FBVyxDQUFDLGlCQUFpQjtTQUM5QixDQUFDO1FBQ0YsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUM1QixPQUFPLFFBQVEsS0FBSyxRQUFRO2VBQ3pCLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQztlQUNyQixJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxVQUFVLEdBQUcsR0FBRyxDQUN2RCxDQUFDLEVBQUUsQ0FBQztZQUNILElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLHdEQUF3RCxDQUFDLENBQUM7WUFDeEYsTUFBTSxJQUFJLEtBQUssQ0FBQyx3REFBd0QsQ0FBQyxDQUFDO1FBQzVFLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDckMsQ0FBQztDQUNGIn0=
@@ -2,6 +2,7 @@ import * as plugins from './plugins.js';
2
2
  import { VirtualStreamManager } from './classes.virtualstreammanager.js';
3
3
  export { toClientWebSocketCloseCode } from './helpers.websocket.js';
4
4
  export { TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS, TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS_PER_NAME, } from './classes.clienttagreconciler.js';
5
+ export { TYPEDSOCKET_REQUEST_CANCELLATION_METHOD, TYPEDSOCKET_REQUEST_CANCELLATION_PROTOCOL, } from './constants.virtualstream.js';
5
6
  import type { TTypedSocketDiagnosticEvent } from './interfaces.diagnostics.js';
6
7
  import type { ICreateVirtualStreamOptions, IVirtualStreamAuthorizationAdapter, TVirtualStreamDirection } from './interfaces.virtualstream.js';
7
8
  import type { ITypedSocketClientTagPolicy } from './classes.typedsockettagpolicymanager.js';
@@ -160,6 +161,7 @@ export declare class TypedSocket {
160
161
  private unsubscribeSmartServeConnectionClose;
161
162
  private detachVirtualStreamResolvers;
162
163
  private detachIncomingRequestAuthorityGuards;
164
+ private detachIncomingRequestSignalResolvers;
163
165
  private detachResponseAuthorityGuards;
164
166
  private pendingServerRequests;
165
167
  private pendingServerRequestIdsByPeer;
@@ -168,6 +170,7 @@ export declare class TypedSocket {
168
170
  private readonly serverReadyCallbackPeers;
169
171
  private readonly virtualStreamAuthorizationAdapter;
170
172
  private readonly tagPolicyManager;
173
+ private readonly requestCancellationManager;
171
174
  private constructor();
172
175
  /**
173
176
  * Attaches the SmartServe transport after server router composition.
@@ -192,6 +195,9 @@ export declare class TypedSocket {
192
195
  private isCurrentClientConnection;
193
196
  private failClientHandshake;
194
197
  private abortClientConnectionState;
198
+ private registerClientRequestSignal;
199
+ private handleClientCancellation;
200
+ private createClientCancellationContext;
195
201
  /**
196
202
  * Handles WebSocket disconnection
197
203
  */
@@ -231,7 +237,12 @@ export declare class TypedSocket {
231
237
  private sendRequest;
232
238
  private normalizeRequestTimeout;
233
239
  private requireClientOptions;
240
+ private sendClientCancellation;
234
241
  private cancelPendingServerRequestsForPeer;
242
+ private registerServerRequestSignal;
243
+ private handleServerCancellation;
244
+ private createServerCancellationContext;
245
+ private sendServerCancellation;
235
246
  private retainServerInterestRegistration;
236
247
  private authorizeIncomingServerResponse;
237
248
  private isAttachedServerPeer;