@the-open-engine/zeroshot 6.11.0 → 6.12.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 (76) hide show
  1. package/cli/commands/providers.js +13 -13
  2. package/cli/index.js +77 -35
  3. package/cli/lib/first-run.js +12 -11
  4. package/cli/lib/update-checker.js +517 -132
  5. package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -1
  6. package/lib/agent-cli-provider/adapters/opencode.js +3 -0
  7. package/lib/agent-cli-provider/adapters/opencode.js.map +1 -1
  8. package/lib/agent-cli-provider/types.d.ts +1 -0
  9. package/lib/agent-cli-provider/types.d.ts.map +1 -1
  10. package/lib/agent-cli-provider/types.js.map +1 -1
  11. package/lib/cluster/client.cjs +146 -0
  12. package/lib/cluster/client.d.ts +44 -0
  13. package/lib/cluster/client.mjs +141 -0
  14. package/lib/cluster/connection.cjs +382 -0
  15. package/lib/cluster/connection.d.ts +41 -0
  16. package/lib/cluster/connection.mjs +378 -0
  17. package/lib/cluster/errors.cjs +44 -0
  18. package/lib/cluster/errors.d.ts +23 -0
  19. package/lib/cluster/errors.mjs +32 -0
  20. package/lib/cluster/frames.cjs +49 -0
  21. package/lib/cluster/frames.d.ts +12 -0
  22. package/lib/cluster/frames.mjs +45 -0
  23. package/lib/cluster/generated/protocol-schema.cjs +5 -0
  24. package/lib/cluster/generated/protocol-schema.d.ts +1 -0
  25. package/lib/cluster/generated/protocol-schema.mjs +2 -0
  26. package/lib/cluster/generated/protocol.cjs +22 -0
  27. package/lib/cluster/generated/protocol.d.ts +781 -0
  28. package/lib/cluster/generated/protocol.mjs +19 -0
  29. package/lib/cluster/index.cjs +40 -0
  30. package/lib/cluster/index.d.ts +10 -0
  31. package/lib/cluster/index.mjs +6 -0
  32. package/lib/cluster/queue.cjs +71 -0
  33. package/lib/cluster/queue.d.ts +15 -0
  34. package/lib/cluster/queue.mjs +67 -0
  35. package/lib/cluster/socket.cjs +15 -0
  36. package/lib/cluster/socket.d.ts +11 -0
  37. package/lib/cluster/socket.mjs +12 -0
  38. package/lib/cluster/subscriptions.cjs +270 -0
  39. package/lib/cluster/subscriptions.d.ts +69 -0
  40. package/lib/cluster/subscriptions.mjs +264 -0
  41. package/lib/cluster/validators.cjs +46 -0
  42. package/lib/cluster/validators.d.ts +3 -0
  43. package/lib/cluster/validators.mjs +42 -0
  44. package/lib/settings.js +195 -23
  45. package/lib/setup-apply.js +45 -32
  46. package/lib/setup-undo.js +25 -16
  47. package/package.json +25 -3
  48. package/scripts/build-cluster.js +43 -0
  49. package/scripts/generate-cluster-types.js +203 -0
  50. package/scripts/release-dry-run.js +6 -6
  51. package/scripts/rust-distribution.js +933 -0
  52. package/src/agent/agent-hook-executor.js +14 -6
  53. package/src/agent/agent-lifecycle.js +25 -8
  54. package/src/agent/agent-task-executor.js +711 -139
  55. package/src/agent/output-reformatter.js +54 -41
  56. package/src/agent/pr-verification.js +11 -3
  57. package/src/agent/task-execution-handle.js +373 -0
  58. package/src/agent-cli-provider/adapters/opencode.ts +3 -0
  59. package/src/agent-cli-provider/types.ts +1 -0
  60. package/src/agent-wrapper.js +5 -2
  61. package/src/cluster/client.ts +199 -0
  62. package/src/cluster/connection.ts +300 -0
  63. package/src/cluster/errors.ts +32 -0
  64. package/src/cluster/frames.ts +44 -0
  65. package/src/cluster/generated/protocol-schema.ts +2 -0
  66. package/src/cluster/generated/protocol.ts +183 -0
  67. package/src/cluster/index.ts +38 -0
  68. package/src/cluster/queue.ts +84 -0
  69. package/src/cluster/socket.ts +31 -0
  70. package/src/cluster/subscriptions.ts +256 -0
  71. package/src/cluster/validators.ts +56 -0
  72. package/src/cluster/ws.d.ts +7 -0
  73. package/src/isolation-manager.js +16 -0
  74. package/src/issue-providers/jira-provider.js +1 -1
  75. package/src/issue-providers/linear-provider.js +4 -4
  76. package/task-lib/runner.js +3 -0
