@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.
- package/dist/{chunk-VH3NGOXQ.js → chunk-D5PVGZPQ.js} +5 -3
- package/dist/{chunk-K7CUSLWL.js → chunk-JH275HID.js} +1 -1
- package/dist/{chunk-WER2DWCP.js → chunk-NBE3D667.js} +0 -4
- package/dist/{chunk-6Q3MSICL.js → chunk-SR4DBLJ6.js} +11 -3
- package/dist/{chunk-UABIFWM7.js → chunk-YFPVQTWL.js} +220 -105
- package/dist/{chunk-PUX3U2SZ.js → chunk-ZWPEZS27.js} +1 -1
- package/dist/{connection-893bd769.d.ts → connection-aa0ea000.d.ts} +1 -1
- package/dist/{connection-89918b74.d.ts → connection-cfec12e6.d.ts} +1 -1
- package/dist/index-e2513701.d.ts +342 -0
- package/dist/logging/index.cjs +0 -4
- package/dist/logging/index.d.cts +2 -1
- package/dist/logging/index.d.ts +2 -1
- package/dist/logging/index.js +1 -1
- package/dist/router/index.cjs +11 -2
- package/dist/router/index.d.cts +7 -383
- package/dist/router/index.d.ts +7 -383
- package/dist/router/index.js +3 -3
- package/dist/services-4bba42d8.d.ts +736 -0
- package/dist/services-5fc5712d.d.ts +736 -0
- package/dist/transport/impls/uds/client.cjs +80 -53
- package/dist/transport/impls/uds/client.d.cts +5 -5
- package/dist/transport/impls/uds/client.d.ts +5 -5
- package/dist/transport/impls/uds/client.js +4 -4
- package/dist/transport/impls/uds/server.cjs +151 -62
- package/dist/transport/impls/uds/server.d.cts +4 -4
- package/dist/transport/impls/uds/server.d.ts +4 -4
- package/dist/transport/impls/uds/server.js +4 -4
- package/dist/transport/impls/ws/client.cjs +80 -53
- package/dist/transport/impls/ws/client.d.cts +3 -3
- package/dist/transport/impls/ws/client.d.ts +3 -3
- package/dist/transport/impls/ws/client.js +4 -4
- package/dist/transport/impls/ws/server.cjs +151 -62
- package/dist/transport/impls/ws/server.d.cts +4 -4
- package/dist/transport/impls/ws/server.d.ts +4 -4
- package/dist/transport/impls/ws/server.js +4 -4
- package/dist/transport/index.cjs +188 -71
- package/dist/transport/index.d.cts +295 -3
- package/dist/transport/index.d.ts +295 -3
- package/dist/transport/index.js +3 -4
- package/dist/util/testHelpers.cjs +410 -401
- package/dist/util/testHelpers.d.cts +3 -3
- package/dist/util/testHelpers.d.ts +3 -3
- package/dist/util/testHelpers.js +4 -5
- package/package.json +1 -1
- package/dist/chunk-RPIDSIQG.js +0 -0
- package/dist/index-46ed19d8.d.ts +0 -111
- package/dist/index-d412ca83.d.ts +0 -420
- 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
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
//
|
|
59
|
-
var
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
128
|
-
|
|
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
|
-
|
|
83
|
+
this.buffer[this.top] = data;
|
|
84
|
+
this.top = this.top + 1 & this.mask;
|
|
85
|
+
return true;
|
|
158
86
|
}
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
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.
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
182
|
-
this.
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
187
|
-
if (
|
|
188
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
221
|
-
|
|
135
|
+
if (val?.value != null) {
|
|
136
|
+
this.size -= this.calculateSize(val.value);
|
|
137
|
+
}
|
|
138
|
+
return val;
|
|
222
139
|
}
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
}
|