@replit/river 0.18.5 → 0.19.2

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 (48) hide show
  1. package/dist/{chunk-VH3NGOXQ.js → chunk-D5PVGZPQ.js} +5 -3
  2. package/dist/{chunk-K7CUSLWL.js → chunk-JH275HID.js} +1 -1
  3. package/dist/{chunk-WER2DWCP.js → chunk-NBE3D667.js} +0 -4
  4. package/dist/{chunk-6Q3MSICL.js → chunk-SR4DBLJ6.js} +11 -3
  5. package/dist/{chunk-UABIFWM7.js → chunk-YFPVQTWL.js} +220 -105
  6. package/dist/{chunk-PUX3U2SZ.js → chunk-ZWPEZS27.js} +1 -1
  7. package/dist/{connection-893bd769.d.ts → connection-aa0ea000.d.ts} +1 -1
  8. package/dist/{connection-89918b74.d.ts → connection-cfec12e6.d.ts} +1 -1
  9. package/dist/index-e2513701.d.ts +342 -0
  10. package/dist/logging/index.cjs +0 -4
  11. package/dist/logging/index.d.cts +2 -1
  12. package/dist/logging/index.d.ts +2 -1
  13. package/dist/logging/index.js +1 -1
  14. package/dist/router/index.cjs +11 -2
  15. package/dist/router/index.d.cts +7 -383
  16. package/dist/router/index.d.ts +7 -383
  17. package/dist/router/index.js +3 -3
  18. package/dist/services-4bba42d8.d.ts +736 -0
  19. package/dist/services-5fc5712d.d.ts +736 -0
  20. package/dist/transport/impls/uds/client.cjs +80 -53
  21. package/dist/transport/impls/uds/client.d.cts +5 -5
  22. package/dist/transport/impls/uds/client.d.ts +5 -5
  23. package/dist/transport/impls/uds/client.js +4 -4
  24. package/dist/transport/impls/uds/server.cjs +151 -62
  25. package/dist/transport/impls/uds/server.d.cts +4 -4
  26. package/dist/transport/impls/uds/server.d.ts +4 -4
  27. package/dist/transport/impls/uds/server.js +4 -4
  28. package/dist/transport/impls/ws/client.cjs +80 -53
  29. package/dist/transport/impls/ws/client.d.cts +3 -3
  30. package/dist/transport/impls/ws/client.d.ts +3 -3
  31. package/dist/transport/impls/ws/client.js +4 -4
  32. package/dist/transport/impls/ws/server.cjs +151 -62
  33. package/dist/transport/impls/ws/server.d.cts +4 -4
  34. package/dist/transport/impls/ws/server.d.ts +4 -4
  35. package/dist/transport/impls/ws/server.js +4 -4
  36. package/dist/transport/index.cjs +188 -71
  37. package/dist/transport/index.d.cts +295 -3
  38. package/dist/transport/index.d.ts +295 -3
  39. package/dist/transport/index.js +3 -4
  40. package/dist/util/testHelpers.cjs +410 -401
  41. package/dist/util/testHelpers.d.cts +3 -3
  42. package/dist/util/testHelpers.d.ts +3 -3
  43. package/dist/util/testHelpers.js +4 -5
  44. package/package.json +1 -1
  45. package/dist/chunk-RPIDSIQG.js +0 -0
  46. package/dist/index-46ed19d8.d.ts +0 -111
  47. package/dist/index-d412ca83.d.ts +0 -420
  48. package/dist/procedures-bfffcb0b.d.ts +0 -324
@@ -49,420 +49,107 @@ module.exports = __toCommonJS(testHelpers_exports);
49
49
  var import_isomorphic_ws = __toESM(require("isomorphic-ws"), 1);
50
50
  var import_ws = require("ws");
51
51
 