@@ -0,0 +1,378 @@
1
+ import { JSON_RPC_VERSION, MAX_FRAME_BYTES, SUBSCRIPTION_METHODS, UNARY_METHODS } from './generated/protocol.mjs';
2
+ import { ClusterConfigError, ClusterInternalError, ClusterProtocolError, ClusterRpcError, ClusterStateError, ClusterTimeoutError, ClusterTransportError, requestAbortError, } from './errors.mjs';
3
+ import { boundedFrameText, isRecord } from './frames.mjs';
4
+ import { BoundedQueue } from './queue.mjs';
5
+ import { addSocketListener } from './socket.mjs';
6
+ import { assertDefinition, assertMethodResult } from './validators.mjs';
7
+ if (!Object.prototype.hasOwnProperty.call(Symbol, 'asyncDispose')) {
8
+ Object.defineProperty(Symbol, 'asyncDispose', {
9
+ configurable: false, enumerable: false,
10
+ value: Symbol.for('Symbol.asyncDispose'), writable: false,
11
+ });
12
+ }
13
+ export const CONNECTION_TRANSITIONS = Object.freeze({
14
+ OPEN: Object.freeze(['CLOSING']),
15
+ CLOSING: Object.freeze(['CLOSED']),
16
+ CLOSED: Object.freeze([]),
17
+ });
18
+ export const PROTOCOL_DIAGNOSTIC_CAPACITY = 128;
19
+ function deferred() {
20
+ let resolve;
21
+ let reject;
22
+ const promise = new Promise((onResolve, onReject) => {
23
+ resolve = onResolve;
24
+ reject = onReject;
25
+ });
26
+ return { promise, resolve, reject };
27
+ }
28
+ export class Connection {
29
+ #state = 'OPEN';
30
+ #sequence = 1;
31
+ #pending = new Map();
32
+ #subscriptions = new Map();
33
+ #lateSubscriptionReapers = new Set();
34
+ #removeSocketListeners = [];
35
+ #ownedSubscriptions = new WeakSet();
36
+ #closePromise;
37
+ closeDiagnostics = [];
38
+ protocolDiagnostics = [];
39
+ #socket;
40
+ constructor(socket) {
41
+ if (socket.readyState !== 1)
42
+ throw new ClusterStateError('Connection requires an already-open WebSocket', 'SOCKET_NOT_OPEN');
43
+ this.#socket = socket;
44
+ this.#removeSocketListeners.push(addSocketListener(socket, 'message', (event) => this.#onMessage(event)), addSocketListener(socket, 'error', () => { void this.#startClose(false); }), addSocketListener(socket, 'close', () => { void this.#startClose(false); }));
45
+ }
46
+ get state() { return this.#state; }
47
+ get pendingSize() { return this.#pending.size; }
48
+ get subscriptionCount() { return this.#subscriptions.size; }
49
+ call(method, params, options = {}) {
50
+ if (!UNARY_METHODS.includes(method)) {
51
+ throw new ClusterConfigError(`${method} is a subscription method`, 'INVALID_METHOD');
52
+ }
53
+ return this.#dispatch(method, params, options);
54
+ }
55
+ cancelSubscription(registration) {
56
+ if (!this.#ownedSubscriptions.has(registration)) {
57
+ return Promise.reject(new ClusterStateError('subscription is not owned by this connection', 'UNOWNED_SUBSCRIPTION'));
58
+ }
59
+ if (registration.cancelSent)
60
+ return Promise.resolve();
61
+ registration.cancelSent = true;
62
+ return this.#sendNotification('subscription/cancel', { subscriptionId: registration.id });
63
+ }
64
+ openSubscription(method, params, options = {}) {
65
+ if (!SUBSCRIPTION_METHODS.includes(method)) {
66
+ throw new ClusterConfigError(`${method} is not a subscription method`, 'INVALID_METHOD');
67
+ }
68
+ return this.#dispatch(method, params, options, method);
69
+ }
70
+ unregisterSubscription(id, registration) {
71
+ if (this.#subscriptions.get(id) !== registration)
72
+ return;
73
+ this.#subscriptions.delete(id);
74
+ this.#disarmSubscriptionAbort(registration);
75
+ }
76
+ recordDiagnostic(error) { this.closeDiagnostics.push(error); }
77
+ close() { return this.#startClose(true); }
78
+ #dispatch(method, params, options, subscriptionKind) {
79
+ this.#requireOpen();
80
+ if (options.signal?.aborted)
81
+ return Promise.reject(requestAbortError(method));
82
+ if (options.requestTimeoutMs !== undefined && options.requestTimeoutMs < 0)
83
+ return Promise.reject(new ClusterConfigError('requestTimeoutMs must be non-negative', 'INVALID_TIMEOUT'));
84
+ const id = this.#allocateId();
85
+ const result = deferred();
86
+ const entry = { id, method, expectedId: id, resolve: result.resolve, reject: result.reject, settled: false, ...(subscriptionKind === undefined ? {} : { subscriptionKind }) };
87
+ this.#pending.set(id, entry);
88
+ if (options.signal) {
89
+ const onAbort = () => {
90
+ if (!this.#removeExact(id, entry))
91
+ return;
92
+ this.#settleEntry(entry);
93
+ if (entry.subscriptionKind)
94
+ this.#lateSubscriptionReapers.add(id);
95
+ entry.reject(requestAbortError(method));
96
+ void this.#sendNotification('$/cancelRequest', { id }).catch((error) => this.recordDiagnostic(error));
97
+ };
98
+ entry.signal = options.signal;
99
+ entry.abortHandler = onAbort;
100
+ options.signal.addEventListener('abort', onAbort, { once: true });
101
+ }
102
+ if (options.requestTimeoutMs !== undefined) {
103
+ entry.timeout = setTimeout(() => {
104
+ if (!this.#removeExact(id, entry))
105
+ return;
106
+ this.#settleEntry(entry);
107
+ if (entry.subscriptionKind)
108
+ this.#lateSubscriptionReapers.add(id);
109
+ entry.reject(new ClusterTimeoutError(`${method} request timed out`, 'REQUEST_TIMEOUT'));
110
+ void this.#sendNotification('$/cancelRequest', { id }).catch((error) => this.recordDiagnostic(error));
111
+ }, options.requestTimeoutMs);
112
+ }
113
+ const request = { jsonrpc: JSON_RPC_VERSION, id, method, params };
114
+ void this.#sendFrame(request).catch((cause) => {
115
+ if (!this.#removeExact(id, entry))
116
+ return;
117
+ this.#settleEntry(entry);
118
+ entry.reject(new ClusterTransportError(`failed to send ${method}`, 'SEND_FAILED', { cause }));
119
+ });
120
+ return result.promise;
121
+ }
122
+ #allocateId() { return `z${this.#sequence++}`; }
123
+ #removeExact(id, entry) { if (this.#pending.get(id) !== entry)
124
+ return false; this.#pending.delete(id); return true; }
125
+ #settleEntry(entry) {
126
+ if (entry.settled)
127
+ return;
128
+ entry.settled = true;
129
+ if (entry.timeout !== undefined)
130
+ clearTimeout(entry.timeout);
131
+ if (entry.signal && entry.abortHandler)
132
+ entry.signal.removeEventListener('abort', entry.abortHandler);
133
+ }
134
+ #requireOpen() { if (this.#state !== 'OPEN')
135
+ throw new ClusterStateError(`connection is ${this.#state.toLowerCase()}`, `CONNECTION_${this.#state}`); }
136
+ async #sendFrame(value, allowClosing = false) {
137
+ if (this.#state === 'CLOSED' || (!allowClosing && this.#state !== 'OPEN'))
138
+ throw new ClusterStateError(`connection is ${this.#state.toLowerCase()}`, `CONNECTION_${this.#state}`);
139
+ const payload = JSON.stringify(value);
140
+ if (this.#socket.send.length >= 2) {
141
+ await new Promise((resolve, reject) => { try {
142
+ this.#socket.send(payload, (error) => error ? reject(error) : resolve());
143
+ }
144
+ catch (error) {
145
+ reject(error);
146
+ } });
147
+ return;
148
+ }
149
+ const sent = this.#socket.send(payload);
150
+ if (sent && typeof sent.then === 'function')
151
+ await sent;
152
+ }
153
+ #sendNotification(method, params) {
154
+ return this.#sendFrame({ jsonrpc: JSON_RPC_VERSION, method, params }, true);
155
+ }
156
+ #onMessage(event) {
157
+ if (this.#state !== 'OPEN')
158
+ return;
159
+ const inbound = boundedFrameText(event, MAX_FRAME_BYTES);
160
+ if (inbound.kind === 'unsupported') {
161
+ this.#recordProtocolError('WebSocket message is not text or bytes');
162
+ return;
163
+ }
164
+ if (inbound.kind === 'oversized') {
165
+ this.#recordProtocolError(`frame exceeds ${MAX_FRAME_BYTES} bytes`);
166
+ return;
167
+ }
168
+ const { text, bytes } = inbound;
169
+ let frame;
170
+ try {
171
+ frame = JSON.parse(text);
172
+ }
173
+ catch (cause) {
174
+ this.#recordProtocolError('invalid JSON frame', cause);
175
+ return;
176
+ }
177
+ if (!isRecord(frame)) {
178
+ this.#recordProtocolError('invalid JSON-RPC frame');
179
+ return;
180
+ }
181
+ if ('id' in frame) {
182
+ this.#routeResponse(frame);
183
+ return;
184
+ }
185
+ if (frame.jsonrpc !== JSON_RPC_VERSION) {
186
+ this.#recordProtocolError('invalid JSON-RPC frame');
187
+ return;
188
+ }
189
+ if (typeof frame.method === 'string' && isRecord(frame.params)) {
190
+ this.#routeNotification(frame.method, frame.params, frame, bytes);
191
+ return;
192
+ }
193
+ this.#recordProtocolError('unrecognized JSON-RPC frame');
194
+ }
195
+ #routeResponse(frame) {
196
+ if (typeof frame.id !== 'string') {
197
+ this.#recordProtocolError('response id is not a string');
198
+ return;
199
+ }
200
+ const entry = this.#pending.get(frame.id);
201
+ if (!entry) {
202
+ this.#reapLateSubscription(frame.id, frame.result);
203
+ return;
204
+ }
205
+ this.#removeExact(frame.id, entry);
206
+ this.#settleEntry(entry);
207
+ if (frame.id !== entry.expectedId || frame.jsonrpc !== JSON_RPC_VERSION) {
208
+ entry.reject(new ClusterProtocolError('response identity mismatch', 'INVALID_RESPONSE_IDENTITY'));
209
+ return;
210
+ }
211
+ if (isRecord(frame.error)) {
212
+ this.#routeRpcError(entry, frame.error);
213
+ return;
214
+ }
215
+ this.#routeSuccess(entry, frame);
216
+ }
217
+ #reapLateSubscription(id, result) {
218
+ if (!this.#lateSubscriptionReapers.delete(id) || !isRecord(result))
219
+ return;
220
+ if (typeof result.subscriptionId !== 'string')
221
+ return;
222
+ void this.#sendNotification('subscription/cancel', { subscriptionId: result.subscriptionId })
223
+ .catch((error) => this.recordDiagnostic(error));
224
+ }
225
+ #routeRpcError(entry, error) {
226
+ try {
227
+ assertDefinition('JsonRpcError', error);
228
+ }
229
+ catch (cause) {
230
+ entry.reject(cause);
231
+ return;
232
+ }
233
+ const data = isRecord(error.data) ? error.data : undefined;
234
+ entry.reject(new ClusterRpcError(error.code, error.message, data));
235
+ }
236
+ #routeSuccess(entry, frame) {
237
+ if (!('result' in frame)) {
238
+ entry.reject(new ClusterProtocolError('response has neither result nor error', 'INVALID_RESPONSE'));
239
+ return;
240
+ }
241
+ try {
242
+ assertMethodResult(entry.method, frame.result);
243
+ }
244
+ catch (error) {
245
+ if (entry.subscriptionKind && isRecord(frame.result) && typeof frame.result.subscriptionId === 'string') {
246
+ void this.#sendNotification('subscription/cancel', { subscriptionId: frame.result.subscriptionId })
247
+ .catch((cause) => this.recordDiagnostic(cause));
248
+ }
249
+ entry.reject(error);
250
+ return;
251
+ }
252
+ if (!entry.subscriptionKind) {
253
+ entry.resolve(frame.result);
254
+ return;
255
+ }
256
+ const result = frame.result;
257
+ const registration = {
258
+ id: result.subscriptionId, kind: entry.subscriptionKind,
259
+ queue: new BoundedQueue(), overflowed: false, cancelSent: false,
260
+ };
261
+ if (this.#subscriptions.has(registration.id)) {
262
+ entry.reject(new ClusterProtocolError('duplicate subscriptionId', 'DUPLICATE_SUBSCRIPTION'));
263
+ return;
264
+ }
265
+ this.#ownedSubscriptions.add(registration);
266
+ this.#subscriptions.set(registration.id, registration);
267
+ this.#armSubscriptionAbort(registration, entry.signal);
268
+ entry.resolve({ result, registration });
269
+ }
270
+ #armSubscriptionAbort(registration, signal) {
271
+ if (!signal)
272
+ return;
273
+ const onAbort = () => {
274
+ if (this.#subscriptions.get(registration.id) !== registration)
275
+ return;
276
+ this.unregisterSubscription(registration.id, registration);
277
+ registration.queue.closeAndDiscard();
278
+ void this.cancelSubscription(registration).catch((error) => this.recordDiagnostic(error));
279
+ };
280
+ registration.abortSignal = signal;
281
+ registration.abortHandler = onAbort;
282
+ signal.addEventListener('abort', onAbort, { once: true });
283
+ if (signal.aborted)
284
+ onAbort();
285
+ }
286
+ #disarmSubscriptionAbort(registration) {
287
+ if (registration.abortSignal && registration.abortHandler) {
288
+ registration.abortSignal.removeEventListener('abort', registration.abortHandler);
289
+ }
290
+ delete registration.abortSignal;
291
+ delete registration.abortHandler;
292
+ }
293
+ #routeNotification(method, params, frame, bytes) {
294
+ const subscriptionId = params.subscriptionId;
295
+ if (typeof subscriptionId !== 'string') {
296
+ this.#recordProtocolError('subscription notification has no subscriptionId');
297
+ return;
298
+ }
299
+ const registration = this.#subscriptions.get(subscriptionId);
300
+ if (!registration)
301
+ return;
302
+ const terminal = method === 'subscription/closed';
303
+ const outcome = registration.queue.push(frame, bytes);
304
+ if (outcome === 'overflow') {
305
+ registration.overflowed = true;
306
+ this.unregisterSubscription(subscriptionId, registration);
307
+ registration.queue.endRetainingBuffer();
308
+ if (!terminal)
309
+ void this.cancelSubscription(registration).catch((error) => this.recordDiagnostic(error));
310
+ return;
311
+ }
312
+ if (terminal) {
313
+ this.unregisterSubscription(subscriptionId, registration);
314
+ registration.queue.endRetainingBuffer();
315
+ }
316
+ }
317
+ #recordProtocolError(message, cause) {
318
+ if (this.protocolDiagnostics.length === PROTOCOL_DIAGNOSTIC_CAPACITY)
319
+ this.protocolDiagnostics.shift();
320
+ this.protocolDiagnostics.push(new ClusterProtocolError(message, 'INVALID_PEER_FRAME', cause === undefined ? undefined : { cause }));
321
+ }
322
+ #startClose(sendCancels) {
323
+ if (this.#closePromise)
324
+ return this.#closePromise;
325
+ if (this.#state === 'CLOSED')
326
+ return Promise.resolve();
327
+ this.#transition('CLOSING');
328
+ this.#closePromise = Promise.resolve().then(() => this.#finishClose(sendCancels));
329
+ return this.#closePromise;
330
+ }
331
+ async #finishClose(sendCancels) {
332
+ const subscriptions = [...this.#subscriptions.values()];
333
+ this.#subscriptions.clear();
334
+ for (const subscription of subscriptions) {
335
+ this.#disarmSubscriptionAbort(subscription);
336
+ subscription.queue.closeAndDiscard();
337
+ }
338
+ const pending = [...this.#pending.values()];
339
+ this.#pending.clear();
340
+ for (const entry of pending) {
341
+ this.#settleEntry(entry);
342
+ entry.reject(new ClusterTransportError('connection closed', 'CONNECTION_CLOSED'));
343
+ }
344
+ this.#lateSubscriptionReapers.clear();
345
+ if (sendCancels)
346
+ for (const subscription of subscriptions) {
347
+ try {
348
+ await this.cancelSubscription(subscription);
349
+ }
350
+ catch (error) {
351
+ this.recordDiagnostic(error);
352
+ }
353
+ }
354
+ try {
355
+ await this.#socket.close();
356
+ }
357
+ catch (error) {
358
+ this.recordDiagnostic(error);
359
+ }
360
+ for (const remove of this.#removeSocketListeners.splice(0)) {
361
+ try {
362
+ remove();
363
+ }
364
+ catch (error) {
365
+ this.recordDiagnostic(error);
366
+ }
367
+ }
368
+ this.#transition('CLOSED');
369
+ }
370
+ #transition(to) {
371
+ if (!CONNECTION_TRANSITIONS[this.#state].includes(to))
372
+ throw new ClusterInternalError(`illegal connection transition ${this.#state} -> ${to}`, 'ILLEGAL_STATE_TRANSITION');
373
+ this.#state = to;
374
+ }
375
+ }
376
+ Object.defineProperty(Connection.prototype, Symbol.asyncDispose, {
377
+ configurable: true, value: Connection.prototype.close,
378
+ });
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClusterRpcError = exports.ClusterTimeoutError = exports.ClusterTransportError = exports.ClusterProtocolError = exports.ClusterInternalError = exports.ClusterStateError = exports.ClusterConfigError = exports.ClusterError = void 0;
4
+ exports.requestAbortError = requestAbortError;
5
+ class ClusterError extends Error {
6
+ code;
7
+ constructor(message, code, options) {
8
+ super(message, options);
9
+ this.code = code;
10
+ this.name = new.target.name;
11
+ }
12
+ }
13
+ exports.ClusterError = ClusterError;
14
+ class ClusterConfigError extends ClusterError {
15
+ }
16
+ exports.ClusterConfigError = ClusterConfigError;
17
+ class ClusterStateError extends ClusterError {
18
+ }
19
+ exports.ClusterStateError = ClusterStateError;
20
+ class ClusterInternalError extends ClusterError {
21
+ }
22
+ exports.ClusterInternalError = ClusterInternalError;
23
+ class ClusterProtocolError extends ClusterError {
24
+ }
25
+ exports.ClusterProtocolError = ClusterProtocolError;
26
+ class ClusterTransportError extends ClusterError {
27
+ }
28
+ exports.ClusterTransportError = ClusterTransportError;
29
+ class ClusterTimeoutError extends ClusterError {
30
+ }
31
+ exports.ClusterTimeoutError = ClusterTimeoutError;
32
+ function requestAbortError(method) {
33
+ return new DOMException(`${method} aborted locally; the server may still have committed this request`, 'AbortError');
34
+ }
35
+ class ClusterRpcError extends ClusterError {
36
+ rpcCode;
37
+ data;
38
+ constructor(rpcCode, message, data) {
39
+ super(message, data?.code ?? String(rpcCode));
40
+ this.rpcCode = rpcCode;
41
+ this.data = data;
42
+ }
43
+ }
44
+ exports.ClusterRpcError = ClusterRpcError;
@@ -0,0 +1,23 @@
1
+ import type { DomainErrorData } from './generated/protocol.js';
2
+ export declare class ClusterError extends Error {
3
+ readonly code: string;
4
+ constructor(message: string, code: string, options?: ErrorOptions);
5
+ }
6
+ export declare class ClusterConfigError extends ClusterError {
7
+ }
8
+ export declare class ClusterStateError extends ClusterError {
9
+ }
10
+ export declare class ClusterInternalError extends ClusterError {
11
+ }
12
+ export declare class ClusterProtocolError extends ClusterError {
13
+ }
14
+ export declare class ClusterTransportError extends ClusterError {
15
+ }
16
+ export declare class ClusterTimeoutError extends ClusterError {
17
+ }
18
+ export declare function requestAbortError(method: string): DOMException;
19
+ export declare class ClusterRpcError extends ClusterError {
20
+ readonly rpcCode: number;
21
+ readonly data?: DomainErrorData | undefined;
22
+ constructor(rpcCode: number, message: string, data?: DomainErrorData | undefined);
23
+ }
@@ -0,0 +1,32 @@
1
+ export class ClusterError extends Error {
2
+ code;
3
+ constructor(message, code, options) {
4
+ super(message, options);
5
+ this.code = code;
6
+ this.name = new.target.name;
7
+ }
8
+ }
9
+ export class ClusterConfigError extends ClusterError {
10
+ }
11
+ export class ClusterStateError extends ClusterError {
12
+ }
13
+ export class ClusterInternalError extends ClusterError {
14
+ }
15
+ export class ClusterProtocolError extends ClusterError {
16
+ }
17
+ export class ClusterTransportError extends ClusterError {
18
+ }
19
+ export class ClusterTimeoutError extends ClusterError {
20
+ }
21
+ export function requestAbortError(method) {
22
+ return new DOMException(`${method} aborted locally; the server may still have committed this request`, 'AbortError');
23
+ }
24
+ export class ClusterRpcError extends ClusterError {
25
+ rpcCode;
26
+ data;
27
+ constructor(rpcCode, message, data) {
28
+ super(message, data?.code ?? String(rpcCode));
29
+ this.rpcCode = rpcCode;
30
+ this.data = data;
31
+ }
32
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.boundedFrameText = boundedFrameText;
4
+ exports.isRecord = isRecord;
5
+ function boundedUtf8Length(value, maximum) {
6
+ let bytes = 0;
7
+ for (let index = 0; index < value.length; index += 1) {
8
+ const codePoint = value.codePointAt(index);
9
+ if (codePoint === undefined)
10
+ break;
11
+ if (codePoint <= 0x7f)
12
+ bytes += 1;
13
+ else if (codePoint <= 0x7ff)
14
+ bytes += 2;
15
+ else if (codePoint <= 0xffff)
16
+ bytes += 3;
17
+ else {
18
+ bytes += 4;
19
+ index += 1;
20
+ }
21
+ if (bytes > maximum)
22
+ return undefined;
23
+ }
24
+ return bytes;
25
+ }
26
+ function boundedFrameText(event, maximum) {
27
+ const candidate = event && typeof event === 'object' && 'data' in event
28
+ ? event.data
29
+ : event;
30
+ if (typeof candidate === 'string') {
31
+ const bytes = boundedUtf8Length(candidate, maximum);
32
+ return bytes === undefined ? { kind: 'oversized' } : { kind: 'frame', text: candidate, bytes };
33
+ }
34
+ if (candidate instanceof ArrayBuffer) {
35
+ if (candidate.byteLength > maximum)
36
+ return { kind: 'oversized' };
37
+ return { kind: 'frame', text: new TextDecoder().decode(candidate), bytes: candidate.byteLength };
38
+ }
39
+ if (ArrayBuffer.isView(candidate)) {
40
+ if (candidate.byteLength > maximum)
41
+ return { kind: 'oversized' };
42
+ const view = new Uint8Array(candidate.buffer, candidate.byteOffset, candidate.byteLength);
43
+ return { kind: 'frame', text: new TextDecoder().decode(view), bytes: candidate.byteLength };
44
+ }
45
+ return { kind: 'unsupported' };
46
+ }
47
+ function isRecord(value) {
48
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
49
+ }
@@ -0,0 +1,12 @@
1
+ export type FrameRecord = Readonly<Record<string, unknown>>;
2
+ export type BoundedFrameText = {
3
+ readonly kind: 'frame';
4
+ readonly text: string;
5
+ readonly bytes: number;
6
+ } | {
7
+ readonly kind: 'oversized';
8
+ } | {
9
+ readonly kind: 'unsupported';
10
+ };
11
+ export declare function boundedFrameText(event: unknown, maximum: number): BoundedFrameText;
12
+ export declare function isRecord(value: unknown): value is FrameRecord;
@@ -0,0 +1,45 @@
1
+ function boundedUtf8Length(value, maximum) {
2
+ let bytes = 0;
3
+ for (let index = 0; index < value.length; index += 1) {
4
+ const codePoint = value.codePointAt(index);
5
+ if (codePoint === undefined)
6
+ break;
7
+ if (codePoint <= 0x7f)
8
+ bytes += 1;
9
+ else if (codePoint <= 0x7ff)
10
+ bytes += 2;
11
+ else if (codePoint <= 0xffff)
12
+ bytes += 3;
13
+ else {
14
+ bytes += 4;
15
+ index += 1;
16
+ }
17
+ if (bytes > maximum)
18
+ return undefined;
19
+ }
20
+ return bytes;
21
+ }
22
+ export function boundedFrameText(event, maximum) {
23
+ const candidate = event && typeof event === 'object' && 'data' in event
24
+ ? event.data
25
+ : event;
26
+ if (typeof candidate === 'string') {
27
+ const bytes = boundedUtf8Length(candidate, maximum);
28
+ return bytes === undefined ? { kind: 'oversized' } : { kind: 'frame', text: candidate, bytes };
29
+ }
30
+ if (candidate instanceof ArrayBuffer) {
31
+ if (candidate.byteLength > maximum)
32
+ return { kind: 'oversized' };
33
+ return { kind: 'frame', text: new TextDecoder().decode(candidate), bytes: candidate.byteLength };
34
+ }
35
+ if (ArrayBuffer.isView(candidate)) {
36
+ if (candidate.byteLength > maximum)
37
+ return { kind: 'oversized' };
38
+ const view = new Uint8Array(candidate.buffer, candidate.byteOffset, candidate.byteLength);
39
+ return { kind: 'frame', text: new TextDecoder().decode(view), bytes: candidate.byteLength };
40
+ }
41
+ return { kind: 'unsupported' };
42
+ }
43
+ export function isRecord(value) {
44
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
45
+ }