@replit/river 0.216.1 → 0.217.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 (76) hide show
  1. package/README.md +2 -2
  2. package/dist/{adapter-BXCk-dmy.d.ts → adapter-Dl5Mewp3.d.ts} +1 -1
  3. package/dist/{chunk-C4EPHIKQ.js → chunk-FWVKRK36.js} +48 -26
  4. package/dist/chunk-FWVKRK36.js.map +1 -0
  5. package/dist/chunk-WMPWPIA4.js +72 -0
  6. package/dist/chunk-WMPWPIA4.js.map +1 -0
  7. package/dist/{chunk-62BM2WOT.js → chunk-YTV5S3DJ.js} +27 -19
  8. package/dist/chunk-YTV5S3DJ.js.map +1 -0
  9. package/dist/{client-BNc5Pj_4.d.ts → client-Tf2PXWoq.d.ts} +2 -2
  10. package/dist/codec/index.d.ts +3 -3
  11. package/dist/codec/index.js +2 -2
  12. package/dist/{connection-ou9w2dSY.d.ts → connection-D9yKScvK.d.ts} +3 -3
  13. package/dist/customSchemas/index.d.ts +34 -0
  14. package/dist/customSchemas/index.js +9 -0
  15. package/dist/customSchemas/index.js.map +1 -0
  16. package/dist/{index-ZWkoesQD.d.ts → index-DgUMnNOi.d.ts} +1 -1
  17. package/dist/logging/index.d.ts +3 -3
  18. package/dist/{message-CpXWqmJw.d.ts → message-DxS8db8A.d.ts} +30 -31
  19. package/dist/protobuf/index.d.ts +12 -16
  20. package/dist/protobuf/index.js +9 -7
  21. package/dist/protobuf/index.js.map +1 -1
  22. package/dist/router/index.d.ts +11 -11
  23. package/dist/router/index.js +1 -1
  24. package/dist/{server-BPu7Td80.d.ts → server-DhHG-q75.d.ts} +5 -5
  25. package/dist/{services-DpT2yNtt.d.ts → services-BT8Bq8Rs.d.ts} +8 -9
  26. package/dist/testUtil/index.d.ts +8 -8
  27. package/dist/testUtil/index.js +2 -2
  28. package/dist/testUtil/index.js.map +1 -1
  29. package/dist/transport/impls/ws/client.d.ts +7 -7
  30. package/dist/transport/impls/ws/client.js +2 -2
  31. package/dist/transport/impls/ws/server.d.ts +7 -7
  32. package/dist/transport/impls/ws/server.js +2 -2
  33. package/dist/transport/impls/ws/server.js.map +1 -1
  34. package/dist/transport/index.d.ts +8 -8
  35. package/dist/transport/index.js +2 -2
  36. package/dist/{transport-B1MUtXL7.d.ts → transport-D6czLXyc.d.ts} +13 -12
  37. package/package.json +14 -39
  38. package/dist/adapter-D5X11kmP.d.cts +0 -29
  39. package/dist/chunk-62BM2WOT.js.map +0 -1
  40. package/dist/chunk-C4EPHIKQ.js.map +0 -1
  41. package/dist/client-BZUvFL6B.d.cts +0 -54
  42. package/dist/codec/index.cjs +0 -268
  43. package/dist/codec/index.cjs.map +0 -1
  44. package/dist/codec/index.d.cts +0 -19
  45. package/dist/connection-xxgJHs2o.d.cts +0 -40
  46. package/dist/index-BAGGleT3.d.cts +0 -37
  47. package/dist/logging/index.cjs +0 -55
  48. package/dist/logging/index.cjs.map +0 -1
  49. package/dist/logging/index.d.cts +0 -4
  50. package/dist/message-CpXWqmJw.d.cts +0 -119
  51. package/dist/protobuf/codec.cjs +0 -107
  52. package/dist/protobuf/codec.cjs.map +0 -1
  53. package/dist/protobuf/codec.d.cts +0 -13
  54. package/dist/protobuf/index.cjs +0 -1877
  55. package/dist/protobuf/index.cjs.map +0 -1
  56. package/dist/protobuf/index.d.cts +0 -488
  57. package/dist/router/index.cjs +0 -2043
  58. package/dist/router/index.cjs.map +0 -1
  59. package/dist/router/index.d.cts +0 -80
  60. package/dist/server-JdnoVO11.d.cts +0 -72
  61. package/dist/services-CjigASqe.d.cts +0 -1135
  62. package/dist/testUtil/index.cjs +0 -3051
  63. package/dist/testUtil/index.cjs.map +0 -1
  64. package/dist/testUtil/index.d.cts +0 -122
  65. package/dist/transport/impls/ws/client.cjs +0 -2308
  66. package/dist/transport/impls/ws/client.cjs.map +0 -1
  67. package/dist/transport/impls/ws/client.d.cts +0 -33
  68. package/dist/transport/impls/ws/server.cjs +0 -2179
  69. package/dist/transport/impls/ws/server.cjs.map +0 -1
  70. package/dist/transport/impls/ws/server.d.cts +0 -21
  71. package/dist/transport/index.cjs +0 -2727
  72. package/dist/transport/index.cjs.map +0 -1
  73. package/dist/transport/index.d.cts +0 -11
  74. package/dist/transport-BnU3Zb0Q.d.cts +0 -590
  75. package/dist/types-BGGvYIJM.d.cts +0 -20
  76. package/dist/wslike-Dng9H1C7.d.cts +0 -40