52
- // transport/transport.ts
53
- var import_value = require("@sinclair/typebox/value");
54
-
55
- // logging/log.ts
56
- var log = void 0;
52
+ // node_modules/p-defer/index.js
53
+ function pDefer() {
54
+ const deferred = {};
55
+ deferred.promise = new Promise((resolve, reject) => {
56
+ deferred.resolve = resolve;
57
+ deferred.reject = reject;
58
+ });
59
+ return deferred;
60
+ }
57
61
 
58
- // transport/session.ts
59
- var import_nanoid = require("nanoid");
60
- var nanoid = (0, import_nanoid.customAlphabet)("1234567890abcdefghijklmnopqrstuvxyz", 6);
61
- var unsafeId = () => nanoid();
62
- var Session = class {
63
- codec;
64
- options;
65
- /**
66
- * The buffer of messages that have been sent but not yet acknowledged.
67
- */
68
- sendBuffer = [];
69
- /**
70
- * The active connection associated with this session
71
- */
72
- connection;
73
- from;
74
- to;
75
- /**
76
- * The unique ID of this session.
77
- */
78
- id;
79
- /**
80
- * What the other side advertised as their session ID
81
- * for this session.
82
- */
83
- advertisedSessionId;
84
- /**
85
- * Number of messages we've sent along this session (excluding handshake and acks)
86
- */
87
- seq = 0;
88
- /**
89
- * Number of unique messages we've received this session (excluding handshake and acks)
90
- */
91
- ack = 0;
92
- /**
93
- * The grace period between when the inner connection is disconnected
94
- * and when we should consider the entire session disconnected.
95
- */
96
- disconnectionGrace;
97
- /**
98
- * Number of heartbeats we've sent without a response.
99
- */
100
- heartbeatMisses;
101
- /**
102
- * The interval for sending heartbeats.
103
- */
104
- heartbeat;
105
- constructor(conn, from, to, options) {
106
- this.id = `session-${nanoid(12)}`;
107
- this.options = options;
108
- this.from = from;
109
- this.to = to;
110
- this.connection = conn;
111
- this.codec = options.codec;
112
- this.heartbeatMisses = 0;
113
- this.heartbeat = setInterval(
114
- () => this.sendHeartbeat(),
115
- options.heartbeatIntervalMs
116
- );
117
- }
118
- get loggingMetadata() {
119
- return {
120
- clientId: this.from,
121
- connectedTo: this.to,
122
- sessionId: this.id,
123
- connId: this.connection?.debugId
124
- };
62
+ // node_modules/it-pushable/dist/src/fifo.js
63
+ var FixedFIFO = class {
64
+ buffer;
65
+ mask;
66
+ top;
67
+ btm;
68
+ next;
69
+ constructor(hwm) {
70
+ if (!(hwm > 0) || (hwm - 1 & hwm) !== 0) {
71
+ throw new Error("Max size for a FixedFIFO should be a power of two");
72
+ }
73
+ this.buffer = new Array(hwm);
74
+ this.mask = hwm - 1;
75
+ this.top = 0;
76
+ this.btm = 0;
77
+ this.next = null;
125
78
  }
126
- /**
127
- * Sends a message over the session's connection.
128
- * If the connection is not ready or the message fails to send, the message can be buffered for retry unless skipped.
129
- *
130
- * @param msg The partial message to be sent, which will be constructed into a full message.
131
- * @param addToSendBuff Whether to add the message to the send buffer for retry.
132
- * @returns The full transport ID of the message that was attempted to be sent.
133
- */
134
- send(msg) {
135
- const fullMsg = this.constructMsg(msg);
136
- log?.debug(`sending msg`, {
137
- ...this.loggingMetadata,
138
- fullTransportMessage: fullMsg
139
- });
140
- if (this.connection) {
141
- const ok = this.connection.send(this.codec.toBuffer(fullMsg));
142
- if (ok)
143
- return fullMsg.id;
144
- log?.info(
145
- `failed to send msg to ${fullMsg.to}, connection is probably dead`,
146
- {
147
- ...this.loggingMetadata,
148
- fullTransportMessage: fullMsg
149
- }
150
- );
151
- } else {
152
- log?.info(
153
- `failed to send msg to ${fullMsg.to}, connection not ready yet`,
154
- { ...this.loggingMetadata, fullTransportMessage: fullMsg }
155
- );
79
+ push(data) {
80
+ if (this.buffer[this.top] !== void 0) {
81
+ return false;
156
82
  }
157
- return fullMsg.id;
83
+ this.buffer[this.top] = data;
84
+ this.top = this.top + 1 & this.mask;
85
+ return true;
158
86
  }
159
- sendHeartbeat() {
160
- const misses = this.heartbeatMisses;
161
- const missDuration = misses * this.options.heartbeatIntervalMs;
162
- if (misses > this.options.heartbeatsUntilDead) {
163
- if (this.connection) {
164
- log?.info(
165
- `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
166
- this.loggingMetadata
167
- );
168
- this.closeStaleConnection();
169
- }
170
- return;
87
+ shift() {
88
+ const last = this.buffer[this.btm];
89
+ if (last === void 0) {
90
+ return void 0;
171
91
  }
172
- this.send({
173
- streamId: "heartbeat",
174
- controlFlags: 1 /* AckBit */,
175
- payload: {
176
- type: "ACK"
177
- }
178
- });
179
- this.heartbeatMisses++;
92
+ this.buffer[this.btm] = void 0;
93
+ this.btm = this.btm + 1 & this.mask;
94
+ return last;
180
95
  }
181
- resetBufferedMessages() {
182
- this.sendBuffer = [];
183
- this.seq = 0;
184
- this.ack = 0;
96
+ isEmpty() {
97
+ return this.buffer[this.btm] === void 0;
98
+ }
99
+ };
100
+ var FIFO = class {
101
+ size;
102
+ hwm;
103
+ head;
104
+ tail;
105
+ constructor(options = {}) {
106
+ this.hwm = options.splitLimit ?? 16;
107
+ this.head = new FixedFIFO(this.hwm);
108
+ this.tail = this.head;
109
+ this.size = 0;
185
110
  }
186
- sendBufferedMessages() {
187
- if (!this.connection) {
188
- const msg = `tried sending buffered messages without a connection (if you hit this code path something is seriously wrong)`;
189
- log?.error(msg, this.loggingMetadata);
190
- throw new Error(msg);
111
+ calculateSize(obj) {
112
+ if (obj?.byteLength != null) {
113
+ return obj.byteLength;
191
114
  }
192
- log?.info(
193
- `resending ${this.sendBuffer.length} buffered messages`,
194
- this.loggingMetadata
195
- );
196
- for (const msg of this.sendBuffer) {
197
- log?.debug(`resending msg`, {
198
- ...this.loggingMetadata,
199
- fullTransportMessage: msg
200
- });
201
- const ok = this.connection.send(this.codec.toBuffer(msg));
202
- if (!ok) {
203
- const errMsg = `failed to send buffered message to ${this.to} (if you hit this code path something is seriously wrong)`;
204
- log?.error(errMsg, {
205
- ...this.loggingMetadata,
206
- fullTransportMessage: msg
207
- });
208
- throw new Error(errMsg);
209
- }
115
+ return 1;
116
+ }
117
+ push(val) {
118
+ if (val?.value != null) {
119
+ this.size += this.calculateSize(val.value);
120
+ }
121
+ if (!this.head.push(val)) {
122
+ const prev = this.head;
123
+ this.head = prev.next = new FixedFIFO(2 * this.head.buffer.length);
124
+ this.head.push(val);
210
125
  }
211
126
  }
212
- updateBookkeeping(ack, seq) {
213
- if (seq + 1 < this.ack) {
214
- log?.error(
215
- `received stale seq ${seq} + 1 < ${this.ack}`,
216
- this.loggingMetadata
217
- );
218
- return;
127
+ shift() {
128
+ let val = this.tail.shift();
129
+ if (val === void 0 && this.tail.next != null) {
130
+ const next = this.tail.next;
131
+ this.tail.next = null;
132
+ this.tail = next;
133
+ val = this.tail.shift();
219
134
  }
220
- this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
221
- this.ack = seq + 1;
135
+ if (val?.value != null) {
136
+ this.size -= this.calculateSize(val.value);
137
+ }
138
+ return val;
222
139
  }
223
- closeStaleConnection(conn) {
224
- if (this.connection === void 0 || this.connection === conn)
225
- return;
226
- log?.info(
227
- `closing old inner connection from session to ${this.to}`,
228
- this.loggingMetadata
229
- );
230
- this.connection.close();
231
- this.connection = void 0;
140
+ isEmpty() {
141
+ return this.head.isEmpty();
232
142
  }
233
- replaceWithNewConnection(newConn) {
234
- this.closeStaleConnection(newConn);
235
- this.cancelGrace();
236
- this.connection = newConn;
237
- }
238
- beginGrace(cb) {
239
- log?.info(
240
- `starting ${this.options.sessionDisconnectGraceMs}ms grace period until session to ${this.to} is closed`,
241
- this.loggingMetadata
242
- );
243
- this.disconnectionGrace = setTimeout(() => {
244
- this.close();
245
- cb();
246
- }, this.options.sessionDisconnectGraceMs);
247
- }
248
- // called on reconnect of the underlying session
249
- cancelGrace() {
250
- this.heartbeatMisses = 0;
251
- clearTimeout(this.disconnectionGrace);
252
- this.disconnectionGrace = void 0;
253
- }
254
- // closed when we want to discard the whole session
255
- // (i.e. shutdown or session disconnect)
256
- close() {
257
- this.closeStaleConnection();
258
- this.cancelGrace();
259
- this.resetBufferedMessages();
260
- clearInterval(this.heartbeat);
261
- }
262
- get connected() {
263
- return this.connection !== void 0;
264
- }
265
- get nextExpectedSeq() {
266
- return this.ack;
267
- }
268
- constructMsg(partialMsg) {
269
- const msg = {
270
- ...partialMsg,
271
- id: unsafeId(),
272
- to: this.to,
273
- from: this.from,
274
- seq: this.seq,
275
- ack: this.ack
276
- };
277
- this.seq++;
278
- this.sendBuffer.push(msg);
279
- return msg;
280
- }
281
- inspectSendBuffer() {
282
- return this.sendBuffer;
283
- }
284
- };
285
-
286
- // util/stringify.ts
287
- function coerceErrorString(err) {
288
- if (err instanceof Error) {
289
- return err.message || "unknown reason";
290
- }
291
- return `[coerced to error] ${String(err)}`;
292
- }
293
-
294
- // codec/json.ts
295
- var encoder = new TextEncoder();
296
- var decoder = new TextDecoder();
297
- function uint8ArrayToBase64(uint8Array) {
298
- let binary = "";
299
- uint8Array.forEach((byte) => {
300
- binary += String.fromCharCode(byte);
301
- });
302
- return btoa(binary);
303
- }
304
- function base64ToUint8Array(base64) {
305
- const binaryString = atob(base64);
306
- const uint8Array = new Uint8Array(binaryString.length);
307
- for (let i = 0; i < binaryString.length; i++) {
308
- uint8Array[i] = binaryString.charCodeAt(i);
309
- }
310
- return uint8Array;
311
- }
312
- var NaiveJsonCodec = {
313
- toBuffer: (obj) => {
314
- return encoder.encode(
315
- JSON.stringify(obj, function replacer(key) {
316
- const val = this[key];
317
- if (val instanceof Uint8Array) {
318
- return { $t: uint8ArrayToBase64(val) };
319
- } else {
320
- return val;
321
- }
322
- })
323
- );
324
- },
325
- fromBuffer: (buff) => {
326
- try {
327
- const parsed = JSON.parse(
328
- decoder.decode(buff),
329
- function reviver(_key, val) {
330
- if (val?.$t) {
331
- return base64ToUint8Array(val.$t);
332
- } else {
333
- return val;
334
- }
335
- }
336
- );
337
- if (typeof parsed === "object")
338
- return parsed;
339
- return null;
340
- } catch {
341
- return null;
342
- }
343
- }
344
- };
345
-
346
- // transport/transport.ts
347
- var defaultTransportOptions = {
348
- heartbeatIntervalMs: 1e3,
349
- heartbeatsUntilDead: 2,
350
- sessionDisconnectGraceMs: 5e3,
351
- codec: NaiveJsonCodec
352
- };
353
- var defaultConnectionRetryOptions = {
354
- baseIntervalMs: 250,
355
- maxJitterMs: 200,
356
- maxBackoffMs: 32e3,
357
- attemptBudgetCapacity: 5,
358
- budgetRestoreIntervalMs: 200
359
- };
360
- var defaultClientTransportOptions = {
361
- ...defaultTransportOptions,
362
- ...defaultConnectionRetryOptions
363
- };
364
-
365
- // node_modules/p-defer/index.js
366
- function pDefer() {
367
- const deferred = {};
368
- deferred.promise = new Promise((resolve, reject) => {
369
- deferred.resolve = resolve;
370
- deferred.reject = reject;
371
- });
372
- return deferred;
373
- }
374
-
375
- // node_modules/it-pushable/dist/src/fifo.js
376
- var FixedFIFO = class {
377
- buffer;
378
- mask;
379
- top;
380
- btm;
381
- next;
382
- constructor(hwm) {
383
- if (!(hwm > 0) || (hwm - 1 & hwm) !== 0) {
384
- throw new Error("Max size for a FixedFIFO should be a power of two");
385
- }
386
- this.buffer = new Array(hwm);
387
- this.mask = hwm - 1;
388
- this.top = 0;
389
- this.btm = 0;
390
- this.next = null;
391
- }
392
- push(data) {
393
- if (this.buffer[this.top] !== void 0) {
394
- return false;
395
- }
396
- this.buffer[this.top] = data;
397
- this.top = this.top + 1 & this.mask;
398
- return true;
399
- }
400
- shift() {
401
- const last = this.buffer[this.btm];
402
- if (last === void 0) {
403
- return void 0;
404
- }
405
- this.buffer[this.btm] = void 0;
406
- this.btm = this.btm + 1 & this.mask;
407
- return last;
408
- }
409
- isEmpty() {
410
- return this.buffer[this.btm] === void 0;
411
- }
412
- };
413
- var FIFO = class {
414
- size;
415
- hwm;
416
- head;
417
- tail;
418
- constructor(options = {}) {
419
- this.hwm = options.splitLimit ?? 16;
420
- this.head = new FixedFIFO(this.hwm);
421
- this.tail = this.head;
422
- this.size = 0;
423
- }
424
- calculateSize(obj) {
425
- if (obj?.byteLength != null) {
426
- return obj.byteLength;
427
- }
428
- return 1;
429
- }
430
- push(val) {
431
- if (val?.value != null) {
432
- this.size += this.calculateSize(val.value);
433
- }
434
- if (!this.head.push(val)) {
435
- const prev = this.head;
436
- this.head = prev.next = new FixedFIFO(2 * this.head.buffer.length);
437
- this.head.push(val);
438
- }
439
- }
440
- shift() {
441
- let val = this.tail.shift();
442
- if (val === void 0 && this.tail.next != null) {
443
- const next = this.tail.next;
444
- this.tail.next = null;
445
- this.tail = next;
446
- val = this.tail.shift();
447
- }
448
- if (val?.value != null) {
449
- this.size -= this.calculateSize(val.value);
450
- }
451
- return val;
452
- }
453
- isEmpty() {
454
- return this.head.isEmpty();
455
- }
456
- };
457
-
458
- // node_modules/it-pushable/dist/src/index.js
459
- var AbortError = class extends Error {
460
- type;
461
- code;
462
- constructor(message, code) {
463
- super(message ?? "The operation was aborted");
464
- this.type = "aborted";
465
- this.code = code ?? "ABORT_ERR";
143
+ };
144
+
145
+ // node_modules/it-pushable/dist/src/index.js
146
+ var AbortError = class extends Error {
147
+ type;
148
+ code;
149
+ constructor(message, code) {
150
+ super(message ?? "The operation was aborted");
151
+ this.type = "aborted";
152
+ this.code = code ?? "ABORT_ERR";
466
153
  }
467
154
  };
468
155
  function pushable(options = {}) {
@@ -656,8 +343,330 @@ var RiverUncaughtSchema = import_typebox.Type.Object({
656
343
  message: import_typebox.Type.String()
657
344
  });
658
345
 
346
+ // logging/log.ts
347
+ var log = void 0;
348
+
349
+ // util/stringify.ts
350
+ function coerceErrorString(err) {
351
+ if (err instanceof Error) {
352
+ return err.message || "unknown reason";
353
+ }
354
+ return `[coerced to error] ${String(err)}`;
355
+ }
356
+
659
357
  // util/testHelpers.ts
660
358
  var import_nanoid2 = require("nanoid");
359
+
360
+ // transport/session.ts
361
+ var import_nanoid = require("nanoid");
362
+ var nanoid = (0, import_nanoid.customAlphabet)("1234567890abcdefghijklmnopqrstuvxyz", 6);
363
+ var unsafeId = () => nanoid();
364
+ var Session = class {
365
+ codec;
366
+ options;
367
+ /**
368
+ * The buffer of messages that have been sent but not yet acknowledged.
369
+ */
370
+ sendBuffer = [];
371
+ /**
372
+ * The active connection associated with this session
373
+ */
374
+ connection;
375
+ from;
376
+ to;
377
+ /**
378
+ * The unique ID of this session.
379
+ */
380
+ id;
381
+ /**
382
+ * What the other side advertised as their session ID
383
+ * for this session.
384
+ */
385
+ advertisedSessionId;
386
+ /**
387
+ * The metadata for this session, as parsed from the handshake.
388
+ *
389
+ * Will only ever be populated on the server side.
390
+ */
391
+ metadata;
392
+ /**
393
+ * Number of messages we've sent along this session (excluding handshake and acks)
394
+ */
395
+ seq = 0;
396
+ /**
397
+ * Number of unique messages we've received this session (excluding handshake and acks)
398
+ */
399
+ ack = 0;
400
+ /**
401
+ * The grace period between when the inner connection is disconnected
402
+ * and when we should consider the entire session disconnected.
403
+ */
404
+ disconnectionGrace;
405
+ /**
406
+ * Number of heartbeats we've sent without a response.
407
+ */
408
+ heartbeatMisses;
409
+ /**
410
+ * The interval for sending heartbeats.
411
+ */
412
+ heartbeat;
413
+ constructor(conn, from, to, options) {
414
+ this.id = `session-${nanoid(12)}`;
415
+ this.options = options;
416
+ this.from = from;
417
+ this.to = to;
418
+ this.connection = conn;
419
+ this.codec = options.codec;
420
+ this.heartbeatMisses = 0;
421
+ this.heartbeat = setInterval(
422
+ () => this.sendHeartbeat(),
423
+ options.heartbeatIntervalMs
424
+ );
425
+ }
426
+ get loggingMetadata() {
427
+ return {
428
+ clientId: this.from,
429
+ connectedTo: this.to,
430
+ sessionId: this.id,
431
+ connId: this.connection?.debugId
432
+ };
433
+ }
434
+ /**
435
+ * Sends a message over the session's connection.
436
+ * If the connection is not ready or the message fails to send, the message can be buffered for retry unless skipped.
437
+ *
438
+ * @param msg The partial message to be sent, which will be constructed into a full message.
439
+ * @param addToSendBuff Whether to add the message to the send buffer for retry.
440
+ * @returns The full transport ID of the message that was attempted to be sent.
441
+ */
442
+ send(msg) {
443
+ const fullMsg = this.constructMsg(msg);
444
+ log?.debug(`sending msg`, {
445
+ ...this.loggingMetadata,
446
+ fullTransportMessage: fullMsg
447
+ });
448
+ if (this.connection) {
449
+ const ok = this.connection.send(this.codec.toBuffer(fullMsg));
450
+ if (ok)
451
+ return fullMsg.id;
452
+ log?.info(
453
+ `failed to send msg to ${fullMsg.to}, connection is probably dead`,
454
+ {
455
+ ...this.loggingMetadata,
456
+ fullTransportMessage: fullMsg
457
+ }
458
+ );
459
+ } else {
460
+ log?.info(
461
+ `failed to send msg to ${fullMsg.to}, connection not ready yet`,
462
+ { ...this.loggingMetadata, fullTransportMessage: fullMsg }
463
+ );
464
+ }
465
+ return fullMsg.id;
466
+ }
467
+ sendHeartbeat() {
468
+ const misses = this.heartbeatMisses;
469
+ const missDuration = misses * this.options.heartbeatIntervalMs;
470
+ if (misses > this.options.heartbeatsUntilDead) {
471
+ if (this.connection) {
472
+ log?.info(
473
+ `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
474
+ this.loggingMetadata
475
+ );
476
+ this.closeStaleConnection();
477
+ }
478
+ return;
479
+ }
480
+ this.send({
481
+ streamId: "heartbeat",
482
+ controlFlags: 1 /* AckBit */,
483
+ payload: {
484
+ type: "ACK"
485
+ }
486
+ });
487
+ this.heartbeatMisses++;
488
+ }
489
+ resetBufferedMessages() {
490
+ this.sendBuffer = [];
491
+ this.seq = 0;
492
+ this.ack = 0;
493
+ }
494
+ sendBufferedMessages(conn) {
495
+ log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
496
+ ...this.loggingMetadata,
497
+ connId: conn.debugId
498
+ });
499
+ for (const msg of this.sendBuffer) {
500
+ log?.debug(`resending msg`, {
501
+ ...this.loggingMetadata,
502
+ fullTransportMessage: msg,
503
+ connId: conn.debugId
504
+ });
505
+ const ok = conn.send(this.codec.toBuffer(msg));
506
+ if (!ok) {
507
+ const errMsg = `failed to send buffered message to ${this.to} (sus, this is a fresh connection)`;
508
+ log?.error(errMsg, {
509
+ ...this.loggingMetadata,
510
+ fullTransportMessage: msg,
511
+ connId: conn.debugId
512
+ });
513
+ throw new Error(errMsg);
514
+ }
515
+ }
516
+ }
517
+ updateBookkeeping(ack, seq) {
518
+ if (seq + 1 < this.ack) {
519
+ log?.error(
520
+ `received stale seq ${seq} + 1 < ${this.ack}`,
521
+ this.loggingMetadata
522
+ );
523
+ return;
524
+ }
525
+ this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
526
+ this.ack = seq + 1;
527
+ }
528
+ closeStaleConnection(conn) {
529
+ if (this.connection === void 0 || this.connection === conn)
530
+ return;
531
+ log?.info(
532
+ `closing old inner connection from session to ${this.to}`,
533
+ this.loggingMetadata
534
+ );
535
+ this.connection.close();
536
+ this.connection = void 0;
537
+ }
538
+ replaceWithNewConnection(newConn) {
539
+ this.closeStaleConnection(newConn);
540
+ this.cancelGrace();
541
+ this.connection = newConn;
542
+ this.sendBufferedMessages(newConn);
543
+ }
544
+ beginGrace(cb) {
545
+ log?.info(
546
+ `starting ${this.options.sessionDisconnectGraceMs}ms grace period until session to ${this.to} is closed`,
547
+ this.loggingMetadata
548
+ );
549
+ this.disconnectionGrace = setTimeout(() => {
550
+ this.close();
551
+ cb();
552
+ }, this.options.sessionDisconnectGraceMs);
553
+ }
554
+ // called on reconnect of the underlying session
555
+ cancelGrace() {
556
+ this.heartbeatMisses = 0;
557
+ clearTimeout(this.disconnectionGrace);
558
+ this.disconnectionGrace = void 0;
559
+ }
560
+ // closed when we want to discard the whole session
561
+ // (i.e. shutdown or session disconnect)
562
+ close() {
563
+ this.closeStaleConnection();
564
+ this.cancelGrace();
565
+ this.resetBufferedMessages();
566
+ clearInterval(this.heartbeat);
567
+ }
568
+ get connected() {
569
+ return this.connection !== void 0;
570
+ }
571
+ get nextExpectedSeq() {
572
+ return this.ack;
573
+ }
574
+ constructMsg(partialMsg) {
575
+ const msg = {
576
+ ...partialMsg,
577
+ id: unsafeId(),
578
+ to: this.to,
579
+ from: this.from,
580
+ seq: this.seq,
581
+ ack: this.ack
582
+ };
583
+ this.seq++;
584
+ this.sendBuffer.push(msg);
585
+ return msg;
586
+ }
587
+ inspectSendBuffer() {
588
+ return this.sendBuffer;
589
+ }
590
+ };
591
+
592
+ // transport/transport.ts
593
+ var import_value = require("@sinclair/typebox/value");
594
+
595
+ // codec/json.ts
596
+ var encoder = new TextEncoder();
597
+ var decoder = new TextDecoder();
598
+ function uint8ArrayToBase64(uint8Array) {
599
+ let binary = "";
600
+ uint8Array.forEach((byte) => {
601
+ binary += String.fromCharCode(byte);
602
+ });
603
+ return btoa(binary);
604
+ }
605
+ function base64ToUint8Array(base64) {
606
+ const binaryString = atob(base64);
607
+ const uint8Array = new Uint8Array(binaryString.length);
608
+ for (let i = 0; i < binaryString.length; i++) {
609
+ uint8Array[i] = binaryString.charCodeAt(i);
610
+ }
611
+ return uint8Array;
612
+ }
613
+ var NaiveJsonCodec = {
614
+ toBuffer: (obj) => {
615
+ return encoder.encode(
616
+ JSON.stringify(obj, function replacer(key) {
617
+ const val = this[key];
618
+ if (val instanceof Uint8Array) {
619
+ return { $t: uint8ArrayToBase64(val) };
620
+ } else {
621
+ return val;
622
+ }
623
+ })
624
+ );
625
+ },
626
+ fromBuffer: (buff) => {
627
+ try {
628
+ const parsed = JSON.parse(
629
+ decoder.decode(buff),
630
+ function reviver(_key, val) {
631
+ if (val?.$t) {
632
+ return base64ToUint8Array(val.$t);
633
+ } else {
634
+ return val;
635
+ }
636
+ }
637
+ );
638
+ if (typeof parsed === "object")
639
+ return parsed;
640
+ return null;
641
+ } catch {
642
+ return null;
643
+ }
644
+ }
645
+ };
646
+
647
+ // transport/transport.ts
648
+ var defaultTransportOptions = {
649
+ heartbeatIntervalMs: 1e3,
650
+ heartbeatsUntilDead: 2,
651
+ sessionDisconnectGraceMs: 5e3,
652
+ codec: NaiveJsonCodec
653
+ };
654
+ var defaultConnectionRetryOptions = {
655
+ baseIntervalMs: 250,
656
+ maxJitterMs: 200,
657
+ maxBackoffMs: 32e3,
658
+ attemptBudgetCapacity: 5,
659
+ budgetRestoreIntervalMs: 200
660
+ };
661
+ var defaultClientTransportOptions = {
662
+ ...defaultTransportOptions,
663
+ ...defaultConnectionRetryOptions
664
+ };
665
+ var defaultServerTransportOptions = {
666
+ ...defaultTransportOptions
667
+ };
668
+
669
+ // util/testHelpers.ts
661
670
  function createWebSocketServer(server) {
662
671
  return new import_ws.WebSocketServer({ server });
663
672
  }