@replit/river 0.200.0-rc.6 → 0.200.0-rc.7

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 (68) hide show
  1. package/README.md +2 -2
  2. package/dist/{chunk-TMNVRR5R.js → chunk-3XKJOFZA.js} +193 -90
  3. package/dist/chunk-3XKJOFZA.js.map +1 -0
  4. package/dist/{chunk-IGNFE3QW.js → chunk-BZBEE2VR.js} +2 -2
  5. package/dist/chunk-BZBEE2VR.js.map +1 -0
  6. package/dist/{chunk-WE2PAPNC.js → chunk-CXPZSAU4.js} +102 -95
  7. package/dist/chunk-CXPZSAU4.js.map +1 -0
  8. package/dist/{chunk-WF3AW2CB.js → chunk-F2E7ILHW.js} +41 -45
  9. package/dist/chunk-F2E7ILHW.js.map +1 -0
  10. package/dist/{chunk-NOLXEIRP.js → chunk-U4W75CMT.js} +3 -3
  11. package/dist/chunk-U4W75CMT.js.map +1 -0
  12. package/dist/{chunk-GXRIBO3N.js → chunk-VLW5OKZG.js} +2 -2
  13. package/dist/{chunk-MXU6DJVG.js → chunk-XIJVDPYY.js} +161 -159
  14. package/dist/chunk-XIJVDPYY.js.map +1 -0
  15. package/dist/{client-f56a6da3.d.ts → client-829bf1f9.d.ts} +3 -1
  16. package/dist/{connection-6031a354.d.ts → connection-5e67d641.d.ts} +1 -1
  17. package/dist/{context-73df8978.d.ts → context-9eabf54f.d.ts} +132 -81
  18. package/dist/router/index.cjs +162 -160
  19. package/dist/router/index.cjs.map +1 -1
  20. package/dist/router/index.d.cts +7 -7
  21. package/dist/router/index.d.ts +7 -7
  22. package/dist/router/index.js +6 -6
  23. package/dist/{server-9f31d98f.d.ts → server-d82a2d9b.d.ts} +8 -3
  24. package/dist/{services-69d72cd5.d.ts → services-6a446f04.d.ts} +157 -139
  25. package/dist/transport/impls/ws/client.cjs +285 -178
  26. package/dist/transport/impls/ws/client.cjs.map +1 -1
  27. package/dist/transport/impls/ws/client.d.cts +3 -3
  28. package/dist/transport/impls/ws/client.d.ts +3 -3
  29. package/dist/transport/impls/ws/client.js +7 -7
  30. package/dist/transport/impls/ws/server.cjs +224 -128
  31. package/dist/transport/impls/ws/server.cjs.map +1 -1
  32. package/dist/transport/impls/ws/server.d.cts +3 -3
  33. package/dist/transport/impls/ws/server.d.ts +3 -3
  34. package/dist/transport/impls/ws/server.js +5 -5
  35. package/dist/transport/index.cjs +322 -218
  36. package/dist/transport/index.cjs.map +1 -1
  37. package/dist/transport/index.d.cts +3 -3
  38. package/dist/transport/index.d.ts +3 -3
  39. package/dist/transport/index.js +7 -7
  40. package/dist/util/testHelpers.cjs +227 -133
  41. package/dist/util/testHelpers.cjs.map +1 -1
  42. package/dist/util/testHelpers.d.cts +15 -12
  43. package/dist/util/testHelpers.d.ts +15 -12
  44. package/dist/util/testHelpers.js +41 -43
  45. package/dist/util/testHelpers.js.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/chunk-IGNFE3QW.js.map +0 -1
  48. package/dist/chunk-MU25KVV7.js +0 -112
  49. package/dist/chunk-MU25KVV7.js.map +0 -1
  50. package/dist/chunk-MXU6DJVG.js.map +0 -1
  51. package/dist/chunk-NOLXEIRP.js.map +0 -1
  52. package/dist/chunk-TMNVRR5R.js.map +0 -1
  53. package/dist/chunk-WE2PAPNC.js.map +0 -1
  54. package/dist/chunk-WF3AW2CB.js.map +0 -1
  55. package/dist/connection-11991b13.d.ts +0 -31
  56. package/dist/transport/impls/uds/client.cjs +0 -1696
  57. package/dist/transport/impls/uds/client.cjs.map +0 -1
  58. package/dist/transport/impls/uds/client.d.cts +0 -18
  59. package/dist/transport/impls/uds/client.d.ts +0 -18
  60. package/dist/transport/impls/uds/client.js +0 -38
  61. package/dist/transport/impls/uds/client.js.map +0 -1
  62. package/dist/transport/impls/uds/server.cjs +0 -1663
  63. package/dist/transport/impls/uds/server.cjs.map +0 -1
  64. package/dist/transport/impls/uds/server.d.cts +0 -19
  65. package/dist/transport/impls/uds/server.d.ts +0 -19
  66. package/dist/transport/impls/uds/server.js +0 -33
  67. package/dist/transport/impls/uds/server.js.map +0 -1
  68. /package/dist/{chunk-GXRIBO3N.js.map → chunk-VLW5OKZG.js.map} +0 -0