@@ -1,2308 +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/ws/client.ts
21
- var client_exports = {};
22
- __export(client_exports, {
23
- WebSocketClientTransport: () => WebSocketClientTransport
24
- });
25
- module.exports = __toCommonJS(client_exports);
26
-
27
- // transport/client.ts
28
- var import_api4 = require("@opentelemetry/api");
29
-
30
- // transport/message.ts
31
- var import_typebox = require("@sinclair/typebox");
32
-
33
- // transport/id.ts
34
- var import_nanoid = require("nanoid");
35
- var alphabet = (0, import_nanoid.customAlphabet)(
36
- "1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
37
- );
38
- var generateId = () => alphabet(12);
39
-
40
- // transport/message.ts
41
- var TransportMessageSchema = (t) => import_typebox.Type.Object({
42
- id: import_typebox.Type.String(),
43
- from: import_typebox.Type.String(),
44
- to: import_typebox.Type.String(),
45
- seq: import_typebox.Type.Integer(),
46
- ack: import_typebox.Type.Integer(),
47
- serviceName: import_typebox.Type.Optional(import_typebox.Type.String()),
48
- procedureName: import_typebox.Type.Optional(import_typebox.Type.String()),
49
- streamId: import_typebox.Type.String(),
50
- controlFlags: import_typebox.Type.Integer(),
51
- tracing: import_typebox.Type.Optional(
52
- import_typebox.Type.Object({
53
- traceparent: import_typebox.Type.String(),
54
- tracestate: import_typebox.Type.String()
55
- })
56
- ),
57
- payload: t
58
- });
59
- var ControlMessageAckSchema = import_typebox.Type.Object({
60
- type: import_typebox.Type.Literal("ACK")
61
- });
62
- var ControlMessageCloseSchema = import_typebox.Type.Object({
63
- type: import_typebox.Type.Literal("CLOSE")
64
- });
65
- var currentProtocolVersion = "v2.0";
66
- var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
67
- type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
68
- protocolVersion: import_typebox.Type.String(),
69
- sessionId: import_typebox.Type.String(),
70
- /**
71
- * Specifies what the server's expected session state (from the pov of the client). This can be
72
- * used by the server to know whether this is a new or a reestablished connection, and whether it
73
- * is compatible with what it already has.
74
- */
75
- expectedSessionState: import_typebox.Type.Object({
76
- // what the client expects the server to send next
77
- nextExpectedSeq: import_typebox.Type.Integer(),
78
- nextSentSeq: import_typebox.Type.Integer()
79
- }),
80
- metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
81
- });
82
- var HandshakeErrorRetriableResponseCodes = import_typebox.Type.Union([
83
- import_typebox.Type.Literal("SESSION_STATE_MISMATCH")
84
- ]);
85
- var HandshakeErrorCustomHandlerFatalResponseCodes = import_typebox.Type.Union([
86
- // The custom validation handler rejected the handler because the client is unsupported.
87
- import_typebox.Type.Literal("REJECTED_UNSUPPORTED_CLIENT"),
88
- // The custom validation handler rejected the handshake.
89
- import_typebox.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
90
- ]);
91
- var HandshakeErrorFatalResponseCodes = import_typebox.Type.Union([
92
- HandshakeErrorCustomHandlerFatalResponseCodes,
93
- // The ciient sent a handshake that doesn't comply with the extended handshake metadata.
94
- import_typebox.Type.Literal("MALFORMED_HANDSHAKE_META"),
95
- // The ciient sent a handshake that doesn't comply with ControlMessageHandshakeRequestSchema.
96
- import_typebox.Type.Literal("MALFORMED_HANDSHAKE"),
97
- // The client's protocol version does not match the server's.
98
- import_typebox.Type.Literal("PROTOCOL_VERSION_MISMATCH")
99
- ]);
100
- var HandshakeErrorResponseCodes = import_typebox.Type.Union([
101
- HandshakeErrorRetriableResponseCodes,
102
- HandshakeErrorFatalResponseCodes
103
- ]);
104
- var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
105
- type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
106
- status: import_typebox.Type.Union([
107
- import_typebox.Type.Object({
108
- ok: import_typebox.Type.Literal(true),
109
- sessionId: import_typebox.Type.String()
110
- }),
111
- import_typebox.Type.Object({
112
- ok: import_typebox.Type.Literal(false),
113
- reason: import_typebox.Type.String(),
114
- code: HandshakeErrorResponseCodes
115
- })
116
- ])
117
- });
118
- var ControlMessagePayloadSchema = import_typebox.Type.Union([
119
- ControlMessageCloseSchema,
120
- ControlMessageAckSchema,
121
- ControlMessageHandshakeRequestSchema,
122
- ControlMessageHandshakeResponseSchema
123
- ]);
124
- var OpaqueTransportMessageSchema = TransportMessageSchema(
125
- import_typebox.Type.Unknown()
126
- );
127
- function handshakeRequestMessage({
128
- from,
129
- to,
130
- sessionId,
131
- expectedSessionState,
132
- metadata,
133
- tracing
134
- }) {
135
- return {
136
- id: generateId(),
137
- from,
138
- to,
139
- seq: 0,
140
- ack: 0,
141
- streamId: generateId(),
142
- controlFlags: 0,
143
- tracing,
144
- payload: {
145
- type: "HANDSHAKE_REQ",
146
- protocolVersion: currentProtocolVersion,
147
- sessionId,
148
- expectedSessionState,
149
- metadata
150
- }
151
- };
152
- }
153
- function isAck(controlFlag) {
154
- return (controlFlag & 1 /* AckBit */) === 1 /* AckBit */;
155
- }
156
-
157
- // codec/json.ts
158
- var encoder = new TextEncoder();
159
- var decoder = new TextDecoder();
160
- function uint8ArrayToBase64(uint8Array) {
161
- let binary = "";
162
- uint8Array.forEach((byte) => {
163
- binary += String.fromCharCode(byte);
164
- });
165
- return btoa(binary);
166
- }
167
- function base64ToUint8Array(base64) {
168
- const binaryString = atob(base64);
169
- const uint8Array = new Uint8Array(binaryString.length);
170
- for (let i = 0; i < binaryString.length; i++) {
171
- uint8Array[i] = binaryString.charCodeAt(i);
172
- }
173
- return uint8Array;
174
- }
175
- var NaiveJsonCodec = {
176
- toBuffer: (obj) => {
177
- return encoder.encode(
178
- JSON.stringify(obj, function replacer(key) {
179
- const val = this[key];
180
- if (val instanceof Uint8Array) {
181
- return { $t: uint8ArrayToBase64(val) };
182
- } else if (typeof val === "bigint") {
183
- return { $b: val.toString() };
184
- } else {
185
- return val;
186
- }
187
- })
188
- );
189
- },
190
- fromBuffer: (buff) => {
191
- const parsed = JSON.parse(
192
- decoder.decode(buff),
193
- function reviver(_key, val) {
194
- if (val?.$t !== void 0) {
195
- return base64ToUint8Array(val.$t);
196
- } else if (val?.$b !== void 0) {
197
- return BigInt(val.$b);
198
- } else {
199
- return val;
200
- }
201
- }
202
- );
203
- if (typeof parsed !== "object" || parsed === null) {
204
- throw new Error("unpacked msg is not an object");
205
- }
206
- return parsed;
207
- }
208
- };
209
-
210
- // transport/options.ts
211
- var defaultTransportOptions = {
212
- heartbeatIntervalMs: 1e3,
213
- heartbeatsUntilDead: 2,
214
- sessionDisconnectGraceMs: 5e3,
215
- connectionTimeoutMs: 2e3,
216
- handshakeTimeoutMs: 1e3,
217
- enableTransparentSessionReconnects: true,
218
- codec: NaiveJsonCodec
219
- };
220
- var defaultConnectionRetryOptions = {
221
- baseIntervalMs: 150,
222
- maxJitterMs: 200,
223
- maxBackoffMs: 32e3,
224
- attemptBudgetCapacity: 5,
225
- budgetRestoreIntervalMs: 200,
226
- isFatalConnectionError: () => false
227
- };
228
- var defaultClientTransportOptions = {
229
- ...defaultTransportOptions,
230
- ...defaultConnectionRetryOptions
231
- };
232
- var defaultServerTransportOptions = {
233
- ...defaultTransportOptions
234
- };
235
-
236
- // transport/rateLimit.ts
237
- var LeakyBucketRateLimit = class {
238
- budgetConsumed;
239
- intervalHandle;
240
- options;
241
- constructor(options) {
242
- this.options = options;
243
- this.budgetConsumed = 0;
244
- }
245
- getBackoffMs() {
246
- if (this.getBudgetConsumed() === 0) {
247
- return 0;
248
- }
249
- const exponent = Math.max(0, this.getBudgetConsumed() - 1);
250
- const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
251
- const backoffMs = Math.min(
252
- this.options.baseIntervalMs * 2 ** exponent,
253
- this.options.maxBackoffMs
254
- );
255
- return backoffMs + jitter;
256
- }
257
- get totalBudgetRestoreTime() {
258
- return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
259
- }
260
- consumeBudget() {
261
- this.stopLeak();
262
- this.budgetConsumed = this.getBudgetConsumed() + 1;
263
- }
264
- getBudgetConsumed() {
265
- return this.budgetConsumed;
266
- }
267
- hasBudget() {
268
- return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
269
- }
270
- startRestoringBudget() {
271
- if (this.intervalHandle) {
272
- return;
273
- }
274
- const restoreBudgetForUser = () => {
275
- const currentBudget = this.budgetConsumed;
276
- if (!currentBudget) {
277
- this.stopLeak();
278
- return;
279
- }
280
- const newBudget = currentBudget - 1;
281
- if (newBudget === 0) {
282
- return;
283
- }
284
- this.budgetConsumed = newBudget;
285
- };
286
- this.intervalHandle = setInterval(
287
- restoreBudgetForUser,
288
- this.options.budgetRestoreIntervalMs
289
- );
290
- }
291
- stopLeak() {
292
- if (!this.intervalHandle) {
293
- return;
294
- }
295
- clearInterval(this.intervalHandle);
296
- this.intervalHandle = void 0;
297
- }
298
- resetBudget() {
299
- this.stopLeak();
300
- this.budgetConsumed = 0;
301
- }
302
- close() {
303
- this.stopLeak();
304
- }
305
- };
306
-
307
- // logging/log.ts
308
- var import_api = require("@opentelemetry/api");
309
- var LoggingLevels = {
310
- debug: -1,
311
- info: 0,
312
- warn: 1,
313
- error: 2
314
- };
315
- var cleanedLogFn = (log) => {
316
- return (msg, metadata) => {
317
- if (metadata && !metadata.telemetry) {
318
- const span = import_api.trace.getSpan(import_api.context.active());
319
- if (span) {
320
- metadata.telemetry = {
321
- traceId: span.spanContext().traceId,
322
- spanId: span.spanContext().spanId
323
- };
324
- }
325
- }
326
- if (!metadata?.transportMessage) {
327
- log(msg, metadata);
328
- return;
329
- }
330
- const { payload, ...rest } = metadata.transportMessage;
331
- metadata.transportMessage = rest;
332
- log(msg, metadata);
333
- };
334
- };
335
- var BaseLogger = class {
336
- minLevel;
337
- output;
338
- constructor(output, minLevel = "info") {
339
- this.minLevel = minLevel;
340
- this.output = output;
341
- }
342
- debug(msg, metadata) {
343
- if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
344
- this.output(msg, metadata ?? {}, "debug");
345
- }
346
- }
347
- info(msg, metadata) {
348
- if (LoggingLevels[this.minLevel] <= LoggingLevels.info) {
349
- this.output(msg, metadata ?? {}, "info");
350
- }
351
- }
352
- warn(msg, metadata) {
353
- if (LoggingLevels[this.minLevel] <= LoggingLevels.warn) {
354
- this.output(msg, metadata ?? {}, "warn");
355
- }
356
- }
357
- error(msg, metadata) {
358
- if (LoggingLevels[this.minLevel] <= LoggingLevels.error) {
359
- this.output(msg, metadata ?? {}, "error");
360
- }
361
- }
362
- };
363
- var createLogProxy = (log) => ({
364
- debug: cleanedLogFn(log.debug.bind(log)),
365
- info: cleanedLogFn(log.info.bind(log)),
366
- warn: cleanedLogFn(log.warn.bind(log)),
367
- error: cleanedLogFn(log.error.bind(log))
368
- });
369
-
370
- // transport/events.ts
371
- var ProtocolError = {
372
- RetriesExceeded: "conn_retry_exceeded",
373
- HandshakeFailed: "handshake_failed",
374
- MessageOrderingViolated: "message_ordering_violated",
375
- InvalidMessage: "invalid_message",
376
- MessageSendFailure: "message_send_failure"
377
- };
378
- var EventDispatcher = class {
379
- eventListeners = {};
380
- removeAllListeners() {
381
- this.eventListeners = {};
382
- }
383
- numberOfListeners(eventType) {
384
- return this.eventListeners[eventType]?.size ?? 0;
385
- }
386
- addEventListener(eventType, handler) {
387
- if (!this.eventListeners[eventType]) {
388
- this.eventListeners[eventType] = /* @__PURE__ */ new Set();
389
- }
390
- this.eventListeners[eventType]?.add(handler);
391
- }
392
- removeEventListener(eventType, handler) {
393
- const handlers = this.eventListeners[eventType];
394
- if (handlers) {
395
- this.eventListeners[eventType]?.delete(handler);
396
- }
397
- }
398
- dispatchEvent(eventType, event) {
399
- const handlers = this.eventListeners[eventType];
400
- if (handlers) {
401
- const copy = [...handlers];
402
- for (const handler of copy) {
403
- handler(event);
404
- }
405
- }
406
- }
407
- };
408
-
409
- // transport/sessionStateMachine/common.ts
410
- var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
411
- var StateMachineState = class {
412
- /*
413
- * Whether this state has been consumed
414
- * and we've moved on to another state
415
- */
416
- _isConsumed;
417
- /**
418
- * Cleanup this state machine state and mark it as consumed.
419
- * After calling close, it is an error to access any properties on the state.
420
- * You should never need to call this as a consumer.
421
- *
422
- * If you're looking to close the session from the client,
423
- * use `.hardDisconnect` on the client transport.
424
- */
425
- close() {
426
- this._handleClose();
427
- }
428
- constructor() {
429
- this._isConsumed = false;
430
- return new Proxy(this, {
431
- get(target, prop) {
432
- if (prop === "_isConsumed" || prop === "id" || prop === "state") {
433
- return Reflect.get(target, prop);
434
- }
435
- if (prop === "_handleStateExit") {
436
- return () => {
437
- target._isConsumed = true;
438
- target._handleStateExit();
439
- };
440
- }
441
- if (prop === "_handleClose") {
442
- return () => {
443
- target._isConsumed = true;
444
- target._handleStateExit();
445
- target._handleClose();
446
- };
447
- }
448
- if (target._isConsumed) {
449
- throw new Error(
450
- `${ERR_CONSUMED}: getting ${prop.toString()} on consumed state`
451
- );
452
- }
453
- return Reflect.get(target, prop);
454
- },
455
- set(target, prop, value) {
456
- if (target._isConsumed) {
457
- throw new Error(
458
- `${ERR_CONSUMED}: setting ${prop.toString()} on consumed state`
459
- );
460
- }
461
- return Reflect.set(target, prop, value);
462
- }
463
- });
464
- }
465
- };
466
- var CommonSession = class extends StateMachineState {
467
- from;
468
- options;
469
- codec;
470
- tracer;
471
- log;
472
- constructor({ from, options, log, tracer, codec }) {
473
- super();
474
- this.from = from;
475
- this.options = options;
476
- this.log = log;
477
- this.tracer = tracer;
478
- this.codec = codec;
479
- }
480
- };
481
- var IdentifiedSession = class extends CommonSession {
482
- id;
483
- telemetry;
484
- to;
485
- protocolVersion;
486
- listeners;
487
- /**
488
- * Index of the message we will send next (excluding handshake)
489
- */
490
- seq;
491
- /**
492
- * Last seq we sent over the wire this session (excluding handshake) and retransmissions
493
- */
494
- seqSent;
495
- /**
496
- * Number of unique messages we've received this session (excluding handshake)
497
- */
498
- ack;
499
- sendBuffer;
500
- constructor(props) {
501
- const {
502
- id,
503
- to,
504
- seq,
505
- ack,
506
- sendBuffer,
507
- telemetry,
508
- log,
509
- protocolVersion,
510
- seqSent: messagesSent,
511
- listeners
512
- } = props;
513
- super(props);
514
- this.id = id;
515
- this.to = to;
516
- this.seq = seq;
517
- this.ack = ack;
518
- this.sendBuffer = sendBuffer;
519
- this.telemetry = telemetry;
520
- this.log = log;
521
- this.protocolVersion = protocolVersion;
522
- this.seqSent = messagesSent;
523
- this.listeners = listeners;
524
- }
525
- get loggingMetadata() {
526
- const metadata = {
527
- clientId: this.from,
528
- connectedTo: this.to,
529
- sessionId: this.id
530
- };
531
- if (this.telemetry.span.isRecording()) {
532
- const spanContext = this.telemetry.span.spanContext();
533
- metadata.telemetry = {
534
- traceId: spanContext.traceId,
535
- spanId: spanContext.spanId
536
- };
537
- }
538
- return metadata;
539
- }
540
- encodeMsg(partialMsg) {
541
- const msg = {
542
- ...partialMsg,
543
- id: generateId(),
544
- to: this.to,
545
- from: this.from,
546
- seq: this.seq,
547
- ack: this.ack
548
- };
549
- const encoded = this.codec.toBuffer(msg);
550
- if (!encoded.ok) {
551
- this.listeners.onMessageSendFailure(
552
- { ...partialMsg, seq: this.seq },
553
- encoded.reason
554
- );
555
- return encoded;
556
- }
557
- this.seq++;
558
- return {
559
- ok: true,
560
- value: {
561
- id: msg.id,
562
- seq: msg.seq,
563
- msg: partialMsg,
564
- data: encoded.value
565
- }
566
- };
567
- }
568
- nextSeq() {
569
- return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;
570
- }
571
- send(msg) {
572
- const encodeResult = this.encodeMsg(msg);
573
- if (!encodeResult.ok) {
574
- return encodeResult;
575
- }
576
- this.sendBuffer.push(encodeResult.value);
577
- return {
578
- ok: true,
579
- value: encodeResult.value.id
580
- };
581
- }
582
- _handleStateExit() {
583
- }
584
- _handleClose() {
585
- this.sendBuffer.length = 0;
586
- this.telemetry.span.end();
587
- }
588
- };
589
- var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
590
- graceExpiryTime;
591
- gracePeriodTimeout;
592
- listeners;
593
- constructor(props) {
594
- super(props);
595
- this.listeners = props.listeners;
596
- this.graceExpiryTime = props.graceExpiryTime;
597
- this.gracePeriodTimeout = setTimeout(() => {
598
- this.listeners.onSessionGracePeriodElapsed();
599
- }, this.graceExpiryTime - Date.now());
600
- }
601
- _handleStateExit() {
602
- super._handleStateExit();
603
- if (this.gracePeriodTimeout) {
604
- clearTimeout(this.gracePeriodTimeout);
605
- this.gracePeriodTimeout = void 0;
606
- }
607
- }
608
- _handleClose() {
609
- super._handleClose();
610
- }
611
- };
612
-
613
- // transport/sessionStateMachine/SessionConnecting.ts
614
- var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
615
- state = "Connecting" /* Connecting */;
616
- connPromise;
617
- listeners;
618
- connectionTimeout;
619
- constructor(props) {
620
- super(props);
621
- this.connPromise = props.connPromise;
622
- this.listeners = props.listeners;
623
- this.connPromise.then(
624
- (conn) => {
625
- if (this._isConsumed) return;
626
- this.listeners.onConnectionEstablished(conn);
627
- },
628
- (err) => {
629
- if (this._isConsumed) return;
630
- this.listeners.onConnectionFailed(err);
631
- }
632
- );
633
- this.connectionTimeout = setTimeout(() => {
634
- this.listeners.onConnectionTimeout();
635
- }, this.options.connectionTimeoutMs);
636
- }
637
- // close a pending connection if it resolves, ignore errors if the promise
638
- // ends up rejected anyways
639
- bestEffortClose() {
640
- const logger = this.log;
641
- const metadata = this.loggingMetadata;
642
- this.connPromise.then((conn) => {
643
- conn.close();
644
- logger?.info(
645
- "connection eventually resolved but session has transitioned, closed connection",
646
- {
647
- ...metadata,
648
- ...conn.loggingMetadata
649
- }
650
- );
651
- }).catch(() => {
652
- });
653
- }
654
- _handleStateExit() {
655
- super._handleStateExit();
656
- if (this.connectionTimeout) {
657
- clearTimeout(this.connectionTimeout);
658
- this.connectionTimeout = void 0;
659
- }
660
- }
661
- _handleClose() {
662
- super._handleClose();
663
- this.bestEffortClose();
664
- }
665
- };
666
-
667
- // transport/sessionStateMachine/SessionNoConnection.ts
668
- var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
669
- state = "NoConnection" /* NoConnection */;
670
- _handleClose() {
671
- super._handleClose();
672
- }
673
- _handleStateExit() {
674
- super._handleStateExit();
675
- }
676
- };
677
-
678
- // tracing/index.ts
679
- var import_api2 = require("@opentelemetry/api");
680
-
681
- // transport/stringifyError.ts
682
- function coerceErrorString(err) {
683
- if (err instanceof Error) {
684
- return err.message || "unknown reason";
685
- }
686
- return `[coerced to error] ${String(err)}`;
687
- }
688
-
689
- // package.json
690
- var version = "0.216.1";
691
-
692
- // tracing/index.ts
693
- function getPropagationContext(ctx) {
694
- const tracing = {
695
- traceparent: "",
696
- tracestate: ""
697
- };
698
- import_api2.propagation.inject(ctx, tracing);
699
- return tracing;
700
- }
701
- function createSessionTelemetryInfo(tracer, sessionId, to, from, propagationCtx) {
702
- const parentCtx = propagationCtx ? import_api2.propagation.extract(import_api2.context.active(), propagationCtx) : import_api2.context.active();
703
- const span = tracer.startSpan(
704
- `river.session`,
705
- {
706
- attributes: {
707
- component: "river",
708
- "river.session.id": sessionId,
709
- "river.session.to": to,
710
- "river.session.from": from
711
- }
712
- },
713
- parentCtx
714
- );
715
- const ctx = import_api2.trace.setSpan(parentCtx, span);
716
- return { span, ctx };
717
- }
718
- function createConnectionTelemetryInfo(tracer, connection, info) {
719
- const span = tracer.startSpan(
720
- `river.connection`,
721
- {
722
- attributes: {
723
- component: "river",
724
- "river.connection.id": connection.id
725
- },
726
- links: [{ context: info.span.spanContext() }]
727
- },
728
- info.ctx
729
- );
730
- const ctx = import_api2.trace.setSpan(info.ctx, span);
731
- return { span, ctx };
732
- }
733
- function getTracer() {
734
- return import_api2.trace.getTracer("river", version);
735
- }
736
-
737
- // transport/sessionStateMachine/SessionWaitingForHandshake.ts
738
- var SessionWaitingForHandshake = class extends CommonSession {
739
- state = "WaitingForHandshake" /* WaitingForHandshake */;
740
- conn;
741
- listeners;
742
- handshakeTimeout;
743
- constructor(props) {
744
- super(props);
745
- this.conn = props.conn;
746
- this.listeners = props.listeners;
747
- this.handshakeTimeout = setTimeout(() => {
748
- this.listeners.onHandshakeTimeout();
749
- }, this.options.handshakeTimeoutMs);
750
- this.conn.setDataListener(this.onHandshakeData);
751
- this.conn.setErrorListener(this.listeners.onConnectionErrored);
752
- this.conn.setCloseListener(this.listeners.onConnectionClosed);
753
- }
754
- get loggingMetadata() {
755
- return {
756
- clientId: this.from,
757
- connId: this.conn.id,
758
- ...this.conn.loggingMetadata
759
- };
760
- }
761
- onHandshakeData = (msg) => {
762
- const parsedMsgRes = this.codec.fromBuffer(msg);
763
- if (!parsedMsgRes.ok) {
764
- this.listeners.onInvalidHandshake(
765
- `could not parse handshake message: ${parsedMsgRes.reason}`,
766
- "MALFORMED_HANDSHAKE"
767
- );
768
- return;
769
- }
770
- this.listeners.onHandshake(parsedMsgRes.value);
771
- };
772
- sendHandshake(msg) {
773
- const buff = this.codec.toBuffer(msg);
774
- if (!buff.ok) {
775
- return buff;
776
- }
777
- const sent = this.conn.send(buff.value);
778
- if (!sent) {
779
- return {
780
- ok: false,
781
- reason: "failed to send handshake"
782
- };
783
- }
784
- return {
785
- ok: true,
786
- value: msg.id
787
- };
788
- }
789
- _handleStateExit() {
790
- this.conn.removeDataListener();
791
- this.conn.removeErrorListener();
792
- this.conn.removeCloseListener();
793
- clearTimeout(this.handshakeTimeout);
794
- this.handshakeTimeout = void 0;
795
- }
796
- _handleClose() {
797
- this.conn.close();
798
- }
799
- };
800
-
801
- // transport/sessionStateMachine/SessionHandshaking.ts
802
- var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
803
- state = "Handshaking" /* Handshaking */;
804
- conn;
805
- listeners;
806
- handshakeTimeout;
807
- constructor(props) {
808
- super(props);
809
- this.conn = props.conn;
810
- this.listeners = props.listeners;
811
- this.handshakeTimeout = setTimeout(() => {
812
- this.listeners.onHandshakeTimeout();
813
- }, this.options.handshakeTimeoutMs);
814
- this.conn.setDataListener(this.onHandshakeData);
815
- this.conn.setErrorListener(this.listeners.onConnectionErrored);
816
- this.conn.setCloseListener(this.listeners.onConnectionClosed);
817
- }
818
- get loggingMetadata() {
819
- return {
820
- ...super.loggingMetadata,
821
- ...this.conn.loggingMetadata
822
- };
823
- }
824
- onHandshakeData = (msg) => {
825
- const parsedMsgRes = this.codec.fromBuffer(msg);
826
- if (!parsedMsgRes.ok) {
827
- this.listeners.onInvalidHandshake(
828
- `could not parse handshake message: ${parsedMsgRes.reason}`,
829
- "MALFORMED_HANDSHAKE"
830
- );
831
- return;
832
- }
833
- this.listeners.onHandshake(parsedMsgRes.value);
834
- };
835
- sendHandshake(msg) {
836
- const buff = this.codec.toBuffer(msg);
837
- if (!buff.ok) {
838
- return buff;
839
- }
840
- const sent = this.conn.send(buff.value);
841
- if (!sent) {
842
- return {
843
- ok: false,
844
- reason: "failed to send handshake"
845
- };
846
- }
847
- return {
848
- ok: true,
849
- value: msg.id
850
- };
851
- }
852
- _handleStateExit() {
853
- super._handleStateExit();
854
- this.conn.removeDataListener();
855
- this.conn.removeErrorListener();
856
- this.conn.removeCloseListener();
857
- if (this.handshakeTimeout) {
858
- clearTimeout(this.handshakeTimeout);
859
- this.handshakeTimeout = void 0;
860
- }
861
- }
862
- _handleClose() {
863
- super._handleClose();
864
- this.conn.close();
865
- }
866
- };
867
-
868
- // transport/sessionStateMachine/SessionConnected.ts
869
- var import_api3 = require("@opentelemetry/api");
870
- var SessionConnected = class extends IdentifiedSession {
871
- state = "Connected" /* Connected */;
872
- conn;
873
- listeners;
874
- heartbeatHandle;
875
- heartbeatMissTimeout;
876
- isActivelyHeartbeating = false;
877
- updateBookkeeping(ack, seq) {
878
- this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
879
- this.ack = seq + 1;
880
- if (this.heartbeatMissTimeout) {
881
- clearTimeout(this.heartbeatMissTimeout);
882
- }
883
- this.startMissingHeartbeatTimeout();
884
- }
885
- assertSendOrdering(encodedMsg) {
886
- if (encodedMsg.seq > this.seqSent + 1) {
887
- const msg = `invariant violation: would have sent out of order msg (seq: ${encodedMsg.seq}, expected: ${this.seqSent} + 1)`;
888
- this.log?.error(msg, {
889
- ...this.loggingMetadata,
890
- tags: ["invariant-violation"]
891
- });
892
- throw new Error(msg);
893
- }
894
- }
895
- send(msg) {
896
- const encodeResult = this.encodeMsg(msg);
897
- if (!encodeResult.ok) {
898
- return encodeResult;
899
- }
900
- const encodedMsg = encodeResult.value;
901
- this.assertSendOrdering(encodedMsg);
902
- this.sendBuffer.push(encodedMsg);
903
- const sent = this.conn.send(encodedMsg.data);
904
- if (!sent) {
905
- const reason = "failed to send message";
906
- this.listeners.onMessageSendFailure(
907
- { ...encodedMsg.msg, seq: encodedMsg.seq },
908
- reason
909
- );
910
- return { ok: false, reason };
911
- }
912
- this.seqSent = encodedMsg.seq;
913
- return { ok: true, value: encodedMsg.id };
914
- }
915
- constructor(props) {
916
- super(props);
917
- this.conn = props.conn;
918
- this.listeners = props.listeners;
919
- this.conn.setDataListener(this.onMessageData);
920
- this.conn.setCloseListener(this.listeners.onConnectionClosed);
921
- this.conn.setErrorListener(this.listeners.onConnectionErrored);
922
- }
923
- sendBufferedMessages() {
924
- if (this.sendBuffer.length > 0) {
925
- this.log?.info(
926
- `sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
927
- this.loggingMetadata
928
- );
929
- for (const msg of this.sendBuffer) {
930
- this.assertSendOrdering(msg);
931
- const sent = this.conn.send(msg.data);
932
- if (!sent) {
933
- const reason = "failed to send buffered message";
934
- this.listeners.onMessageSendFailure(
935
- { ...msg.msg, seq: msg.seq },
936
- reason
937
- );
938
- return { ok: false, reason };
939
- }
940
- this.seqSent = msg.seq;
941
- }
942
- }
943
- return { ok: true, value: void 0 };
944
- }
945
- get loggingMetadata() {
946
- return {
947
- ...super.loggingMetadata,
948
- ...this.conn.loggingMetadata
949
- };
950
- }
951
- startMissingHeartbeatTimeout() {
952
- const maxMisses = this.options.heartbeatsUntilDead;
953
- const missDuration = maxMisses * this.options.heartbeatIntervalMs;
954
- this.heartbeatMissTimeout = setTimeout(() => {
955
- this.log?.info(
956
- `closing connection to ${this.to} due to inactivity (missed ${maxMisses} heartbeats which is ${missDuration}ms)`,
957
- this.loggingMetadata
958
- );
959
- this.telemetry.span.addEvent(
960
- "closing connection due to missing heartbeat"
961
- );
962
- this.conn.close();
963
- }, missDuration);
964
- }
965
- startActiveHeartbeat() {
966
- this.isActivelyHeartbeating = true;
967
- this.heartbeatHandle = setInterval(() => {
968
- this.sendHeartbeat();
969
- }, this.options.heartbeatIntervalMs);
970
- }
971
- sendHeartbeat() {
972
- this.log?.debug("sending heartbeat", this.loggingMetadata);
973
- const heartbeat = {
974
- streamId: "heartbeat",
975
- controlFlags: 1 /* AckBit */,
976
- payload: {
977
- type: "ACK"
978
- }
979
- };
980
- this.send(heartbeat);
981
- }
982
- onMessageData = (msg) => {
983
- const parsedMsgRes = this.codec.fromBuffer(msg);
984
- if (!parsedMsgRes.ok) {
985
- this.listeners.onInvalidMessage(
986
- `could not parse message: ${parsedMsgRes.reason}`
987
- );
988
- return;
989
- }
990
- const parsedMsg = parsedMsgRes.value;
991
- if (parsedMsg.seq !== this.ack) {
992
- if (parsedMsg.seq < this.ack) {
993
- this.log?.debug(
994
- `received duplicate msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack}), discarding`,
995
- {
996
- ...this.loggingMetadata,
997
- transportMessage: parsedMsg
998
- }
999
- );
1000
- } else {
1001
- const reason = `received out-of-order msg, closing connection (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
1002
- this.log?.error(reason, {
1003
- ...this.loggingMetadata,
1004
- transportMessage: parsedMsg,
1005
- tags: ["invariant-violation"]
1006
- });
1007
- this.telemetry.span.setStatus({
1008
- code: import_api3.SpanStatusCode.ERROR,
1009
- message: reason
1010
- });
1011
- this.conn.close();
1012
- }
1013
- return;
1014
- }
1015
- this.log?.debug(`received msg`, {
1016
- ...this.loggingMetadata,
1017
- transportMessage: parsedMsg
1018
- });
1019
- this.updateBookkeeping(parsedMsg.ack, parsedMsg.seq);
1020
- if (!isAck(parsedMsg.controlFlags)) {
1021
- this.listeners.onMessage(parsedMsg);
1022
- return;
1023
- }
1024
- this.log?.debug(`discarding msg (ack bit set)`, {
1025
- ...this.loggingMetadata,
1026
- transportMessage: parsedMsg
1027
- });
1028
- if (!this.isActivelyHeartbeating) {
1029
- this.sendHeartbeat();
1030
- }
1031
- };
1032
- _handleStateExit() {
1033
- super._handleStateExit();
1034
- this.conn.removeDataListener();
1035
- this.conn.removeCloseListener();
1036
- this.conn.removeErrorListener();
1037
- if (this.heartbeatHandle) {
1038
- clearInterval(this.heartbeatHandle);
1039
- this.heartbeatHandle = void 0;
1040
- }
1041
- if (this.heartbeatMissTimeout) {
1042
- clearTimeout(this.heartbeatMissTimeout);
1043
- this.heartbeatMissTimeout = void 0;
1044
- }
1045
- }
1046
- _handleClose() {
1047
- super._handleClose();
1048
- this.conn.close();
1049
- }
1050
- };
1051
-
1052
- // transport/sessionStateMachine/SessionBackingOff.ts
1053
- var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
1054
- state = "BackingOff" /* BackingOff */;
1055
- listeners;
1056
- backoffTimeout;
1057
- constructor(props) {
1058
- super(props);
1059
- this.listeners = props.listeners;
1060
- this.backoffTimeout = setTimeout(() => {
1061
- this.listeners.onBackoffFinished();
1062
- }, props.backoffMs);
1063
- }
1064
- _handleClose() {
1065
- super._handleClose();
1066
- }
1067
- _handleStateExit() {
1068
- super._handleStateExit();
1069
- if (this.backoffTimeout) {
1070
- clearTimeout(this.backoffTimeout);
1071
- this.backoffTimeout = void 0;
1072
- }
1073
- }
1074
- };
1075
-
1076
- // codec/adapter.ts
1077
- var import_value = require("@sinclair/typebox/value");
1078
-
1079
- // transport/connection.ts
1080
- var Connection = class {
1081
- id;
1082
- telemetry;
1083
- constructor() {
1084
- this.id = `conn-${generateId()}`;
1085
- }
1086
- get loggingMetadata() {
1087
- const metadata = { connId: this.id };
1088
- if (this.telemetry?.span.isRecording()) {
1089
- const spanContext = this.telemetry.span.spanContext();
1090
- metadata.telemetry = {
1091
- traceId: spanContext.traceId,
1092
- spanId: spanContext.spanId
1093
- };
1094
- }
1095
- return metadata;
1096
- }
1097
- dataListener;
1098
- closeListener;
1099
- errorListener;
1100
- onData(msg) {
1101
- this.dataListener?.(msg);
1102
- }
1103
- onError(err) {
1104
- this.errorListener?.(err);
1105
- }
1106
- onClose() {
1107
- this.closeListener?.();
1108
- this.telemetry?.span.end();
1109
- }
1110
- /**
1111
- * Set the callback for when a message is received.
1112
- * @param cb The message handler callback.
1113
- */
1114
- setDataListener(cb) {
1115
- this.dataListener = cb;
1116
- }
1117
- removeDataListener() {
1118
- this.dataListener = void 0;
1119
- }
1120
- /**
1121
- * Set the callback for when the connection is closed.
1122
- * This should also be called if an error happens and after notifying the error listener.
1123
- * @param cb The callback to call when the connection is closed.
1124
- */
1125
- setCloseListener(cb) {
1126
- this.closeListener = cb;
1127
- }
1128
- removeCloseListener() {
1129
- this.closeListener = void 0;
1130
- }
1131
- /**
1132
- * Set the callback for when an error is received.
1133
- * This should only be used for logging errors, all cleanup
1134
- * should be delegated to setCloseListener.
1135
- *
1136
- * The implementer should take care such that the implemented
1137
- * connection will call both the close and error callbacks
1138
- * on an error.
1139
- *
1140
- * @param cb The callback to call when an error is received.
1141
- */
1142
- setErrorListener(cb) {
1143
- this.errorListener = cb;
1144
- }
1145
- removeErrorListener() {
1146
- this.errorListener = void 0;
1147
- }
1148
- };
1149
-
1150
- // transport/impls/ws/connection.ts
1151
- var WS_HEALTHY_CLOSE_CODE = 1e3;
1152
- var WebSocketCloseError = class extends Error {
1153
- code;
1154
- reason;
1155
- constructor(code, reason) {
1156
- super(`websocket closed with code and reason: ${code} - ${reason}`);
1157
- this.code = code;
1158
- this.reason = reason;
1159
- }
1160
- };
1161
- var WebSocketConnection = class extends Connection {
1162
- ws;
1163
- extras;
1164
- get loggingMetadata() {
1165
- const metadata = super.loggingMetadata;
1166
- if (this.extras) {
1167
- metadata.extras = this.extras;
1168
- }
1169
- return metadata;
1170
- }
1171
- constructor(ws, extras) {
1172
- super();
1173
- this.ws = ws;
1174
- this.extras = extras;
1175
- this.ws.binaryType = "arraybuffer";
1176
- let didError = false;
1177
- this.ws.onerror = () => {
1178
- didError = true;
1179
- };
1180
- this.ws.onclose = ({ code, reason }) => {
1181
- if (didError) {
1182
- const err = new WebSocketCloseError(code, reason);
1183
- this.onError(err);
1184
- }
1185
- this.onClose();
1186
- };
1187
- this.ws.onmessage = (msg) => {
1188
- this.onData(msg.data);
1189
- };
1190
- }
1191
- send(payload) {
1192
- try {
1193
- this.ws.send(payload);
1194
- return true;
1195
- } catch {
1196
- return false;
1197
- }
1198
- }
1199
- close() {
1200
- this.ws.close(WS_HEALTHY_CLOSE_CODE);
1201
- }
1202
- };
1203
-
1204
- // codec/adapter.ts
1205
- var CodecMessageAdapter = class {
1206
- constructor(codec) {
1207
- this.codec = codec;
1208
- }
1209
- toBuffer(msg) {
1210
- try {
1211
- return {
1212
- ok: true,
1213
- value: this.codec.toBuffer(msg)
1214
- };
1215
- } catch (e) {
1216
- return {
1217
- ok: false,
1218
- reason: coerceErrorString(e)
1219
- };
1220
- }
1221
- }
1222
- fromBuffer(buf) {
1223
- try {
1224
- const parsedMsg = this.codec.fromBuffer(buf);
1225
- if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
1226
- return {
1227
- ok: false,
1228
- reason: "transport message schema mismatch"
1229
- };
1230
- }
1231
- return {
1232
- ok: true,
1233
- value: parsedMsg
1234
- };
1235
- } catch (e) {
1236
- return {
1237
- ok: false,
1238
- reason: coerceErrorString(e)
1239
- };
1240
- }
1241
- }
1242
- };
1243
-
1244
- // transport/sessionStateMachine/transitions.ts
1245
- function inheritSharedSession(session) {
1246
- return {
1247
- id: session.id,
1248
- from: session.from,
1249
- to: session.to,
1250
- seq: session.seq,
1251
- ack: session.ack,
1252
- seqSent: session.seqSent,
1253
- sendBuffer: session.sendBuffer,
1254
- telemetry: session.telemetry,
1255
- options: session.options,
1256
- log: session.log,
1257
- tracer: session.tracer,
1258
- protocolVersion: session.protocolVersion,
1259
- codec: session.codec
1260
- };
1261
- }
1262
- function inheritSharedSessionWithGrace(session) {
1263
- return {
1264
- ...inheritSharedSession(session),
1265
- graceExpiryTime: session.graceExpiryTime
1266
- };
1267
- }
1268
- var SessionStateGraph = {
1269
- entrypoints: {
1270
- NoConnection: (to, from, listeners, options, protocolVersion, tracer, log) => {
1271
- const id = `session-${generateId()}`;
1272
- const telemetry = createSessionTelemetryInfo(tracer, id, to, from);
1273
- const sendBuffer = [];
1274
- const session = new SessionNoConnection({
1275
- listeners,
1276
- id,
1277
- from,
1278
- to,
1279
- seq: 0,
1280
- ack: 0,
1281
- seqSent: 0,
1282
- graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
1283
- sendBuffer,
1284
- telemetry,
1285
- options,
1286
- protocolVersion,
1287
- tracer,
1288
- log,
1289
- codec: new CodecMessageAdapter(options.codec)
1290
- });
1291
- session.log?.info(`session ${session.id} created in NoConnection state`, {
1292
- ...session.loggingMetadata,
1293
- tags: ["state-transition"]
1294
- });
1295
- return session;
1296
- },
1297
- WaitingForHandshake: (from, conn, listeners, options, tracer, log) => {
1298
- const session = new SessionWaitingForHandshake({
1299
- conn,
1300
- listeners,
1301
- from,
1302
- options,
1303
- tracer,
1304
- log,
1305
- codec: new CodecMessageAdapter(options.codec)
1306
- });
1307
- session.log?.info(`session created in WaitingForHandshake state`, {
1308
- ...session.loggingMetadata,
1309
- tags: ["state-transition"]
1310
- });
1311
- return session;
1312
- }
1313
- },
1314
- // All of the transitions 'move'/'consume' the old session and return a new one.
1315
- // After a session is transitioned, any usage of the old session will throw.
1316
- transition: {
1317
- // happy path transitions
1318
- NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
1319
- const carriedState = inheritSharedSessionWithGrace(oldSession);
1320
- oldSession._handleStateExit();
1321
- const session = new SessionBackingOff({
1322
- backoffMs,
1323
- listeners,
1324
- ...carriedState
1325
- });
1326
- session.log?.info(
1327
- `session ${session.id} transition from NoConnection to BackingOff`,
1328
- {
1329
- ...session.loggingMetadata,
1330
- tags: ["state-transition"]
1331
- }
1332
- );
1333
- return session;
1334
- },
1335
- BackingOffToConnecting: (oldSession, connPromise, listeners) => {
1336
- const carriedState = inheritSharedSessionWithGrace(oldSession);
1337
- oldSession._handleStateExit();
1338
- const session = new SessionConnecting({
1339
- connPromise,
1340
- listeners,
1341
- ...carriedState
1342
- });
1343
- session.log?.info(
1344
- `session ${session.id} transition from BackingOff to Connecting`,
1345
- {
1346
- ...session.loggingMetadata,
1347
- tags: ["state-transition"]
1348
- }
1349
- );
1350
- return session;
1351
- },
1352
- ConnectingToHandshaking: (oldSession, conn, listeners) => {
1353
- const carriedState = inheritSharedSessionWithGrace(oldSession);
1354
- oldSession._handleStateExit();
1355
- const session = new SessionHandshaking({
1356
- conn,
1357
- listeners,
1358
- ...carriedState
1359
- });
1360
- conn.telemetry = createConnectionTelemetryInfo(
1361
- session.tracer,
1362
- conn,
1363
- session.telemetry
1364
- );
1365
- session.log?.info(
1366
- `session ${session.id} transition from Connecting to Handshaking`,
1367
- {
1368
- ...session.loggingMetadata,
1369
- tags: ["state-transition"]
1370
- }
1371
- );
1372
- return session;
1373
- },
1374
- HandshakingToConnected: (oldSession, listeners) => {
1375
- const carriedState = inheritSharedSession(oldSession);
1376
- const conn = oldSession.conn;
1377
- oldSession._handleStateExit();
1378
- const session = new SessionConnected({
1379
- conn,
1380
- listeners,
1381
- ...carriedState
1382
- });
1383
- session.startMissingHeartbeatTimeout();
1384
- session.log?.info(
1385
- `session ${session.id} transition from Handshaking to Connected`,
1386
- {
1387
- ...session.loggingMetadata,
1388
- tags: ["state-transition"]
1389
- }
1390
- );
1391
- return session;
1392
- },
1393
- WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) => {
1394
- const conn = pendingSession.conn;
1395
- const { from, options } = pendingSession;
1396
- const carriedState = oldSession ? (
1397
- // old session exists, inherit state
1398
- inheritSharedSession(oldSession)
1399
- ) : (
1400
- // old session does not exist, create new state
1401
- {
1402
- id: sessionId,
1403
- from,
1404
- to,
1405
- seq: 0,
1406
- ack: 0,
1407
- seqSent: 0,
1408
- sendBuffer: [],
1409
- telemetry: createSessionTelemetryInfo(
1410
- pendingSession.tracer,
1411
- sessionId,
1412
- to,
1413
- from,
1414
- propagationCtx
1415
- ),
1416
- options,
1417
- tracer: pendingSession.tracer,
1418
- log: pendingSession.log,
1419
- protocolVersion,
1420
- codec: new CodecMessageAdapter(options.codec)
1421
- }
1422
- );
1423
- pendingSession._handleStateExit();
1424
- oldSession?._handleStateExit();
1425
- const session = new SessionConnected({
1426
- conn,
1427
- listeners,
1428
- ...carriedState
1429
- });
1430
- session.startMissingHeartbeatTimeout();
1431
- conn.telemetry = createConnectionTelemetryInfo(
1432
- session.tracer,
1433
- conn,
1434
- session.telemetry
1435
- );
1436
- session.log?.info(
1437
- `session ${session.id} transition from WaitingForHandshake to Connected`,
1438
- {
1439
- ...session.loggingMetadata,
1440
- tags: ["state-transition"]
1441
- }
1442
- );
1443
- return session;
1444
- },
1445
- // disconnect paths
1446
- BackingOffToNoConnection: (oldSession, listeners) => {
1447
- const carriedState = inheritSharedSessionWithGrace(oldSession);
1448
- oldSession._handleStateExit();
1449
- const session = new SessionNoConnection({
1450
- listeners,
1451
- ...carriedState
1452
- });
1453
- session.log?.info(
1454
- `session ${session.id} transition from BackingOff to NoConnection`,
1455
- {
1456
- ...session.loggingMetadata,
1457
- tags: ["state-transition"]
1458
- }
1459
- );
1460
- return session;
1461
- },
1462
- ConnectingToNoConnection: (oldSession, listeners) => {
1463
- const carriedState = inheritSharedSessionWithGrace(oldSession);
1464
- oldSession.bestEffortClose();
1465
- oldSession._handleStateExit();
1466
- const session = new SessionNoConnection({
1467
- listeners,
1468
- ...carriedState
1469
- });
1470
- session.log?.info(
1471
- `session ${session.id} transition from Connecting to NoConnection`,
1472
- {
1473
- ...session.loggingMetadata,
1474
- tags: ["state-transition"]
1475
- }
1476
- );
1477
- return session;
1478
- },
1479
- HandshakingToNoConnection: (oldSession, listeners) => {
1480
- const carriedState = inheritSharedSessionWithGrace(oldSession);
1481
- oldSession.conn.close();
1482
- oldSession._handleStateExit();
1483
- const session = new SessionNoConnection({
1484
- listeners,
1485
- ...carriedState
1486
- });
1487
- session.log?.info(
1488
- `session ${session.id} transition from Handshaking to NoConnection`,
1489
- {
1490
- ...session.loggingMetadata,
1491
- tags: ["state-transition"]
1492
- }
1493
- );
1494
- return session;
1495
- },
1496
- ConnectedToNoConnection: (oldSession, listeners) => {
1497
- const carriedState = inheritSharedSession(oldSession);
1498
- const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
1499
- oldSession.conn.close();
1500
- oldSession._handleStateExit();
1501
- const session = new SessionNoConnection({
1502
- listeners,
1503
- graceExpiryTime,
1504
- ...carriedState
1505
- });
1506
- session.log?.info(
1507
- `session ${session.id} transition from Connected to NoConnection`,
1508
- {
1509
- ...session.loggingMetadata,
1510
- tags: ["state-transition"]
1511
- }
1512
- );
1513
- return session;
1514
- }
1515
- }
1516
- };
1517
- var transitions = SessionStateGraph.transition;
1518
- var ClientSessionStateGraph = {
1519
- entrypoint: SessionStateGraph.entrypoints.NoConnection,
1520
- transition: {
1521
- // happy paths
1522
- // NoConnection -> BackingOff: attempt to connect
1523
- NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
1524
- // BackingOff -> Connecting: backoff period elapsed, start connection
1525
- BackingOffToConnecting: transitions.BackingOffToConnecting,
1526
- // Connecting -> Handshaking: connection established, start handshake
1527
- ConnectingToHandshaking: transitions.ConnectingToHandshaking,
1528
- // Handshaking -> Connected: handshake complete, session ready
1529
- HandshakingToConnected: transitions.HandshakingToConnected,
1530
- // disconnect paths
1531
- // BackingOff -> NoConnection: unused
1532
- BackingOffToNoConnection: transitions.BackingOffToNoConnection,
1533
- // Connecting -> NoConnection: connection failed or connection timeout
1534
- ConnectingToNoConnection: transitions.ConnectingToNoConnection,
1535
- // Handshaking -> NoConnection: connection closed or handshake timeout
1536
- HandshakingToNoConnection: transitions.HandshakingToNoConnection,
1537
- // Connected -> NoConnection: connection closed
1538
- ConnectedToNoConnection: transitions.ConnectedToNoConnection
1539
- // destroy/close paths
1540
- // NoConnection -> x: grace period elapsed
1541
- // BackingOff -> x: grace period elapsed
1542
- // Connecting -> x: grace period elapsed
1543
- // Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
1544
- // Connected -> x: grace period elapsed or invalid message
1545
- }
1546
- };
1547
- var ServerSessionStateGraph = {
1548
- entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
1549
- transition: {
1550
- // happy paths
1551
- // WaitingForHandshake -> Connected: handshake complete, session ready
1552
- WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
1553
- // disconnect paths
1554
- // Connected -> NoConnection: connection closed
1555
- ConnectedToNoConnection: transitions.ConnectedToNoConnection
1556
- // destroy/close paths
1557
- // WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
1558
- }
1559
- };
1560
-
1561
- // transport/transport.ts
1562
- var Transport = class {
1563
- /**
1564
- * The status of the transport.
1565
- */
1566
- status;
1567
- /**
1568
- * The client ID of this transport.
1569
- */
1570
- clientId;
1571
- /**
1572
- * The event dispatcher for handling events of type EventTypes.
1573
- */
1574
- eventDispatcher;
1575
- /**
1576
- * The options for this transport.
1577
- */
1578
- options;
1579
- log;
1580
- tracer;
1581
- sessions;
1582
- /**
1583
- * Creates a new Transport instance.
1584
- * @param codec The codec used to encode and decode messages.
1585
- * @param clientId The client ID of this transport.
1586
- */
1587
- constructor(clientId, providedOptions) {
1588
- this.options = { ...defaultTransportOptions, ...providedOptions };
1589
- this.eventDispatcher = new EventDispatcher();
1590
- this.clientId = clientId;
1591
- this.status = "open";
1592
- this.sessions = /* @__PURE__ */ new Map();
1593
- this.tracer = getTracer();
1594
- }
1595
- bindLogger(fn, level) {
1596
- if (typeof fn === "function") {
1597
- this.log = createLogProxy(new BaseLogger(fn, level));
1598
- return;
1599
- }
1600
- this.log = createLogProxy(fn);
1601
- }
1602
- /**
1603
- * Called when a message is received by this transport.
1604
- * You generally shouldn't need to override this in downstream transport implementations.
1605
- * @param message The received message.
1606
- */
1607
- handleMsg(message) {
1608
- if (this.getStatus() !== "open") return;
1609
- this.eventDispatcher.dispatchEvent("message", message);
1610
- }
1611
- /**
1612
- * Adds a listener to this transport.
1613
- * @param the type of event to listen for
1614
- * @param handler The message handler to add.
1615
- */
1616
- addEventListener(type, handler) {
1617
- this.eventDispatcher.addEventListener(type, handler);
1618
- }
1619
- /**
1620
- * Removes a listener from this transport.
1621
- * @param the type of event to un-listen on
1622
- * @param handler The message handler to remove.
1623
- */
1624
- removeEventListener(type, handler) {
1625
- this.eventDispatcher.removeEventListener(type, handler);
1626
- }
1627
- protocolError(message) {
1628
- this.eventDispatcher.dispatchEvent("protocolError", message);
1629
- }
1630
- /**
1631
- * Default close implementation for transports. You should override this in the downstream
1632
- * implementation if you need to do any additional cleanup and call super.close() at the end.
1633
- * Closes the transport. Any messages sent while the transport is closed will be silently discarded.
1634
- */
1635
- close() {
1636
- this.status = "closed";
1637
- const sessions = Array.from(this.sessions.values());
1638
- for (const session of sessions) {
1639
- this.deleteSession(session);
1640
- }
1641
- this.eventDispatcher.dispatchEvent("transportStatus", {
1642
- status: this.status
1643
- });
1644
- this.eventDispatcher.removeAllListeners();
1645
- this.log?.info(`manually closed transport`, { clientId: this.clientId });
1646
- }
1647
- getStatus() {
1648
- return this.status;
1649
- }
1650
- // state transitions
1651
- createSession(session) {
1652
- const activeSession = this.sessions.get(session.to);
1653
- if (activeSession) {
1654
- const msg = `attempt to create session for ${session.to} but active session (${activeSession.id}) already exists`;
1655
- this.log?.error(msg, {
1656
- ...session.loggingMetadata,
1657
- tags: ["invariant-violation"]
1658
- });
1659
- throw new Error(msg);
1660
- }
1661
- this.sessions.set(session.to, session);
1662
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1663
- status: "created",
1664
- session
1665
- });
1666
- this.eventDispatcher.dispatchEvent("sessionTransition", {
1667
- state: session.state,
1668
- id: session.id
1669
- });
1670
- }
1671
- updateSession(session) {
1672
- const activeSession = this.sessions.get(session.to);
1673
- if (!activeSession) {
1674
- const msg = `attempt to transition session for ${session.to} but no active session exists`;
1675
- this.log?.error(msg, {
1676
- ...session.loggingMetadata,
1677
- tags: ["invariant-violation"]
1678
- });
1679
- throw new Error(msg);
1680
- }
1681
- if (activeSession.id !== session.id) {
1682
- const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1683
- this.log?.error(msg, {
1684
- ...session.loggingMetadata,
1685
- tags: ["invariant-violation"]
1686
- });
1687
- throw new Error(msg);
1688
- }
1689
- this.sessions.set(session.to, session);
1690
- this.eventDispatcher.dispatchEvent("sessionTransition", {
1691
- state: session.state,
1692
- id: session.id
1693
- });
1694
- }
1695
- deleteSession(session, options) {
1696
- if (session._isConsumed) return;
1697
- const loggingMetadata = session.loggingMetadata;
1698
- if (loggingMetadata.tags && options?.unhealthy) {
1699
- loggingMetadata.tags.push("unhealthy-session");
1700
- }
1701
- session.log?.info(`closing session ${session.id}`, loggingMetadata);
1702
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1703
- status: "closing",
1704
- session
1705
- });
1706
- const to = session.to;
1707
- session.close();
1708
- this.sessions.delete(to);
1709
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1710
- status: "closed",
1711
- session: { id: session.id, to }
1712
- });
1713
- }
1714
- // common listeners
1715
- onSessionGracePeriodElapsed(session) {
1716
- this.log?.info(
1717
- `session to ${session.to} grace period elapsed, closing`,
1718
- session.loggingMetadata
1719
- );
1720
- this.deleteSession(session);
1721
- }
1722
- onConnectingFailed(session) {
1723
- const noConnectionSession = SessionStateGraph.transition.ConnectingToNoConnection(session, {
1724
- onSessionGracePeriodElapsed: () => {
1725
- this.onSessionGracePeriodElapsed(noConnectionSession);
1726
- },
1727
- onMessageSendFailure: (msg, reason) => {
1728
- this.log?.error(`failed to send message: ${reason}`, {
1729
- ...noConnectionSession.loggingMetadata,
1730
- transportMessage: msg
1731
- });
1732
- this.protocolError({
1733
- type: ProtocolError.MessageSendFailure,
1734
- message: reason
1735
- });
1736
- this.deleteSession(noConnectionSession, { unhealthy: true });
1737
- }
1738
- });
1739
- this.updateSession(noConnectionSession);
1740
- return noConnectionSession;
1741
- }
1742
- onConnClosed(session) {
1743
- let noConnectionSession;
1744
- const listeners = {
1745
- onSessionGracePeriodElapsed: () => {
1746
- this.onSessionGracePeriodElapsed(noConnectionSession);
1747
- },
1748
- onMessageSendFailure: (msg, reason) => {
1749
- this.log?.error(`failed to send message: ${reason}`, {
1750
- ...noConnectionSession.loggingMetadata,
1751
- transportMessage: msg
1752
- });
1753
- this.protocolError({
1754
- type: ProtocolError.MessageSendFailure,
1755
- message: reason
1756
- });
1757
- this.deleteSession(noConnectionSession, { unhealthy: true });
1758
- }
1759
- };
1760
- if (session.state === "Handshaking" /* Handshaking */) {
1761
- noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(
1762
- session,
1763
- listeners
1764
- );
1765
- } else {
1766
- noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(
1767
- session,
1768
- listeners
1769
- );
1770
- }
1771
- this.updateSession(noConnectionSession);
1772
- return noConnectionSession;
1773
- }
1774
- /**
1775
- * Gets a send closure scoped to a specific session. Sending using the returned
1776
- * closure after the session has transitioned to a different state will be a noop.
1777
- *
1778
- * Session objects themselves can become stale as they transition between
1779
- * states. As stale sessions cannot be used again (and will throw), holding
1780
- * onto a session object is not recommended.
1781
- */
1782
- getSessionBoundSendFn(to, sessionId) {
1783
- if (this.getStatus() !== "open") {
1784
- throw new Error("cannot get a bound send function on a closed transport");
1785
- }
1786
- return (msg) => {
1787
- const session = this.sessions.get(to);
1788
- if (!session) {
1789
- throw new Error(
1790
- `session scope for ${sessionId} has ended (close), can't send`
1791
- );
1792
- }
1793
- const sameSession = session.id === sessionId;
1794
- if (!sameSession || session._isConsumed) {
1795
- throw new Error(
1796
- `session scope for ${sessionId} has ended (transition), can't send`
1797
- );
1798
- }
1799
- const res = session.send(msg);
1800
- if (!res.ok) {
1801
- throw new Error(res.reason);
1802
- }
1803
- return res.value;
1804
- };
1805
- }
1806
- };
1807
-
1808
- // transport/client.ts
1809
- var import_value2 = require("@sinclair/typebox/value");
1810
- var ClientTransport = class extends Transport {
1811
- /**
1812
- * The options for this transport.
1813
- */
1814
- options;
1815
- retryBudget;
1816
- /**
1817
- * A flag indicating whether the transport should automatically reconnect
1818
- * when a connection is dropped.
1819
- * Realistically, this should always be true for clients unless you are writing
1820
- * tests or a special case where you don't want to reconnect.
1821
- */
1822
- reconnectOnConnectionDrop = true;
1823
- /**
1824
- * Optional handshake options for this client.
1825
- */
1826
- handshakeExtensions;
1827
- sessions;
1828
- constructor(clientId, providedOptions) {
1829
- super(clientId, providedOptions);
1830
- this.sessions = /* @__PURE__ */ new Map();
1831
- this.options = {
1832
- ...defaultClientTransportOptions,
1833
- ...providedOptions
1834
- };
1835
- this.retryBudget = new LeakyBucketRateLimit(this.options);
1836
- }
1837
- extendHandshake(options) {
1838
- this.handshakeExtensions = options;
1839
- }
1840
- tryReconnecting(to) {
1841
- const oldSession = this.sessions.get(to);
1842
- if (!this.options.enableTransparentSessionReconnects && oldSession) {
1843
- this.deleteSession(oldSession);
1844
- }
1845
- if (this.reconnectOnConnectionDrop && this.getStatus() === "open") {
1846
- this.connect(to);
1847
- }
1848
- }
1849
- /*
1850
- * Creates a raw unconnected session object.
1851
- * This is mostly a River internal, you shouldn't need to use this directly.
1852
- */
1853
- createUnconnectedSession(to) {
1854
- const session = ClientSessionStateGraph.entrypoint(
1855
- to,
1856
- this.clientId,
1857
- {
1858
- onSessionGracePeriodElapsed: () => {
1859
- this.onSessionGracePeriodElapsed(session);
1860
- },
1861
- onMessageSendFailure: (msg, reason) => {
1862
- this.log?.error(`failed to send message: ${reason}`, {
1863
- ...session.loggingMetadata,
1864
- transportMessage: msg
1865
- });
1866
- this.protocolError({
1867
- type: ProtocolError.MessageSendFailure,
1868
- message: reason
1869
- });
1870
- this.deleteSession(session, { unhealthy: true });
1871
- }
1872
- },
1873
- this.options,
1874
- currentProtocolVersion,
1875
- this.tracer,
1876
- this.log
1877
- );
1878
- this.createSession(session);
1879
- return session;
1880
- }
1881
- // listeners
1882
- onConnectingFailed(session) {
1883
- const noConnectionSession = super.onConnectingFailed(session);
1884
- this.tryReconnecting(noConnectionSession.to);
1885
- return noConnectionSession;
1886
- }
1887
- onConnClosed(session) {
1888
- const noConnectionSession = super.onConnClosed(session);
1889
- this.tryReconnecting(noConnectionSession.to);
1890
- return noConnectionSession;
1891
- }
1892
- onConnectionEstablished(session, conn) {
1893
- const handshakingSession = ClientSessionStateGraph.transition.ConnectingToHandshaking(
1894
- session,
1895
- conn,
1896
- {
1897
- onConnectionErrored: (err) => {
1898
- const errStr = coerceErrorString(err);
1899
- this.log?.error(
1900
- `connection to ${handshakingSession.to} errored during handshake: ${errStr}`,
1901
- handshakingSession.loggingMetadata
1902
- );
1903
- },
1904
- onConnectionClosed: () => {
1905
- this.log?.warn(
1906
- `connection to ${handshakingSession.to} closed during handshake`,
1907
- handshakingSession.loggingMetadata
1908
- );
1909
- this.onConnClosed(handshakingSession);
1910
- },
1911
- onHandshake: (msg) => {
1912
- this.onHandshakeResponse(handshakingSession, msg);
1913
- },
1914
- onInvalidHandshake: (reason, code) => {
1915
- this.log?.error(
1916
- `invalid handshake: ${reason}`,
1917
- handshakingSession.loggingMetadata
1918
- );
1919
- this.deleteSession(session, { unhealthy: true });
1920
- this.protocolError({
1921
- type: ProtocolError.HandshakeFailed,
1922
- code,
1923
- message: reason
1924
- });
1925
- },
1926
- onHandshakeTimeout: () => {
1927
- this.log?.error(
1928
- `connection to ${handshakingSession.to} timed out during handshake`,
1929
- handshakingSession.loggingMetadata
1930
- );
1931
- this.onConnClosed(handshakingSession);
1932
- },
1933
- onSessionGracePeriodElapsed: () => {
1934
- this.onSessionGracePeriodElapsed(handshakingSession);
1935
- },
1936
- onMessageSendFailure: (msg, reason) => {
1937
- this.log?.error(`failed to send message: ${reason}`, {
1938
- ...handshakingSession.loggingMetadata,
1939
- transportMessage: msg
1940
- });
1941
- this.protocolError({
1942
- type: ProtocolError.MessageSendFailure,
1943
- message: reason
1944
- });
1945
- this.deleteSession(handshakingSession, { unhealthy: true });
1946
- }
1947
- }
1948
- );
1949
- this.updateSession(handshakingSession);
1950
- void this.sendHandshake(handshakingSession);
1951
- return handshakingSession;
1952
- }
1953
- rejectHandshakeResponse(session, reason, metadata) {
1954
- session.conn.telemetry?.span.setStatus({
1955
- code: import_api4.SpanStatusCode.ERROR,
1956
- message: reason
1957
- });
1958
- this.log?.warn(reason, metadata);
1959
- this.deleteSession(session, { unhealthy: true });
1960
- }
1961
- onHandshakeResponse(session, msg) {
1962
- if (!import_value2.Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
1963
- const reason = `received invalid handshake response`;
1964
- this.rejectHandshakeResponse(session, reason, {
1965
- ...session.loggingMetadata,
1966
- transportMessage: msg,
1967
- validationErrors: [
1968
- ...import_value2.Value.Errors(ControlMessageHandshakeResponseSchema, msg.payload)
1969
- ]
1970
- });
1971
- return;
1972
- }
1973
- if (!msg.payload.status.ok) {
1974
- const retriable = import_value2.Value.Check(
1975
- HandshakeErrorRetriableResponseCodes,
1976
- msg.payload.status.code
1977
- );
1978
- const reason = `handshake failed: ${msg.payload.status.reason}`;
1979
- const to = session.to;
1980
- this.rejectHandshakeResponse(session, reason, {
1981
- ...session.loggingMetadata,
1982
- transportMessage: msg
1983
- });
1984
- if (retriable) {
1985
- this.tryReconnecting(to);
1986
- } else {
1987
- this.protocolError({
1988
- type: ProtocolError.HandshakeFailed,
1989
- code: msg.payload.status.code,
1990
- message: reason
1991
- });
1992
- }
1993
- return;
1994
- }
1995
- if (msg.payload.status.sessionId !== session.id) {
1996
- const reason = `session id mismatch: expected ${session.id}, got ${msg.payload.status.sessionId}`;
1997
- this.rejectHandshakeResponse(session, reason, {
1998
- ...session.loggingMetadata,
1999
- transportMessage: msg
2000
- });
2001
- return;
2002
- }
2003
- this.log?.info(`handshake from ${msg.from} ok`, {
2004
- ...session.loggingMetadata,
2005
- transportMessage: msg
2006
- });
2007
- const connectedSession = ClientSessionStateGraph.transition.HandshakingToConnected(session, {
2008
- onConnectionErrored: (err) => {
2009
- const errStr = coerceErrorString(err);
2010
- if (err instanceof Error && this.options.isFatalConnectionError(err)) {
2011
- this.log?.warn(
2012
- `connection to ${connectedSession.to} fatally errored: ${errStr}`,
2013
- connectedSession.loggingMetadata
2014
- );
2015
- this.reconnectOnConnectionDrop = false;
2016
- } else {
2017
- this.log?.warn(
2018
- `connection to ${connectedSession.to} errored: ${errStr}`,
2019
- connectedSession.loggingMetadata
2020
- );
2021
- }
2022
- },
2023
- onConnectionClosed: () => {
2024
- this.log?.info(
2025
- `connection to ${connectedSession.to} closed`,
2026
- connectedSession.loggingMetadata
2027
- );
2028
- this.onConnClosed(connectedSession);
2029
- },
2030
- onMessage: (msg2) => {
2031
- this.handleMsg(msg2);
2032
- },
2033
- onInvalidMessage: (reason) => {
2034
- this.log?.error(`invalid message: ${reason}`, {
2035
- ...connectedSession.loggingMetadata,
2036
- transportMessage: msg
2037
- });
2038
- this.protocolError({
2039
- type: ProtocolError.InvalidMessage,
2040
- message: reason
2041
- });
2042
- this.deleteSession(connectedSession, { unhealthy: true });
2043
- },
2044
- onMessageSendFailure: (msg2, reason) => {
2045
- this.log?.error(`failed to send message: ${reason}`, {
2046
- ...connectedSession.loggingMetadata,
2047
- transportMessage: msg2
2048
- });
2049
- this.protocolError({
2050
- type: ProtocolError.MessageSendFailure,
2051
- message: reason
2052
- });
2053
- this.deleteSession(connectedSession, { unhealthy: true });
2054
- }
2055
- });
2056
- const res = connectedSession.sendBufferedMessages();
2057
- if (!res.ok) {
2058
- return;
2059
- }
2060
- this.updateSession(connectedSession);
2061
- this.retryBudget.startRestoringBudget();
2062
- }
2063
- /**
2064
- * Manually attempts to connect to a client.
2065
- * @param to The client ID of the node to connect to.
2066
- */
2067
- connect(to) {
2068
- if (this.getStatus() !== "open") {
2069
- this.log?.info(
2070
- `transport state is no longer open, cancelling attempt to connect to ${to}`
2071
- );
2072
- return;
2073
- }
2074
- const session = this.sessions.get(to) ?? this.createUnconnectedSession(to);
2075
- if (session.state !== "NoConnection" /* NoConnection */) {
2076
- this.log?.debug(
2077
- `session to ${to} has state ${session.state}, skipping connect attempt`,
2078
- session.loggingMetadata
2079
- );
2080
- return;
2081
- }
2082
- if (!this.retryBudget.hasBudget()) {
2083
- const budgetConsumed = this.retryBudget.getBudgetConsumed();
2084
- const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
2085
- this.log?.error(errMsg, session.loggingMetadata);
2086
- this.protocolError({
2087
- type: ProtocolError.RetriesExceeded,
2088
- message: errMsg
2089
- });
2090
- return;
2091
- }
2092
- const backoffMs = this.retryBudget.getBackoffMs();
2093
- this.log?.info(
2094
- `attempting connection to ${to} (${backoffMs}ms backoff)`,
2095
- session.loggingMetadata
2096
- );
2097
- this.retryBudget.consumeBudget();
2098
- const backingOffSession = ClientSessionStateGraph.transition.NoConnectionToBackingOff(
2099
- session,
2100
- backoffMs,
2101
- {
2102
- onBackoffFinished: () => {
2103
- this.onBackoffFinished(backingOffSession);
2104
- },
2105
- onSessionGracePeriodElapsed: () => {
2106
- this.onSessionGracePeriodElapsed(backingOffSession);
2107
- },
2108
- onMessageSendFailure: (msg, reason) => {
2109
- this.log?.error(`failed to send message: ${reason}`, {
2110
- ...backingOffSession.loggingMetadata,
2111
- transportMessage: msg
2112
- });
2113
- this.protocolError({
2114
- type: ProtocolError.MessageSendFailure,
2115
- message: reason
2116
- });
2117
- this.deleteSession(backingOffSession, { unhealthy: true });
2118
- }
2119
- }
2120
- );
2121
- this.updateSession(backingOffSession);
2122
- }
2123
- /**
2124
- * Manually kills all sessions to the server (including all pending state).
2125
- * This is useful for when you want to close all connections to a server
2126
- * and don't want to wait for the grace period to elapse.
2127
- */
2128
- hardDisconnect() {
2129
- const sessions = Array.from(this.sessions.values());
2130
- for (const session of sessions) {
2131
- this.deleteSession(session);
2132
- }
2133
- }
2134
- onBackoffFinished(session) {
2135
- const connPromise = session.tracer.startActiveSpan(
2136
- "connect",
2137
- async (span) => {
2138
- try {
2139
- return await this.createNewOutgoingConnection(session.to);
2140
- } catch (err) {
2141
- const errStr = coerceErrorString(err);
2142
- span.recordException(errStr);
2143
- span.setStatus({ code: import_api4.SpanStatusCode.ERROR });
2144
- throw err;
2145
- } finally {
2146
- span.end();
2147
- }
2148
- }
2149
- );
2150
- const connectingSession = ClientSessionStateGraph.transition.BackingOffToConnecting(
2151
- session,
2152
- connPromise,
2153
- {
2154
- onConnectionEstablished: (conn) => {
2155
- this.log?.debug(
2156
- `connection to ${connectingSession.to} established`,
2157
- {
2158
- ...conn.loggingMetadata,
2159
- ...connectingSession.loggingMetadata
2160
- }
2161
- );
2162
- this.onConnectionEstablished(connectingSession, conn);
2163
- },
2164
- onConnectionFailed: (error) => {
2165
- const errStr = coerceErrorString(error);
2166
- this.log?.error(
2167
- `error connecting to ${connectingSession.to}: ${errStr}`,
2168
- connectingSession.loggingMetadata
2169
- );
2170
- this.onConnectingFailed(connectingSession);
2171
- },
2172
- onConnectionTimeout: () => {
2173
- this.log?.error(
2174
- `connection to ${connectingSession.to} timed out`,
2175
- connectingSession.loggingMetadata
2176
- );
2177
- this.onConnectingFailed(connectingSession);
2178
- },
2179
- onSessionGracePeriodElapsed: () => {
2180
- this.onSessionGracePeriodElapsed(connectingSession);
2181
- },
2182
- onMessageSendFailure: (msg, reason) => {
2183
- this.log?.error(`failed to send message: ${reason}`, {
2184
- ...connectingSession.loggingMetadata,
2185
- transportMessage: msg
2186
- });
2187
- this.protocolError({
2188
- type: ProtocolError.MessageSendFailure,
2189
- message: reason
2190
- });
2191
- this.deleteSession(connectingSession, { unhealthy: true });
2192
- }
2193
- }
2194
- );
2195
- this.updateSession(connectingSession);
2196
- }
2197
- async sendHandshake(session) {
2198
- let metadata = void 0;
2199
- if (this.handshakeExtensions) {
2200
- try {
2201
- metadata = await this.handshakeExtensions.construct();
2202
- } catch (err) {
2203
- const errStr = coerceErrorString(err);
2204
- this.log?.error(
2205
- `failed to construct handshake metadata for session to ${session.to}: ${errStr}`,
2206
- session.loggingMetadata
2207
- );
2208
- this.protocolError({
2209
- type: ProtocolError.HandshakeFailed,
2210
- message: `failed to construct handshake metadata: ${errStr}`
2211
- });
2212
- this.deleteSession(session, { unhealthy: true });
2213
- return;
2214
- }
2215
- }
2216
- if (session._isConsumed) {
2217
- return;
2218
- }
2219
- const requestMsg = handshakeRequestMessage({
2220
- from: this.clientId,
2221
- to: session.to,
2222
- sessionId: session.id,
2223
- expectedSessionState: {
2224
- nextExpectedSeq: session.ack,
2225
- nextSentSeq: session.nextSeq()
2226
- },
2227
- metadata,
2228
- tracing: getPropagationContext(session.telemetry.ctx)
2229
- });
2230
- this.log?.debug(`sending handshake request to ${session.to}`, {
2231
- ...session.loggingMetadata,
2232
- transportMessage: requestMsg
2233
- });
2234
- const res = session.sendHandshake(requestMsg);
2235
- if (!res.ok) {
2236
- this.log?.error(`failed to send handshake request: ${res.reason}`, {
2237
- ...session.loggingMetadata,
2238
- transportMessage: requestMsg
2239
- });
2240
- this.protocolError({
2241
- type: ProtocolError.MessageSendFailure,
2242
- message: res.reason
2243
- });
2244
- this.deleteSession(session, { unhealthy: true });
2245
- }
2246
- }
2247
- close() {
2248
- this.retryBudget.close();
2249
- super.close();
2250
- }
2251
- };
2252
-
2253
- // transport/impls/ws/client.ts
2254
- var WebSocketClientTransport = class extends ClientTransport {
2255
- /**
2256
- * A function that returns a Promise that resolves to a websocket URL.
2257
- */
2258
- wsGetter;
2259
- /**
2260
- * Creates a new WebSocketClientTransport instance.
2261
- * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
2262
- * @param clientId The ID of the client using the transport. This should be unique per session.
2263
- * @param serverId The ID of the server this transport is connecting to.
2264
- * @param providedOptions An optional object containing configuration options for the transport.
2265
- */
2266
- constructor(wsGetter, clientId, providedOptions) {
2267
- super(clientId, providedOptions);
2268
- this.wsGetter = wsGetter;
2269
- }
2270
- async createNewOutgoingConnection(to) {
2271
- this.log?.info(`establishing a new websocket to ${to}`, {
2272
- clientId: this.clientId,
2273
- connectedTo: to
2274
- });
2275
- const ws = await this.wsGetter(to);
2276
- await new Promise((resolve, reject) => {
2277
- if (ws.readyState === ws.OPEN) {
2278
- resolve();
2279
- return;
2280
- }
2281
- if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
2282
- reject(new Error("ws is closing or closed"));
2283
- return;
2284
- }
2285
- ws.onopen = () => {
2286
- resolve();
2287
- };
2288
- ws.onclose = (evt) => {
2289
- reject(new Error(evt.reason));
2290
- };
2291
- ws.onerror = (err) => {
2292
- reject(new Error(err.message));
2293
- };
2294
- });
2295
- const conn = new WebSocketConnection(ws);
2296
- this.log?.info(`raw websocket to ${to} ok`, {
2297
- clientId: this.clientId,
2298
- connectedTo: to,
2299
- ...conn.loggingMetadata
2300
- });
2301
- return conn;
2302
- }
2303
- };
2304
- // Annotate the CommonJS export names for ESM import in node:
2305
- 0 && (module.exports = {
2306
- WebSocketClientTransport
2307
- });
2308
- //# sourceMappingURL=client.cjs.map