@@ -1,1696 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // transport/impls/uds/client.ts
21
- var client_exports = {};
22
- __export(client_exports, {
23
- UnixDomainSocketClientTransport: () => UnixDomainSocketClientTransport
24
- });
25
- module.exports = __toCommonJS(client_exports);
26
- var import_node_net = require("net");
27
-
28
- // transport/transforms/messageFraming.ts
29
- var import_node_stream = require("stream");
30
- var Uint32LengthPrefixFraming = class extends import_node_stream.Transform {
31
- receivedBuffer;
32
- maxBufferSizeBytes;
33
- constructor({ maxBufferSizeBytes, ...options }) {
34
- super(options);
35
- this.maxBufferSizeBytes = maxBufferSizeBytes;
36
- this.receivedBuffer = Buffer.alloc(0);
37
- }
38
- _transform(chunk, _encoding, cb) {
39
- if (this.receivedBuffer.byteLength + chunk.byteLength > this.maxBufferSizeBytes) {
40
- const err = new Error(
41
- `buffer overflow: ${this.receivedBuffer.byteLength}B > ${this.maxBufferSizeBytes}B`
42
- );
43
- this.emit("error", err);
44
- cb(err);
45
- return;
46
- }
47
- this.receivedBuffer = Buffer.concat([this.receivedBuffer, chunk]);
48
- while (this.receivedBuffer.length > 4) {
49
- const claimedMessageLength = this.receivedBuffer.readUInt32BE(0) + 4;
50
- if (this.receivedBuffer.length >= claimedMessageLength) {
51
- const message = this.receivedBuffer.subarray(4, claimedMessageLength);
52
- this.push(message);
53
- this.receivedBuffer = this.receivedBuffer.subarray(claimedMessageLength);
54
- } else {
55
- break;
56
- }
57
- }
58
- cb();
59
- }
60
- _flush(cb) {
61
- if (this.receivedBuffer.length) {
62
- this.emit("error", new Error("got incomplete message while flushing"));
63
- }
64
- this.receivedBuffer = Buffer.alloc(0);
65
- cb();
66
- }
67
- _destroy(error, callback) {
68
- this.receivedBuffer = Buffer.alloc(0);
69
- super._destroy(error, callback);
70
- }
71
- };
72
- function createLengthEncodedStream(options) {
73
- return new Uint32LengthPrefixFraming({
74
- maxBufferSizeBytes: options?.maxBufferSizeBytes ?? 16 * 1024 * 1024
75
- // 16MB
76
- });
77
- }
78
- var MessageFramer = {
79
- createFramedStream: createLengthEncodedStream,
80
- write: (buf) => {
81
- const lengthPrefix = Buffer.alloc(4);
82
- lengthPrefix.writeUInt32BE(buf.length, 0);
83
- return Buffer.concat([lengthPrefix, buf]);
84
- }
85
- };
86
-
87
- // transport/id.ts
88
- var import_nanoid = require("nanoid");
89
- var alphabet = (0, import_nanoid.customAlphabet)(
90
- "1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
91
- );
92
- var generateId = () => alphabet(12);
93
-
94
- // transport/connection.ts
95
- var Connection = class {
96
- id;
97
- telemetry;
98
- constructor() {
99
- this.id = `conn-${generateId()}`;
100
- }
101
- get loggingMetadata() {
102
- const metadata = { connId: this.id };
103
- const spanContext = this.telemetry?.span.spanContext();
104
- if (this.telemetry?.span.isRecording() && spanContext) {
105
- metadata.telemetry = {
106
- traceId: spanContext.traceId,
107
- spanId: spanContext.spanId
108
- };
109
- }
110
- return metadata;
111
- }
112
- // can't use event emitter because we need this to work in both node + browser
113
- _dataListeners = /* @__PURE__ */ new Set();
114
- _closeListeners = /* @__PURE__ */ new Set();
115
- _errorListeners = /* @__PURE__ */ new Set();
116
- get dataListeners() {
117
- return [...this._dataListeners];
118
- }
119
- get closeListeners() {
120
- return [...this._closeListeners];
121
- }
122
- get errorListeners() {
123
- return [...this._errorListeners];
124
- }
125
- /**
126
- * Handle adding a callback for when a message is received.
127
- * @param msg The message that was received.
128
- */
129
- addDataListener(cb) {
130
- this._dataListeners.add(cb);
131
- }
132
- removeDataListener(cb) {
133
- this._dataListeners.delete(cb);
134
- }
135
- /**
136
- * Handle adding a callback for when the connection is closed.
137
- * This should also be called if an error happens and after notifying all the error listeners.
138
- * @param cb The callback to call when the connection is closed.
139
- */
140
- addCloseListener(cb) {
141
- this._closeListeners.add(cb);
142
- }
143
- removeCloseListener(cb) {
144
- this._closeListeners.delete(cb);
145
- }
146
- /**
147
- * Handle adding a callback for when an error is received.
148
- * This should only be used for this.logging errors, all cleanup
149
- * should be delegated to addCloseListener.
150
- *
151
- * The implementer should take care such that the implemented
152
- * connection will call both the close and error callbacks
153
- * on an error.
154
- *
155
- * @param cb The callback to call when an error is received.
156
- */
157
- addErrorListener(cb) {
158
- this._errorListeners.add(cb);
159
- }
160
- removeErrorListener(cb) {
161
- this._errorListeners.delete(cb);
162
- }
163
- };
164
-
165
- // transport/impls/uds/connection.ts
166
- var UdsConnection = class extends Connection {
167
- sock;
168
- input;
169
- framer;
170
- constructor(sock) {
171
- super();
172
- this.framer = MessageFramer.createFramedStream();
173
- this.sock = sock;
174
- this.input = sock.pipe(this.framer);
175
- this.sock.on("close", () => {
176
- for (const cb of this.closeListeners) {
177
- cb();
178
- }
179
- });
180
- this.sock.on("error", (err) => {
181
- if (err instanceof Error && "code" in err && err.code === "EPIPE") {
182
- return;
183
- }
184
- for (const cb of this.errorListeners) {
185
- cb(err);
186
- }
187
- });
188
- this.input.on("data", (msg) => {
189
- for (const cb of this.dataListeners) {
190
- cb(msg);
191
- }
192
- });
193
- this.sock.on("end", () => {
194
- this.sock.destroy();
195
- });
196
- }
197
- send(payload) {
198
- if (this.framer.destroyed || !this.sock.writable || this.sock.closed) {
199
- return false;
200
- }
201
- this.sock.write(MessageFramer.write(payload));
202
- return true;
203
- }
204
- close() {
205
- this.sock.end();
206
- this.framer.end();
207
- }
208
- };
209
-
210
- // transport/client.ts
211
- var import_api3 = require("@opentelemetry/api");
212
-
213
- // transport/message.ts
214
- var import_typebox = require("@sinclair/typebox");
215
- var TransportMessageSchema = (t) => import_typebox.Type.Object({
216
- id: import_typebox.Type.String(),
217
- from: import_typebox.Type.String(),
218
- to: import_typebox.Type.String(),
219
- seq: import_typebox.Type.Integer(),
220
- ack: import_typebox.Type.Integer(),
221
- serviceName: import_typebox.Type.Optional(import_typebox.Type.String()),
222
- procedureName: import_typebox.Type.Optional(import_typebox.Type.String()),
223
- streamId: import_typebox.Type.String(),
224
- controlFlags: import_typebox.Type.Integer(),
225
- tracing: import_typebox.Type.Optional(
226
- import_typebox.Type.Object({
227
- traceparent: import_typebox.Type.String(),
228
- tracestate: import_typebox.Type.String()
229
- })
230
- ),
231
- payload: t
232
- });
233
- var ControlMessageAckSchema = import_typebox.Type.Object({
234
- type: import_typebox.Type.Literal("ACK")
235
- });
236
- var ControlMessageCloseSchema = import_typebox.Type.Object({
237
- type: import_typebox.Type.Literal("CLOSE")
238
- });
239
- var currentProtocolVersion = "v2.0";
240
- var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
241
- type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
242
- protocolVersion: import_typebox.Type.String(),
243
- sessionId: import_typebox.Type.String(),
244
- /**
245
- * Specifies what the server's expected session state (from the pov of the client). This can be
246
- * used by the server to know whether this is a new or a reestablished connection, and whether it
247
- * is compatible with what it already has.
248
- */
249
- expectedSessionState: import_typebox.Type.Object({
250
- // what the client expects the server to send next
251
- nextExpectedSeq: import_typebox.Type.Integer(),
252
- // TODO: remove optional once we know all servers
253
- // are nextSentSeq here
254
- // what the server expects the client to send next
255
- nextSentSeq: import_typebox.Type.Optional(import_typebox.Type.Integer())
256
- }),
257
- metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
258
- });
259
- var HandshakeErrorRetriableResponseCodes = import_typebox.Type.Union([
260
- import_typebox.Type.Literal("SESSION_STATE_MISMATCH")
261
- ]);
262
- var HandshakeErrorFatalResponseCodes = import_typebox.Type.Union([
263
- import_typebox.Type.Literal("MALFORMED_HANDSHAKE_META"),
264
- import_typebox.Type.Literal("MALFORMED_HANDSHAKE"),
265
- import_typebox.Type.Literal("PROTOCOL_VERSION_MISMATCH"),
266
- import_typebox.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
267
- ]);
268
- var HandshakeErrorResponseCodes = import_typebox.Type.Union([
269
- HandshakeErrorRetriableResponseCodes,
270
- HandshakeErrorFatalResponseCodes
271
- ]);
272
- var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
273
- type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
274
- status: import_typebox.Type.Union([
275
- import_typebox.Type.Object({
276
- ok: import_typebox.Type.Literal(true),
277
- sessionId: import_typebox.Type.String()
278
- }),
279
- import_typebox.Type.Object({
280
- ok: import_typebox.Type.Literal(false),
281
- reason: import_typebox.Type.String(),
282
- // TODO: remove optional once we know all servers
283
- // are sending code here
284
- code: import_typebox.Type.Optional(HandshakeErrorResponseCodes)
285
- })
286
- ])
287
- });
288
- var ControlMessagePayloadSchema = import_typebox.Type.Union([
289
- ControlMessageCloseSchema,
290
- ControlMessageAckSchema,
291
- ControlMessageHandshakeRequestSchema,
292
- ControlMessageHandshakeResponseSchema
293
- ]);
294
- var OpaqueTransportMessageSchema = TransportMessageSchema(
295
- import_typebox.Type.Unknown()
296
- );
297
- function handshakeRequestMessage({
298
- from,
299
- to,
300
- sessionId,
301
- expectedSessionState,
302
- metadata,
303
- tracing
304
- }) {
305
- return {
306
- id: generateId(),
307
- from,
308
- to,
309
- seq: 0,
310
- ack: 0,
311
- streamId: generateId(),
312
- controlFlags: 0,
313
- tracing,
314
- payload: {
315
- type: "HANDSHAKE_REQ",
316
- protocolVersion: currentProtocolVersion,
317
- sessionId,
318
- expectedSessionState,
319
- metadata
320
- }
321
- };
322
- }
323
- function isAck(controlFlag) {
324
- return (controlFlag & 1 /* AckBit */) === 1 /* AckBit */;
325
- }
326
-
327
- // codec/json.ts
328
- var encoder = new TextEncoder();
329
- var decoder = new TextDecoder();
330
- function uint8ArrayToBase64(uint8Array) {
331
- let binary = "";
332
- uint8Array.forEach((byte) => {
333
- binary += String.fromCharCode(byte);
334
- });
335
- return btoa(binary);
336
- }
337
- function base64ToUint8Array(base64) {
338
- const binaryString = atob(base64);
339
- const uint8Array = new Uint8Array(binaryString.length);
340
- for (let i = 0; i < binaryString.length; i++) {
341
- uint8Array[i] = binaryString.charCodeAt(i);
342
- }
343
- return uint8Array;
344
- }
345
- var NaiveJsonCodec = {
346
- toBuffer: (obj) => {
347
- return encoder.encode(
348
- JSON.stringify(obj, function replacer(key) {
349
- const val = this[key];
350
- if (val instanceof Uint8Array) {
351
- return { $t: uint8ArrayToBase64(val) };
352
- } else {
353
- return val;
354
- }
355
- })
356
- );
357
- },
358
- fromBuffer: (buff) => {
359
- try {
360
- const parsed = JSON.parse(
361
- decoder.decode(buff),
362
- function reviver(_key, val) {
363
- if (val?.$t) {
364
- return base64ToUint8Array(val.$t);
365
- } else {
366
- return val;
367
- }
368
- }
369
- );
370
- if (typeof parsed === "object")
371
- return parsed;
372
- return null;
373
- } catch {
374
- return null;
375
- }
376
- }
377
- };
378
-
379
- // transport/options.ts
380
- var defaultTransportOptions = {
381
- heartbeatIntervalMs: 1e3,
382
- heartbeatsUntilDead: 2,
383
- sessionDisconnectGraceMs: 5e3,
384
- connectionTimeoutMs: 2e3,
385
- handshakeTimeoutMs: 1e3,
386
- codec: NaiveJsonCodec
387
- };
388
- var defaultConnectionRetryOptions = {
389
- baseIntervalMs: 250,
390
- maxJitterMs: 200,
391
- maxBackoffMs: 32e3,
392
- attemptBudgetCapacity: 5,
393
- budgetRestoreIntervalMs: 200
394
- };
395
- var defaultClientTransportOptions = {
396
- ...defaultTransportOptions,
397
- ...defaultConnectionRetryOptions
398
- };
399
- var defaultServerTransportOptions = {
400
- ...defaultTransportOptions
401
- };
402
-
403
- // transport/rateLimit.ts
404
- var LeakyBucketRateLimit = class {
405
- budgetConsumed;
406
- intervalHandles;
407
- options;
408
- constructor(options) {
409
- this.options = options;
410
- this.budgetConsumed = /* @__PURE__ */ new Map();
411
- this.intervalHandles = /* @__PURE__ */ new Map();
412
- }
413
- getBackoffMs(user) {
414
- if (!this.budgetConsumed.has(user))
415
- return 0;
416
- const exponent = Math.max(0, this.getBudgetConsumed(user) - 1);
417
- const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
418
- const backoffMs = Math.min(
419
- this.options.baseIntervalMs * 2 ** exponent,
420
- this.options.maxBackoffMs
421
- );
422
- return backoffMs + jitter;
423
- }
424
- get totalBudgetRestoreTime() {
425
- return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
426
- }
427
- consumeBudget(user) {
428
- this.stopLeak(user);
429
- this.budgetConsumed.set(user, this.getBudgetConsumed(user) + 1);
430
- }
431
- getBudgetConsumed(user) {
432
- return this.budgetConsumed.get(user) ?? 0;
433
- }
434
- hasBudget(user) {
435
- return this.getBudgetConsumed(user) < this.options.attemptBudgetCapacity;
436
- }
437
- startRestoringBudget(user) {
438
- if (this.intervalHandles.has(user)) {
439
- return;
440
- }
441
- const restoreBudgetForUser = () => {
442
- const currentBudget = this.budgetConsumed.get(user);
443
- if (!currentBudget) {
444
- this.stopLeak(user);
445
- return;
446
- }
447
- const newBudget = currentBudget - 1;
448
- if (newBudget === 0) {
449
- this.budgetConsumed.delete(user);
450
- return;
451
- }
452
- this.budgetConsumed.set(user, newBudget);
453
- };
454
- const intervalHandle = setInterval(
455
- restoreBudgetForUser,
456
- this.options.budgetRestoreIntervalMs
457
- );
458
- this.intervalHandles.set(user, intervalHandle);
459
- }
460
- stopLeak(user) {
461
- if (!this.intervalHandles.has(user)) {
462
- return;
463
- }
464
- clearInterval(this.intervalHandles.get(user));
465
- this.intervalHandles.delete(user);
466
- }
467
- close() {
468
- for (const user of this.intervalHandles.keys()) {
469
- this.stopLeak(user);
470
- }
471
- }
472
- };
473
-
474
- // logging/log.ts
475
- var LoggingLevels = {
476
- debug: -1,
477
- info: 0,
478
- warn: 1,
479
- error: 2
480
- };
481
- var cleanedLogFn = (log) => {
482
- return (msg, metadata) => {
483
- if (!metadata?.transportMessage) {
484
- log(msg, metadata);
485
- return;
486
- }
487
- const { payload, ...rest } = metadata.transportMessage;
488
- metadata.transportMessage = rest;
489
- log(msg, metadata);
490
- };
491
- };
492
- var BaseLogger = class {
493
- minLevel;
494
- output;
495
- constructor(output, minLevel = "info") {
496
- this.minLevel = minLevel;
497
- this.output = output;
498
- }
499
- debug(msg, metadata) {
500
- if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
501
- this.output(msg, metadata ?? {}, "debug");
502
- }
503
- }
504
- info(msg, metadata) {
505
- if (LoggingLevels[this.minLevel] <= LoggingLevels.info) {
506
- this.output(msg, metadata ?? {}, "info");
507
- }
508
- }
509
- warn(msg, metadata) {
510
- if (LoggingLevels[this.minLevel] <= LoggingLevels.warn) {
511
- this.output(msg, metadata ?? {}, "warn");
512
- }
513
- }
514
- error(msg, metadata) {
515
- if (LoggingLevels[this.minLevel] <= LoggingLevels.error) {
516
- this.output(msg, metadata ?? {}, "error");
517
- }
518
- }
519
- };
520
- var createLogProxy = (log) => ({
521
- debug: cleanedLogFn(log.debug.bind(log)),
522
- info: cleanedLogFn(log.info.bind(log)),
523
- warn: cleanedLogFn(log.warn.bind(log)),
524
- error: cleanedLogFn(log.error.bind(log))
525
- });
526
-
527
- // transport/events.ts
528
- var ProtocolError = {
529
- RetriesExceeded: "conn_retry_exceeded",
530
- HandshakeFailed: "handshake_failed",
531
- MessageOrderingViolated: "message_ordering_violated"
532
- };
533
- var EventDispatcher = class {
534
- eventListeners = {};
535
- removeAllListeners() {
536
- this.eventListeners = {};
537
- }
538
- numberOfListeners(eventType) {
539
- return this.eventListeners[eventType]?.size ?? 0;
540
- }
541
- addEventListener(eventType, handler) {
542
- if (!this.eventListeners[eventType]) {
543
- this.eventListeners[eventType] = /* @__PURE__ */ new Set();
544
- }
545
- this.eventListeners[eventType]?.add(handler);
546
- }
547
- removeEventListener(eventType, handler) {
548
- const handlers = this.eventListeners[eventType];
549
- if (handlers) {
550
- this.eventListeners[eventType]?.delete(handler);
551
- }
552
- }
553
- dispatchEvent(eventType, event) {
554
- const handlers = this.eventListeners[eventType];
555
- if (handlers) {
556
- const copy = [...handlers];
557
- for (const handler of copy) {
558
- handler(event);
559
- }
560
- }
561
- }
562
- };
563
-
564
- // transport/sessionStateMachine/common.ts
565
- var import_value = require("@sinclair/typebox/value");
566
- var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
567
- var StateMachineState = class {
568
- /*
569
- * Whether this state has been consumed
570
- * and we've moved on to another state
571
- */
572
- _isConsumed;
573
- close() {
574
- this._handleClose();
575
- }
576
- constructor() {
577
- this._isConsumed = false;
578
- return new Proxy(this, {
579
- get(target, prop) {
580
- if (prop === "_isConsumed" || prop === "id" || prop === "state") {
581
- return Reflect.get(target, prop);
582
- }
583
- if (prop === "_handleStateExit") {
584
- return () => {
585
- target._isConsumed = true;
586
- target._handleStateExit();
587
- };
588
- }
589
- if (prop === "_handleClose") {
590
- return () => {
591
- target._handleStateExit();
592
- target._handleClose();
593
- };
594
- }
595
- if (target._isConsumed) {
596
- throw new Error(
597
- `${ERR_CONSUMED}: getting ${prop.toString()} on consumed state`
598
- );
599
- }
600
- return Reflect.get(target, prop);
601
- },
602
- set(target, prop, value) {
603
- if (target._isConsumed) {
604
- throw new Error(
605
- `${ERR_CONSUMED}: setting ${prop.toString()} on consumed state`
606
- );
607
- }
608
- return Reflect.set(target, prop, value);
609
- }
610
- });
611
- }
612
- };
613
- var CommonSession = class extends StateMachineState {
614
- from;
615
- options;
616
- log;
617
- constructor(from, options, log) {
618
- super();
619
- this.from = from;
620
- this.options = options;
621
- this.log = log;
622
- }
623
- parseMsg(msg) {
624
- const parsedMsg = this.options.codec.fromBuffer(msg);
625
- if (parsedMsg === null) {
626
- const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));
627
- this.log?.error(
628
- `received malformed msg: ${decodedBuffer}`,
629
- this.loggingMetadata
630
- );
631
- return null;
632
- }
633
- if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
634
- this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
635
- ...this.loggingMetadata,
636
- validationErrors: [
637
- ...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
638
- ]
639
- });
640
- return null;
641
- }
642
- return parsedMsg;
643
- }
644
- };
645
- var IdentifiedSession = class extends CommonSession {
646
- id;
647
- telemetry;
648
- to;
649
- protocolVersion;
650
- /**
651
- * Index of the message we will send next (excluding handshake)
652
- */
653
- seq;
654
- /**
655
- * Number of unique messages we've received this session (excluding handshake)
656
- */
657
- ack;
658
- sendBuffer;
659
- constructor(id, from, to, seq, ack, sendBuffer, telemetry, options, protocolVersion, log) {
660
- super(from, options, log);
661
- this.id = id;
662
- this.to = to;
663
- this.seq = seq;
664
- this.ack = ack;
665
- this.sendBuffer = sendBuffer;
666
- this.telemetry = telemetry;
667
- this.log = log;
668
- this.protocolVersion = protocolVersion;
669
- }
670
- get loggingMetadata() {
671
- const spanContext = this.telemetry.span.spanContext();
672
- return {
673
- clientId: this.from,
674
- connectedTo: this.to,
675
- sessionId: this.id,
676
- telemetry: {
677
- traceId: spanContext.traceId,
678
- spanId: spanContext.spanId
679
- }
680
- };
681
- }
682
- constructMsg(partialMsg) {
683
- const msg = {
684
- ...partialMsg,
685
- id: generateId(),
686
- to: this.to,
687
- from: this.from,
688
- seq: this.seq,
689
- ack: this.ack
690
- };
691
- this.seq++;
692
- return msg;
693
- }
694
- nextSeq() {
695
- return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;
696
- }
697
- send(msg) {
698
- const constructedMsg = this.constructMsg(msg);
699
- this.sendBuffer.push(constructedMsg);
700
- return constructedMsg.id;
701
- }
702
- _handleStateExit() {
703
- }
704
- _handleClose() {
705
- this.sendBuffer.length = 0;
706
- this.telemetry.span.end();
707
- }
708
- };
709
-
710
- // transport/sessionStateMachine/SessionConnecting.ts
711
- var SessionConnecting = class extends IdentifiedSession {
712
- state = "Connecting" /* Connecting */;
713
- connPromise;
714
- listeners;
715
- connectionTimeout;
716
- constructor(connPromise, listeners, ...args) {
717
- super(...args);
718
- this.connPromise = connPromise;
719
- this.listeners = listeners;
720
- this.connectionTimeout = setTimeout(() => {
721
- listeners.onConnectionTimeout();
722
- }, this.options.connectionTimeoutMs);
723
- connPromise.then(
724
- (conn) => {
725
- if (this._isConsumed)
726
- return;
727
- listeners.onConnectionEstablished(conn);
728
- },
729
- (err) => {
730
- if (this._isConsumed)
731
- return;
732
- listeners.onConnectionFailed(err);
733
- }
734
- );
735
- }
736
- // close a pending connection if it resolves, ignore errors if the promise
737
- // ends up rejected anyways
738
- bestEffortClose() {
739
- void this.connPromise.then((conn) => conn.close()).catch(() => {
740
- });
741
- }
742
- _handleStateExit() {
743
- super._handleStateExit();
744
- clearTimeout(this.connectionTimeout);
745
- this.connectionTimeout = void 0;
746
- }
747
- _handleClose() {
748
- this.bestEffortClose();
749
- super._handleClose();
750
- }
751
- };
752
-
753
- // transport/sessionStateMachine/SessionNoConnection.ts
754
- var SessionNoConnection = class extends IdentifiedSession {
755
- state = "NoConnection" /* NoConnection */;
756
- listeners;
757
- gracePeriodTimeout;
758
- constructor(listeners, ...args) {
759
- super(...args);
760
- this.listeners = listeners;
761
- this.gracePeriodTimeout = setTimeout(() => {
762
- this.listeners.onSessionGracePeriodElapsed();
763
- }, this.options.sessionDisconnectGraceMs);
764
- }
765
- _handleClose() {
766
- super._handleClose();
767
- }
768
- _handleStateExit() {
769
- super._handleStateExit();
770
- if (this.gracePeriodTimeout) {
771
- clearTimeout(this.gracePeriodTimeout);
772
- this.gracePeriodTimeout = void 0;
773
- }
774
- }
775
- };
776
-
777
- // tracing/index.ts
778
- var import_api = require("@opentelemetry/api");
779
-
780
- // package.json
781
- var version = "0.200.0-rc.6";
782
-
783
- // tracing/index.ts
784
- function getPropagationContext(ctx) {
785
- const tracing = {
786
- traceparent: "",
787
- tracestate: ""
788
- };
789
- import_api.propagation.inject(ctx, tracing);
790
- return tracing;
791
- }
792
- function createSessionTelemetryInfo(sessionId, to, from, propagationCtx) {
793
- const parentCtx = propagationCtx ? import_api.propagation.extract(import_api.context.active(), propagationCtx) : import_api.context.active();
794
- const span = tracer.startSpan(
795
- `session ${sessionId}`,
796
- {
797
- attributes: {
798
- component: "river",
799
- "river.session.id": sessionId,
800
- "river.session.to": to,
801
- "river.session.from": from
802
- }
803
- },
804
- parentCtx
805
- );
806
- const ctx = import_api.trace.setSpan(parentCtx, span);
807
- return { span, ctx };
808
- }
809
- var tracer = import_api.trace.getTracer("river", version);
810
- var tracing_default = tracer;
811
-
812
- // transport/sessionStateMachine/SessionWaitingForHandshake.ts
813
- var SessionWaitingForHandshake = class extends CommonSession {
814
- state = "WaitingForHandshake" /* WaitingForHandshake */;
815
- conn;
816
- listeners;
817
- handshakeTimeout;
818
- constructor(conn, listeners, ...args) {
819
- super(...args);
820
- this.conn = conn;
821
- this.listeners = listeners;
822
- this.handshakeTimeout = setTimeout(() => {
823
- listeners.onHandshakeTimeout();
824
- }, this.options.handshakeTimeoutMs);
825
- this.conn.addDataListener(this.onHandshakeData);
826
- this.conn.addErrorListener(listeners.onConnectionErrored);
827
- this.conn.addCloseListener(listeners.onConnectionClosed);
828
- }
829
- onHandshakeData = (msg) => {
830
- const parsedMsg = this.parseMsg(msg);
831
- if (parsedMsg === null) {
832
- this.listeners.onInvalidHandshake("could not parse message");
833
- return;
834
- }
835
- this.listeners.onHandshake(parsedMsg);
836
- };
837
- get loggingMetadata() {
838
- return {
839
- clientId: this.from,
840
- connId: this.conn.id
841
- };
842
- }
843
- sendHandshake(msg) {
844
- return this.conn.send(this.options.codec.toBuffer(msg));
845
- }
846
- _handleStateExit() {
847
- this.conn.removeDataListener(this.onHandshakeData);
848
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
849
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
850
- clearTimeout(this.handshakeTimeout);
851
- this.handshakeTimeout = void 0;
852
- }
853
- _handleClose() {
854
- this.conn.close();
855
- }
856
- };
857
-
858
- // transport/sessionStateMachine/SessionHandshaking.ts
859
- var SessionHandshaking = class extends IdentifiedSession {
860
- state = "Handshaking" /* Handshaking */;
861
- conn;
862
- listeners;
863
- handshakeTimeout;
864
- constructor(conn, listeners, ...args) {
865
- super(...args);
866
- this.conn = conn;
867
- this.listeners = listeners;
868
- this.handshakeTimeout = setTimeout(() => {
869
- listeners.onHandshakeTimeout();
870
- }, this.options.handshakeTimeoutMs);
871
- this.conn.addDataListener(this.onHandshakeData);
872
- this.conn.addErrorListener(listeners.onConnectionErrored);
873
- this.conn.addCloseListener(listeners.onConnectionClosed);
874
- }
875
- onHandshakeData = (msg) => {
876
- const parsedMsg = this.parseMsg(msg);
877
- if (parsedMsg === null) {
878
- this.listeners.onInvalidHandshake("could not parse message");
879
- return;
880
- }
881
- this.listeners.onHandshake(parsedMsg);
882
- };
883
- sendHandshake(msg) {
884
- return this.conn.send(this.options.codec.toBuffer(msg));
885
- }
886
- _handleStateExit() {
887
- super._handleStateExit();
888
- this.conn.removeDataListener(this.onHandshakeData);
889
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
890
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
891
- clearTimeout(this.handshakeTimeout);
892
- }
893
- _handleClose() {
894
- super._handleClose();
895
- this.conn.close();
896
- }
897
- };
898
-
899
- // transport/sessionStateMachine/SessionConnected.ts
900
- var import_api2 = require("@opentelemetry/api");
901
- var SessionConnected = class extends IdentifiedSession {
902
- state = "Connected" /* Connected */;
903
- conn;
904
- listeners;
905
- heartbeatHandle;
906
- heartbeatMisses = 0;
907
- get isActivelyHeartbeating() {
908
- return this.heartbeatHandle !== void 0;
909
- }
910
- updateBookkeeping(ack, seq) {
911
- this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
912
- this.ack = seq + 1;
913
- this.heartbeatMisses = 0;
914
- }
915
- send(msg) {
916
- const constructedMsg = this.constructMsg(msg);
917
- this.sendBuffer.push(constructedMsg);
918
- this.conn.send(this.options.codec.toBuffer(constructedMsg));
919
- return constructedMsg.id;
920
- }
921
- constructor(conn, listeners, ...args) {
922
- super(...args);
923
- this.conn = conn;
924
- this.listeners = listeners;
925
- this.conn.addDataListener(this.onMessageData);
926
- this.conn.addCloseListener(listeners.onConnectionClosed);
927
- this.conn.addErrorListener(listeners.onConnectionErrored);
928
- if (this.sendBuffer.length > 0) {
929
- this.log?.debug(
930
- `sending ${this.sendBuffer.length} buffered messages`,
931
- this.loggingMetadata
932
- );
933
- }
934
- for (const msg of this.sendBuffer) {
935
- conn.send(this.options.codec.toBuffer(msg));
936
- }
937
- }
938
- startActiveHeartbeat() {
939
- this.heartbeatHandle = setInterval(() => {
940
- const misses = this.heartbeatMisses;
941
- const missDuration = misses * this.options.heartbeatIntervalMs;
942
- if (misses >= this.options.heartbeatsUntilDead) {
943
- this.log?.info(
944
- `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
945
- this.loggingMetadata
946
- );
947
- this.telemetry.span.addEvent("closing connection due to inactivity");
948
- this.conn.close();
949
- clearInterval(this.heartbeatHandle);
950
- this.heartbeatHandle = void 0;
951
- return;
952
- }
953
- this.sendHeartbeat();
954
- this.heartbeatMisses++;
955
- }, this.options.heartbeatIntervalMs);
956
- }
957
- sendHeartbeat() {
958
- this.send({
959
- streamId: "heartbeat",
960
- controlFlags: 1 /* AckBit */,
961
- payload: {
962
- type: "ACK"
963
- }
964
- });
965
- }
966
- onMessageData = (msg) => {
967
- const parsedMsg = this.parseMsg(msg);
968
- if (parsedMsg === null)
969
- return;
970
- if (parsedMsg.seq !== this.ack) {
971
- if (parsedMsg.seq < this.ack) {
972
- this.log?.debug(
973
- `received duplicate msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack}), discarding`,
974
- {
975
- ...this.loggingMetadata,
976
- transportMessage: parsedMsg
977
- }
978
- );
979
- } else {
980
- const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
981
- this.log?.error(reason, {
982
- ...this.loggingMetadata,
983
- transportMessage: parsedMsg,
984
- tags: ["invariant-violation"]
985
- });
986
- this.telemetry.span.setStatus({
987
- code: import_api2.SpanStatusCode.ERROR,
988
- message: reason
989
- });
990
- this.listeners.onInvalidMessage(reason);
991
- }
992
- return;
993
- }
994
- this.log?.debug(`received msg`, {
995
- ...this.loggingMetadata,
996
- transportMessage: parsedMsg
997
- });
998
- this.updateBookkeeping(parsedMsg.ack, parsedMsg.seq);
999
- if (!isAck(parsedMsg.controlFlags)) {
1000
- this.listeners.onMessage(parsedMsg);
1001
- return;
1002
- }
1003
- this.log?.debug(`discarding msg (ack bit set)`, {
1004
- ...this.loggingMetadata,
1005
- transportMessage: parsedMsg
1006
- });
1007
- if (!this.isActivelyHeartbeating) {
1008
- this.sendHeartbeat();
1009
- }
1010
- };
1011
- _handleStateExit() {
1012
- super._handleStateExit();
1013
- this.conn.removeDataListener(this.onMessageData);
1014
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
1015
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
1016
- clearInterval(this.heartbeatHandle);
1017
- this.heartbeatHandle = void 0;
1018
- }
1019
- _handleClose() {
1020
- super._handleClose();
1021
- this.conn.close();
1022
- }
1023
- };
1024
-
1025
- // transport/sessionStateMachine/transitions.ts
1026
- function inheritSharedSession(session) {
1027
- return [
1028
- session.id,
1029
- session.from,
1030
- session.to,
1031
- session.seq,
1032
- session.ack,
1033
- session.sendBuffer,
1034
- session.telemetry,
1035
- session.options,
1036
- session.protocolVersion,
1037
- session.log
1038
- ];
1039
- }
1040
- var SessionStateGraph = {
1041
- entrypoints: {
1042
- NoConnection(to, from, listeners, options, protocolVersion, log) {
1043
- const id = `session-${generateId()}`;
1044
- const telemetry = createSessionTelemetryInfo(id, to, from);
1045
- const sendBuffer = [];
1046
- const session = new SessionNoConnection(
1047
- listeners,
1048
- id,
1049
- from,
1050
- to,
1051
- 0,
1052
- 0,
1053
- sendBuffer,
1054
- telemetry,
1055
- options,
1056
- protocolVersion,
1057
- log
1058
- );
1059
- session.log?.info(`session ${session.id} created in NoConnection state`, {
1060
- ...session.loggingMetadata,
1061
- tags: ["state-transition"]
1062
- });
1063
- return session;
1064
- },
1065
- WaitingForHandshake(from, conn, listeners, options, log) {
1066
- const session = new SessionWaitingForHandshake(
1067
- conn,
1068
- listeners,
1069
- from,
1070
- options,
1071
- log
1072
- );
1073
- session.log?.info(`session created in WaitingForHandshake state`, {
1074
- ...session.loggingMetadata,
1075
- tags: ["state-transition"]
1076
- });
1077
- return session;
1078
- }
1079
- },
1080
- // All of the transitions 'move'/'consume' the old session and return a new one.
1081
- // After a session is transitioned, any usage of the old session will throw.
1082
- transition: {
1083
- // happy path transitions
1084
- NoConnectionToConnecting(oldSession, connPromise, listeners) {
1085
- const carriedState = inheritSharedSession(oldSession);
1086
- oldSession._handleStateExit();
1087
- const session = new SessionConnecting(
1088
- connPromise,
1089
- listeners,
1090
- ...carriedState
1091
- );
1092
- session.log?.info(
1093
- `session ${session.id} transition from NoConnection to Connecting`,
1094
- {
1095
- ...session.loggingMetadata,
1096
- tags: ["state-transition"]
1097
- }
1098
- );
1099
- return session;
1100
- },
1101
- ConnectingToHandshaking(oldSession, conn, listeners) {
1102
- const carriedState = inheritSharedSession(oldSession);
1103
- oldSession._handleStateExit();
1104
- const session = new SessionHandshaking(conn, listeners, ...carriedState);
1105
- session.log?.info(
1106
- `session ${session.id} transition from Connecting to Handshaking`,
1107
- {
1108
- ...session.loggingMetadata,
1109
- tags: ["state-transition"]
1110
- }
1111
- );
1112
- return session;
1113
- },
1114
- HandshakingToConnected(oldSession, listeners) {
1115
- const carriedState = inheritSharedSession(oldSession);
1116
- const conn = oldSession.conn;
1117
- oldSession._handleStateExit();
1118
- const session = new SessionConnected(conn, listeners, ...carriedState);
1119
- session.log?.info(
1120
- `session ${session.id} transition from Handshaking to Connected`,
1121
- {
1122
- ...session.loggingMetadata,
1123
- tags: ["state-transition"]
1124
- }
1125
- );
1126
- return session;
1127
- },
1128
- WaitingForHandshakeToConnected(pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) {
1129
- const conn = pendingSession.conn;
1130
- const { from, options } = pendingSession;
1131
- const carriedState = oldSession ? (
1132
- // old session exists, inherit state
1133
- inheritSharedSession(oldSession)
1134
- ) : (
1135
- // old session does not exist, create new state
1136
- [
1137
- sessionId,
1138
- from,
1139
- to,
1140
- 0,
1141
- 0,
1142
- [],
1143
- createSessionTelemetryInfo(sessionId, to, from, propagationCtx),
1144
- options,
1145
- protocolVersion,
1146
- pendingSession.log
1147
- ]
1148
- );
1149
- pendingSession._handleStateExit();
1150
- oldSession?._handleStateExit();
1151
- const session = new SessionConnected(conn, listeners, ...carriedState);
1152
- session.log?.info(
1153
- `session ${session.id} transition from WaitingForHandshake to Connected`,
1154
- {
1155
- ...session.loggingMetadata,
1156
- tags: ["state-transition"]
1157
- }
1158
- );
1159
- return session;
1160
- },
1161
- // disconnect paths
1162
- ConnectingToNoConnection(oldSession, listeners) {
1163
- const carriedState = inheritSharedSession(oldSession);
1164
- oldSession.bestEffortClose();
1165
- oldSession._handleStateExit();
1166
- const session = new SessionNoConnection(listeners, ...carriedState);
1167
- session.log?.info(
1168
- `session ${session.id} transition from Connecting to NoConnection`,
1169
- {
1170
- ...session.loggingMetadata,
1171
- tags: ["state-transition"]
1172
- }
1173
- );
1174
- return session;
1175
- },
1176
- HandshakingToNoConnection(oldSession, listeners) {
1177
- const carriedState = inheritSharedSession(oldSession);
1178
- oldSession.conn.close();
1179
- oldSession._handleStateExit();
1180
- const session = new SessionNoConnection(listeners, ...carriedState);
1181
- session.log?.info(
1182
- `session ${session.id} transition from Handshaking to NoConnection`,
1183
- {
1184
- ...session.loggingMetadata,
1185
- tags: ["state-transition"]
1186
- }
1187
- );
1188
- return session;
1189
- },
1190
- ConnectedToNoConnection(oldSession, listeners) {
1191
- const carriedState = inheritSharedSession(oldSession);
1192
- oldSession.conn.close();
1193
- oldSession._handleStateExit();
1194
- const session = new SessionNoConnection(listeners, ...carriedState);
1195
- session.log?.info(
1196
- `session ${session.id} transition from Connected to NoConnection`,
1197
- {
1198
- ...session.loggingMetadata,
1199
- tags: ["state-transition"]
1200
- }
1201
- );
1202
- return session;
1203
- }
1204
- }
1205
- };
1206
-
1207
- // transport/transport.ts
1208
- var Transport = class {
1209
- /**
1210
- * The status of the transport.
1211
- */
1212
- status;
1213
- /**
1214
- * The client ID of this transport.
1215
- */
1216
- clientId;
1217
- /**
1218
- * The event dispatcher for handling events of type EventTypes.
1219
- */
1220
- eventDispatcher;
1221
- /**
1222
- * The options for this transport.
1223
- */
1224
- options;
1225
- log;
1226
- sessions;
1227
- /**
1228
- * Creates a new Transport instance.
1229
- * @param codec The codec used to encode and decode messages.
1230
- * @param clientId The client ID of this transport.
1231
- */
1232
- constructor(clientId, providedOptions) {
1233
- this.options = { ...defaultTransportOptions, ...providedOptions };
1234
- this.eventDispatcher = new EventDispatcher();
1235
- this.clientId = clientId;
1236
- this.status = "open";
1237
- this.sessions = /* @__PURE__ */ new Map();
1238
- }
1239
- bindLogger(fn, level) {
1240
- if (typeof fn === "function") {
1241
- this.log = createLogProxy(new BaseLogger(fn, level));
1242
- return;
1243
- }
1244
- this.log = createLogProxy(fn);
1245
- }
1246
- /**
1247
- * Called when a message is received by this transport.
1248
- * You generally shouldn't need to override this in downstream transport implementations.
1249
- * @param msg The received message.
1250
- */
1251
- handleMsg(msg) {
1252
- if (this.getStatus() !== "open")
1253
- return;
1254
- this.eventDispatcher.dispatchEvent("message", msg);
1255
- }
1256
- /**
1257
- * Adds a listener to this transport.
1258
- * @param the type of event to listen for
1259
- * @param handler The message handler to add.
1260
- */
1261
- addEventListener(type, handler) {
1262
- this.eventDispatcher.addEventListener(type, handler);
1263
- }
1264
- /**
1265
- * Removes a listener from this transport.
1266
- * @param the type of event to un-listen on
1267
- * @param handler The message handler to remove.
1268
- */
1269
- removeEventListener(type, handler) {
1270
- this.eventDispatcher.removeEventListener(type, handler);
1271
- }
1272
- protocolError(type, message) {
1273
- this.eventDispatcher.dispatchEvent("protocolError", { type, message });
1274
- }
1275
- /**
1276
- * Default close implementation for transports. You should override this in the downstream
1277
- * implementation if you need to do any additional cleanup and call super.close() at the end.
1278
- * Closes the transport. Any messages sent while the transport is closed will be silently discarded.
1279
- */
1280
- close() {
1281
- this.status = "closed";
1282
- for (const session of this.sessions.values()) {
1283
- this.deleteSession(session);
1284
- }
1285
- this.eventDispatcher.dispatchEvent("transportStatus", {
1286
- status: this.status
1287
- });
1288
- this.eventDispatcher.removeAllListeners();
1289
- this.log?.info(`manually closed transport`, { clientId: this.clientId });
1290
- }
1291
- getStatus() {
1292
- return this.status;
1293
- }
1294
- updateSession(session) {
1295
- const activeSession = this.sessions.get(session.to);
1296
- if (activeSession && activeSession.id !== session.id) {
1297
- const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1298
- throw new Error(msg);
1299
- }
1300
- this.sessions.set(session.to, session);
1301
- if (!activeSession) {
1302
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1303
- status: "connect",
1304
- session
1305
- });
1306
- }
1307
- this.eventDispatcher.dispatchEvent("sessionTransition", {
1308
- state: session.state,
1309
- session
1310
- });
1311
- return session;
1312
- }
1313
- // state transitions
1314
- deleteSession(session) {
1315
- session.log?.info(`closing session ${session.id}`, session.loggingMetadata);
1316
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1317
- status: "disconnect",
1318
- session
1319
- });
1320
- session.close();
1321
- this.sessions.delete(session.to);
1322
- }
1323
- // common listeners
1324
- onSessionGracePeriodElapsed(session) {
1325
- this.log?.warn(
1326
- `session to ${session.to} grace period elapsed, closing`,
1327
- session.loggingMetadata
1328
- );
1329
- this.deleteSession(session);
1330
- }
1331
- onConnectingFailed(session) {
1332
- const noConnectionSession = SessionStateGraph.transition.ConnectingToNoConnection(session, {
1333
- onSessionGracePeriodElapsed: () => {
1334
- this.onSessionGracePeriodElapsed(noConnectionSession);
1335
- }
1336
- });
1337
- return this.updateSession(noConnectionSession);
1338
- }
1339
- onConnClosed(session) {
1340
- let noConnectionSession;
1341
- if (session.state === "Handshaking" /* Handshaking */) {
1342
- noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(session, {
1343
- onSessionGracePeriodElapsed: () => {
1344
- this.onSessionGracePeriodElapsed(noConnectionSession);
1345
- }
1346
- });
1347
- } else {
1348
- noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(session, {
1349
- onSessionGracePeriodElapsed: () => {
1350
- this.onSessionGracePeriodElapsed(noConnectionSession);
1351
- }
1352
- });
1353
- }
1354
- return this.updateSession(noConnectionSession);
1355
- }
1356
- };
1357
-
1358
- // util/stringify.ts
1359
- function coerceErrorString(err) {
1360
- if (err instanceof Error) {
1361
- return err.message || "unknown reason";
1362
- }
1363
- return `[coerced to error] ${String(err)}`;
1364
- }
1365
-
1366
- // transport/client.ts
1367
- var import_value2 = require("@sinclair/typebox/value");
1368
- var ClientTransport = class extends Transport {
1369
- /**
1370
- * The options for this transport.
1371
- */
1372
- options;
1373
- retryBudget;
1374
- /**
1375
- * A flag indicating whether the transport should automatically reconnect
1376
- * when a connection is dropped.
1377
- * Realistically, this should always be true for clients unless you are writing
1378
- * tests or a special case where you don't want to reconnect.
1379
- */
1380
- reconnectOnConnectionDrop = true;
1381
- /**
1382
- * Optional handshake options for this client.
1383
- */
1384
- handshakeExtensions;
1385
- constructor(clientId, providedOptions) {
1386
- super(clientId, providedOptions);
1387
- this.options = {
1388
- ...defaultClientTransportOptions,
1389
- ...providedOptions
1390
- };
1391
- this.retryBudget = new LeakyBucketRateLimit(this.options);
1392
- }
1393
- extendHandshake(options) {
1394
- this.handshakeExtensions = options;
1395
- }
1396
- tryReconnecting(to) {
1397
- if (this.reconnectOnConnectionDrop && this.getStatus() === "open") {
1398
- this.connect(to);
1399
- }
1400
- }
1401
- send(to, msg) {
1402
- if (this.getStatus() === "closed") {
1403
- const err = "transport is closed, cant send";
1404
- this.log?.error(err, {
1405
- clientId: this.clientId,
1406
- transportMessage: msg,
1407
- tags: ["invariant-violation"]
1408
- });
1409
- throw new Error(err);
1410
- }
1411
- let session = this.sessions.get(to);
1412
- if (!session) {
1413
- session = this.createUnconnectedSession(to);
1414
- }
1415
- return session.send(msg);
1416
- }
1417
- createUnconnectedSession(to) {
1418
- const session = SessionStateGraph.entrypoints.NoConnection(
1419
- to,
1420
- this.clientId,
1421
- {
1422
- onSessionGracePeriodElapsed: () => {
1423
- this.onSessionGracePeriodElapsed(session);
1424
- }
1425
- },
1426
- this.options,
1427
- currentProtocolVersion,
1428
- this.log
1429
- );
1430
- this.updateSession(session);
1431
- return session;
1432
- }
1433
- // listeners
1434
- onConnectingFailed(session) {
1435
- const noConnectionSession = super.onConnectingFailed(session);
1436
- this.tryReconnecting(noConnectionSession.to);
1437
- return noConnectionSession;
1438
- }
1439
- onConnClosed(session) {
1440
- const noConnectionSession = super.onConnClosed(session);
1441
- this.tryReconnecting(noConnectionSession.to);
1442
- return noConnectionSession;
1443
- }
1444
- onConnectionEstablished(session, conn) {
1445
- const handshakingSession = SessionStateGraph.transition.ConnectingToHandshaking(session, conn, {
1446
- onConnectionErrored: (err) => {
1447
- const errStr = coerceErrorString(err);
1448
- this.log?.error(
1449
- `connection to ${handshakingSession.to} errored during handshake: ${errStr}`,
1450
- handshakingSession.loggingMetadata
1451
- );
1452
- },
1453
- onConnectionClosed: () => {
1454
- this.log?.warn(
1455
- `connection to ${handshakingSession.to} closed during handshake`,
1456
- handshakingSession.loggingMetadata
1457
- );
1458
- this.onConnClosed(handshakingSession);
1459
- },
1460
- onHandshake: (msg) => {
1461
- this.onHandshakeResponse(handshakingSession, msg);
1462
- },
1463
- onInvalidHandshake: (reason) => {
1464
- this.log?.error(
1465
- `invalid handshake: ${reason}`,
1466
- handshakingSession.loggingMetadata
1467
- );
1468
- this.deleteSession(session);
1469
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1470
- },
1471
- onHandshakeTimeout: () => {
1472
- this.log?.error(
1473
- `connection to ${handshakingSession.to} timed out during handshake`,
1474
- handshakingSession.loggingMetadata
1475
- );
1476
- this.onConnClosed(handshakingSession);
1477
- }
1478
- });
1479
- this.updateSession(handshakingSession);
1480
- void this.sendHandshake(handshakingSession);
1481
- return handshakingSession;
1482
- }
1483
- rejectHandshakeResponse(session, reason, metadata) {
1484
- session.conn.telemetry?.span.setStatus({
1485
- code: import_api3.SpanStatusCode.ERROR,
1486
- message: reason
1487
- });
1488
- this.log?.warn(reason, metadata);
1489
- this.deleteSession(session);
1490
- }
1491
- onHandshakeResponse(session, msg) {
1492
- if (!import_value2.Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
1493
- const reason = `received invalid handshake response`;
1494
- this.rejectHandshakeResponse(session, reason, {
1495
- ...session.loggingMetadata,
1496
- transportMessage: msg,
1497
- validationErrors: [
1498
- ...import_value2.Value.Errors(ControlMessageHandshakeResponseSchema, msg.payload)
1499
- ]
1500
- });
1501
- return;
1502
- }
1503
- if (!msg.payload.status.ok) {
1504
- const retriable = msg.payload.status.code ? import_value2.Value.Check(
1505
- HandshakeErrorRetriableResponseCodes,
1506
- msg.payload.status.code
1507
- ) : false;
1508
- const reason = `handshake failed: ${msg.payload.status.reason}`;
1509
- this.rejectHandshakeResponse(session, reason, {
1510
- ...session.loggingMetadata,
1511
- transportMessage: msg
1512
- });
1513
- if (retriable) {
1514
- this.tryReconnecting(session.to);
1515
- } else {
1516
- this.deleteSession(session);
1517
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1518
- }
1519
- return;
1520
- }
1521
- if (msg.payload.status.sessionId !== session.id) {
1522
- const reason = `session id mismatch: expected ${session.id}, got ${msg.payload.status.sessionId}`;
1523
- this.rejectHandshakeResponse(session, reason, {
1524
- ...session.loggingMetadata,
1525
- transportMessage: msg
1526
- });
1527
- return;
1528
- }
1529
- this.log?.info(`handshake from ${msg.from} ok`, {
1530
- ...session.loggingMetadata,
1531
- transportMessage: msg
1532
- });
1533
- const connectedSession = SessionStateGraph.transition.HandshakingToConnected(session, {
1534
- onConnectionErrored: (err) => {
1535
- const errStr = coerceErrorString(err);
1536
- this.log?.warn(
1537
- `connection to ${connectedSession.to} errored: ${errStr}`,
1538
- connectedSession.loggingMetadata
1539
- );
1540
- },
1541
- onConnectionClosed: () => {
1542
- this.log?.info(
1543
- `connection to ${connectedSession.to} closed`,
1544
- connectedSession.loggingMetadata
1545
- );
1546
- this.onConnClosed(connectedSession);
1547
- },
1548
- onMessage: (msg2) => this.handleMsg(msg2),
1549
- onInvalidMessage: (reason) => {
1550
- this.deleteSession(connectedSession);
1551
- this.protocolError(ProtocolError.MessageOrderingViolated, reason);
1552
- }
1553
- });
1554
- this.updateSession(connectedSession);
1555
- this.retryBudget.startRestoringBudget(connectedSession.to);
1556
- }
1557
- /**
1558
- * Manually attempts to connect to a client.
1559
- * @param to The client ID of the node to connect to.
1560
- */
1561
- connect(to) {
1562
- let session = this.sessions.get(to);
1563
- session ??= this.createUnconnectedSession(to);
1564
- if (session.state !== "NoConnection" /* NoConnection */) {
1565
- this.log?.debug(
1566
- `session to ${to} has state ${session.state}, skipping connect attempt`,
1567
- session.loggingMetadata
1568
- );
1569
- return;
1570
- }
1571
- if (this.getStatus() !== "open") {
1572
- this.log?.info(
1573
- `transport state is no longer open, cancelling attempt to connect to ${to}`,
1574
- session.loggingMetadata
1575
- );
1576
- return;
1577
- }
1578
- if (!this.retryBudget.hasBudget(to)) {
1579
- const budgetConsumed = this.retryBudget.getBudgetConsumed(to);
1580
- const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
1581
- this.log?.error(errMsg, session.loggingMetadata);
1582
- this.protocolError(ProtocolError.RetriesExceeded, errMsg);
1583
- return;
1584
- }
1585
- let sleep = Promise.resolve();
1586
- const backoffMs = this.retryBudget.getBackoffMs(to);
1587
- if (backoffMs > 0) {
1588
- sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
1589
- }
1590
- this.log?.info(
1591
- `attempting connection to ${to} (${backoffMs}ms backoff)`,
1592
- session.loggingMetadata
1593
- );
1594
- this.retryBudget.consumeBudget(to);
1595
- const reconnectPromise = tracing_default.startActiveSpan("connect", async (span) => {
1596
- try {
1597
- span.addEvent("backoff", { backoffMs });
1598
- await sleep;
1599
- if (this.getStatus() !== "open") {
1600
- throw new Error("transport state is no longer open");
1601
- }
1602
- span.addEvent("connecting");
1603
- return await this.createNewOutgoingConnection(to);
1604
- } catch (err) {
1605
- const errStr = coerceErrorString(err);
1606
- span.recordException(errStr);
1607
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR });
1608
- throw err;
1609
- } finally {
1610
- span.end();
1611
- }
1612
- });
1613
- const connectingSession = SessionStateGraph.transition.NoConnectionToConnecting(
1614
- session,
1615
- reconnectPromise,
1616
- {
1617
- onConnectionEstablished: (conn) => {
1618
- this.log?.debug(
1619
- `connection to ${connectingSession.to} established`,
1620
- connectingSession.loggingMetadata
1621
- );
1622
- this.onConnectionEstablished(connectingSession, conn);
1623
- },
1624
- onConnectionFailed: (error) => {
1625
- const errStr = coerceErrorString(error);
1626
- this.log?.error(
1627
- `error connecting to ${connectingSession.to}: ${errStr}`,
1628
- connectingSession.loggingMetadata
1629
- );
1630
- this.onConnectingFailed(connectingSession);
1631
- },
1632
- onConnectionTimeout: () => {
1633
- this.log?.error(
1634
- `connection to ${connectingSession.to} timed out`,
1635
- connectingSession.loggingMetadata
1636
- );
1637
- this.onConnectingFailed(connectingSession);
1638
- }
1639
- }
1640
- );
1641
- this.updateSession(connectingSession);
1642
- }
1643
- async sendHandshake(session) {
1644
- let metadata = void 0;
1645
- if (this.handshakeExtensions) {
1646
- metadata = await this.handshakeExtensions.construct();
1647
- }
1648
- const requestMsg = handshakeRequestMessage({
1649
- from: this.clientId,
1650
- to: session.to,
1651
- sessionId: session.id,
1652
- expectedSessionState: {
1653
- nextExpectedSeq: session.ack,
1654
- nextSentSeq: session.nextSeq()
1655
- },
1656
- metadata,
1657
- tracing: getPropagationContext(session.telemetry.ctx)
1658
- });
1659
- this.log?.debug(`sending handshake request to ${session.to}`, {
1660
- ...session.loggingMetadata,
1661
- transportMessage: requestMsg
1662
- });
1663
- session.sendHandshake(requestMsg);
1664
- }
1665
- close() {
1666
- this.retryBudget.close();
1667
- super.close();
1668
- }
1669
- };
1670
-
1671
- // transport/impls/uds/client.ts
1672
- var UnixDomainSocketClientTransport = class extends ClientTransport {
1673
- path;
1674
- constructor(socketPath, clientId, providedOptions) {
1675
- super(clientId, providedOptions);
1676
- this.path = socketPath;
1677
- }
1678
- async createNewOutgoingConnection(to) {
1679
- this.log?.info(`establishing a new uds to ${to}`, {
1680
- clientId: this.clientId,
1681
- connectedTo: to
1682
- });
1683
- const sock = await new Promise((resolve, reject) => {
1684
- const sock2 = new import_node_net.Socket();
1685
- sock2.on("connect", () => resolve(sock2));
1686
- sock2.on("error", (err) => reject(err));
1687
- sock2.connect(this.path);
1688
- });
1689
- return new UdsConnection(sock);
1690
- }
1691
- };
1692
- // Annotate the CommonJS export names for ESM import in node:
1693
- 0 && (module.exports = {
1694
- UnixDomainSocketClientTransport
1695
- });
1696
- //# sourceMappingURL=client.cjs.map