@replit/river 0.23.12 → 0.23.14

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 (75) hide show
  1. package/dist/{chunk-3AW3IXVD.js → chunk-4PVU7J25.js} +1 -21
  2. package/dist/chunk-4PVU7J25.js.map +1 -0
  3. package/dist/{chunk-HDBVL7EF.js → chunk-BEALFLCB.js} +2 -2
  4. package/dist/chunk-D2DHRRBN.js +476 -0
  5. package/dist/chunk-D2DHRRBN.js.map +1 -0
  6. package/dist/{chunk-7RUKEUKE.js → chunk-GCCRVSMR.js} +33 -4
  7. package/dist/chunk-GCCRVSMR.js.map +1 -0
  8. package/dist/{chunk-XZ6IOBM5.js → chunk-GN4YEXT7.js} +2 -2
  9. package/dist/chunk-GN4YEXT7.js.map +1 -0
  10. package/dist/chunk-O2AVDJCQ.js +335 -0
  11. package/dist/chunk-O2AVDJCQ.js.map +1 -0
  12. package/dist/chunk-OTVTKAN6.js +451 -0
  13. package/dist/chunk-OTVTKAN6.js.map +1 -0
  14. package/dist/chunk-WUL63FR6.js +335 -0
  15. package/dist/chunk-WUL63FR6.js.map +1 -0
  16. package/dist/{chunk-H6KTH6W6.js → chunk-YCLZWES2.js} +2 -2
  17. package/dist/client-e13979ac.d.ts +52 -0
  18. package/dist/codec/index.js +20 -2
  19. package/dist/codec/index.js.map +1 -1
  20. package/dist/{connection-8debd45f.d.ts → connection-5d0978ce.d.ts} +1 -1
  21. package/dist/{connection-581558f8.d.ts → connection-e57e98ea.d.ts} +1 -1
  22. package/dist/{transport-47af1c81.d.ts → handshake-5665ffd3.d.ts} +101 -153
  23. package/dist/{index-60f03cb7.d.ts → index-ea74cdbb.d.ts} +1 -1
  24. package/dist/logging/index.d.cts +1 -1
  25. package/dist/logging/index.d.ts +1 -1
  26. package/dist/router/index.cjs +16 -1
  27. package/dist/router/index.cjs.map +1 -1
  28. package/dist/router/index.d.cts +8 -6
  29. package/dist/router/index.d.ts +8 -6
  30. package/dist/router/index.js +2 -2
  31. package/dist/server-1cfc88d1.d.ts +24 -0
  32. package/dist/{services-ca72c9f8.d.ts → services-86c4d10d.d.ts} +3 -2
  33. package/dist/transport/impls/uds/client.cjs +303 -180
  34. package/dist/transport/impls/uds/client.cjs.map +1 -1
  35. package/dist/transport/impls/uds/client.d.cts +6 -5
  36. package/dist/transport/impls/uds/client.d.ts +6 -5
  37. package/dist/transport/impls/uds/client.js +6 -4
  38. package/dist/transport/impls/uds/client.js.map +1 -1
  39. package/dist/transport/impls/uds/server.cjs +396 -234
  40. package/dist/transport/impls/uds/server.cjs.map +1 -1
  41. package/dist/transport/impls/uds/server.d.cts +6 -5
  42. package/dist/transport/impls/uds/server.d.ts +6 -5
  43. package/dist/transport/impls/uds/server.js +8 -6
  44. package/dist/transport/impls/uds/server.js.map +1 -1
  45. package/dist/transport/impls/ws/client.cjs +305 -182
  46. package/dist/transport/impls/ws/client.cjs.map +1 -1
  47. package/dist/transport/impls/ws/client.d.cts +6 -5
  48. package/dist/transport/impls/ws/client.d.ts +6 -5
  49. package/dist/transport/impls/ws/client.js +6 -4
  50. package/dist/transport/impls/ws/client.js.map +1 -1
  51. package/dist/transport/impls/ws/server.cjs +350 -188
  52. package/dist/transport/impls/ws/server.cjs.map +1 -1
  53. package/dist/transport/impls/ws/server.d.cts +4 -3
  54. package/dist/transport/impls/ws/server.d.ts +4 -3
  55. package/dist/transport/impls/ws/server.js +8 -6
  56. package/dist/transport/impls/ws/server.js.map +1 -1
  57. package/dist/transport/index.cjs +338 -142
  58. package/dist/transport/index.cjs.map +1 -1
  59. package/dist/transport/index.d.cts +4 -2
  60. package/dist/transport/index.d.ts +4 -2
  61. package/dist/transport/index.js +14 -8
  62. package/dist/util/testHelpers.cjs +10 -6
  63. package/dist/util/testHelpers.cjs.map +1 -1
  64. package/dist/util/testHelpers.d.cts +5 -4
  65. package/dist/util/testHelpers.d.ts +5 -4
  66. package/dist/util/testHelpers.js +4 -5
  67. package/dist/util/testHelpers.js.map +1 -1
  68. package/package.json +13 -14
  69. package/dist/chunk-3AW3IXVD.js.map +0 -1
  70. package/dist/chunk-7RUKEUKE.js.map +0 -1
  71. package/dist/chunk-VRU4IKRT.js +0 -1392
  72. package/dist/chunk-VRU4IKRT.js.map +0 -1
  73. package/dist/chunk-XZ6IOBM5.js.map +0 -1
  74. /package/dist/{chunk-HDBVL7EF.js.map → chunk-BEALFLCB.js.map} +0 -0
  75. /package/dist/{chunk-H6KTH6W6.js.map → chunk-YCLZWES2.js.map} +0 -0
@@ -1,1392 +0,0 @@
1
- import {
2
- ControlMessageHandshakeRequestSchema,
3
- ControlMessageHandshakeResponseSchema,
4
- OpaqueTransportMessageSchema,
5
- PROTOCOL_VERSION,
6
- coerceErrorString,
7
- createConnectionTelemetryInfo,
8
- createSessionTelemetryInfo,
9
- getPropagationContext,
10
- handshakeRequestMessage,
11
- handshakeResponseMessage,
12
- isAck,
13
- tracing_default
14
- } from "./chunk-7RUKEUKE.js";
15
- import {
16
- BaseLogger,
17
- createLogProxy
18
- } from "./chunk-6LCL2ZZF.js";
19
- import {
20
- NaiveJsonCodec
21
- } from "./chunk-3AW3IXVD.js";
22
-
23
- // transport/session.ts
24
- import { customAlphabet } from "nanoid";
25
- import { SpanStatusCode } from "@opentelemetry/api";
26
- var nanoid = customAlphabet("1234567890abcdefghijklmnopqrstuvxyz", 6);
27
- var unsafeId = () => nanoid();
28
- var Connection = class {
29
- id;
30
- telemetry;
31
- constructor() {
32
- this.id = `conn-${nanoid(12)}`;
33
- }
34
- get loggingMetadata() {
35
- const metadata = { connId: this.id };
36
- const spanContext = this.telemetry?.span.spanContext();
37
- if (this.telemetry?.span.isRecording() && spanContext) {
38
- metadata.telemetry = {
39
- traceId: spanContext.traceId,
40
- spanId: spanContext.spanId
41
- };
42
- }
43
- return metadata;
44
- }
45
- };
46
- var Session = class {
47
- codec;
48
- options;
49
- telemetry;
50
- /**
51
- * The buffer of messages that have been sent but not yet acknowledged.
52
- */
53
- sendBuffer = [];
54
- /**
55
- * The active connection associated with this session
56
- */
57
- connection;
58
- /**
59
- * A connection that is currently undergoing handshaking. Used to distinguish between the active
60
- * connection, but still be able to close it if needed.
61
- */
62
- handshakingConnection;
63
- from;
64
- to;
65
- /**
66
- * The unique ID of this session.
67
- */
68
- id;
69
- /**
70
- * What the other side advertised as their session ID
71
- * for this session.
72
- */
73
- advertisedSessionId;
74
- /**
75
- * Number of messages we've sent along this session (excluding handshake and acks)
76
- */
77
- seq = 0;
78
- /**
79
- * Number of unique messages we've received this session (excluding handshake and acks)
80
- */
81
- ack = 0;
82
- /**
83
- * The grace period between when the inner connection is disconnected
84
- * and when we should consider the entire session disconnected.
85
- */
86
- disconnectionGrace;
87
- /**
88
- * Number of heartbeats we've sent without a response.
89
- */
90
- heartbeatMisses;
91
- /**
92
- * The interval for sending heartbeats.
93
- */
94
- heartbeat;
95
- log;
96
- constructor(conn, from, to, options, propagationCtx) {
97
- this.id = `session-${nanoid(12)}`;
98
- this.options = options;
99
- this.from = from;
100
- this.to = to;
101
- this.connection = conn;
102
- this.codec = options.codec;
103
- this.heartbeatMisses = 0;
104
- this.heartbeat = setInterval(
105
- () => this.sendHeartbeat(),
106
- options.heartbeatIntervalMs
107
- );
108
- this.telemetry = createSessionTelemetryInfo(this, propagationCtx);
109
- }
110
- bindLogger(log) {
111
- this.log = log;
112
- }
113
- get loggingMetadata() {
114
- const spanContext = this.telemetry.span.spanContext();
115
- return {
116
- clientId: this.from,
117
- connectedTo: this.to,
118
- sessionId: this.id,
119
- connId: this.connection?.id,
120
- telemetry: {
121
- traceId: spanContext.traceId,
122
- spanId: spanContext.spanId
123
- }
124
- };
125
- }
126
- /**
127
- * Sends a message over the session's connection.
128
- * If the connection is not ready or the message fails to send, the message can be buffered for retry unless skipped.
129
- *
130
- * @param msg The partial message to be sent, which will be constructed into a full message.
131
- * @param addToSendBuff Whether to add the message to the send buffer for retry.
132
- * @returns The full transport ID of the message that was attempted to be sent.
133
- */
134
- send(msg) {
135
- const fullMsg = this.constructMsg(msg);
136
- this.log?.debug(`sending msg`, {
137
- ...this.loggingMetadata,
138
- transportMessage: fullMsg
139
- });
140
- if (this.connection) {
141
- const ok = this.connection.send(this.codec.toBuffer(fullMsg));
142
- if (ok)
143
- return fullMsg.id;
144
- this.log?.info(
145
- `failed to send msg to ${fullMsg.to}, connection is probably dead`,
146
- {
147
- ...this.loggingMetadata,
148
- transportMessage: fullMsg
149
- }
150
- );
151
- } else {
152
- this.log?.debug(
153
- `buffering msg to ${fullMsg.to}, connection not ready yet`,
154
- { ...this.loggingMetadata, transportMessage: fullMsg }
155
- );
156
- }
157
- return fullMsg.id;
158
- }
159
- sendHeartbeat() {
160
- const misses = this.heartbeatMisses;
161
- const missDuration = misses * this.options.heartbeatIntervalMs;
162
- if (misses > this.options.heartbeatsUntilDead) {
163
- if (this.connection) {
164
- this.log?.info(
165
- `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
166
- this.loggingMetadata
167
- );
168
- this.telemetry.span.addEvent("closing connection due to inactivity");
169
- this.closeStaleConnection();
170
- }
171
- return;
172
- }
173
- this.send({
174
- streamId: "heartbeat",
175
- controlFlags: 1 /* AckBit */,
176
- payload: {
177
- type: "ACK"
178
- }
179
- });
180
- this.heartbeatMisses++;
181
- }
182
- resetBufferedMessages() {
183
- this.sendBuffer = [];
184
- this.seq = 0;
185
- this.ack = 0;
186
- }
187
- sendBufferedMessages(conn) {
188
- this.log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
189
- ...this.loggingMetadata,
190
- connId: conn.id
191
- });
192
- for (const msg of this.sendBuffer) {
193
- this.log?.debug(`resending msg`, {
194
- ...this.loggingMetadata,
195
- transportMessage: msg,
196
- connId: conn.id
197
- });
198
- const ok = conn.send(this.codec.toBuffer(msg));
199
- if (!ok) {
200
- const errMsg = `failed to send buffered message to ${this.to} (sus, this is a fresh connection)`;
201
- conn.telemetry?.span.setStatus({
202
- code: SpanStatusCode.ERROR,
203
- message: errMsg
204
- });
205
- this.log?.error(errMsg, {
206
- ...this.loggingMetadata,
207
- transportMessage: msg,
208
- connId: conn.id,
209
- tags: ["invariant-violation"]
210
- });
211
- conn.close();
212
- return;
213
- }
214
- }
215
- }
216
- updateBookkeeping(ack, seq) {
217
- if (seq + 1 < this.ack) {
218
- this.log?.error(`received stale seq ${seq} + 1 < ${this.ack}`, {
219
- ...this.loggingMetadata,
220
- tags: ["invariant-violation"]
221
- });
222
- return;
223
- }
224
- this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
225
- this.ack = seq + 1;
226
- }
227
- closeStaleConnection(conn) {
228
- if (this.connection === void 0 || this.connection === conn)
229
- return;
230
- this.log?.info(
231
- `closing old inner connection from session to ${this.to}`,
232
- this.loggingMetadata
233
- );
234
- this.connection.close();
235
- this.connection = void 0;
236
- }
237
- replaceWithNewConnection(newConn, isTransparentReconnect) {
238
- this.closeStaleConnection(newConn);
239
- this.cancelGrace();
240
- if (isTransparentReconnect) {
241
- this.sendBufferedMessages(newConn);
242
- }
243
- this.connection = newConn;
244
- this.handshakingConnection = void 0;
245
- }
246
- replaceWithNewHandshakingConnection(newConn) {
247
- this.handshakingConnection = newConn;
248
- }
249
- beginGrace(cb) {
250
- this.log?.info(
251
- `starting ${this.options.sessionDisconnectGraceMs}ms grace period until session to ${this.to} is closed`,
252
- this.loggingMetadata
253
- );
254
- this.cancelGrace();
255
- this.disconnectionGrace = setTimeout(() => {
256
- this.log?.info(
257
- `grace period for ${this.to} elapsed`,
258
- this.loggingMetadata
259
- );
260
- cb();
261
- }, this.options.sessionDisconnectGraceMs);
262
- }
263
- // called on reconnect of the underlying session
264
- cancelGrace() {
265
- this.heartbeatMisses = 0;
266
- clearTimeout(this.disconnectionGrace);
267
- this.disconnectionGrace = void 0;
268
- }
269
- /**
270
- * Used to close the handshaking connection, if set.
271
- */
272
- closeHandshakingConnection(expectedHandshakingConn) {
273
- if (this.handshakingConnection === void 0)
274
- return;
275
- if (expectedHandshakingConn !== void 0 && this.handshakingConnection === expectedHandshakingConn) {
276
- return;
277
- }
278
- this.handshakingConnection.close();
279
- this.handshakingConnection = void 0;
280
- }
281
- // closed when we want to discard the whole session
282
- // (i.e. shutdown or session disconnect)
283
- close() {
284
- this.closeStaleConnection();
285
- this.cancelGrace();
286
- this.resetBufferedMessages();
287
- clearInterval(this.heartbeat);
288
- }
289
- get connected() {
290
- return this.connection !== void 0;
291
- }
292
- get nextExpectedSeq() {
293
- return this.ack;
294
- }
295
- constructMsg(partialMsg) {
296
- const msg = {
297
- ...partialMsg,
298
- id: unsafeId(),
299
- to: this.to,
300
- from: this.from,
301
- seq: this.seq,
302
- ack: this.ack
303
- };
304
- this.seq++;
305
- this.sendBuffer.push(msg);
306
- return msg;
307
- }
308
- inspectSendBuffer() {
309
- return this.sendBuffer;
310
- }
311
- };
312
-
313
- // transport/events.ts
314
- var ProtocolError = {
315
- RetriesExceeded: "conn_retry_exceeded",
316
- HandshakeFailed: "handshake_failed",
317
- MessageOrderingViolated: "message_ordering_violated"
318
- };
319
- var EventDispatcher = class {
320
- eventListeners = {};
321
- removeAllListeners() {
322
- this.eventListeners = {};
323
- }
324
- numberOfListeners(eventType) {
325
- return this.eventListeners[eventType]?.size ?? 0;
326
- }
327
- addEventListener(eventType, handler) {
328
- if (!this.eventListeners[eventType]) {
329
- this.eventListeners[eventType] = /* @__PURE__ */ new Set();
330
- }
331
- this.eventListeners[eventType]?.add(handler);
332
- }
333
- removeEventListener(eventType, handler) {
334
- const handlers = this.eventListeners[eventType];
335
- if (handlers) {
336
- this.eventListeners[eventType]?.delete(handler);
337
- }
338
- }
339
- dispatchEvent(eventType, event) {
340
- const handlers = this.eventListeners[eventType];
341
- if (handlers) {
342
- const copy = [...handlers];
343
- for (const handler of copy) {
344
- handler(event);
345
- }
346
- }
347
- }
348
- };
349
-
350
- // transport/transport.ts
351
- import { Value } from "@sinclair/typebox/value";
352
-
353
- // transport/rateLimit.ts
354
- var LeakyBucketRateLimit = class {
355
- budgetConsumed;
356
- intervalHandles;
357
- options;
358
- constructor(options) {
359
- this.options = options;
360
- this.budgetConsumed = /* @__PURE__ */ new Map();
361
- this.intervalHandles = /* @__PURE__ */ new Map();
362
- }
363
- getBackoffMs(user) {
364
- if (!this.budgetConsumed.has(user))
365
- return 0;
366
- const exponent = Math.max(0, this.getBudgetConsumed(user) - 1);
367
- const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
368
- const backoffMs = Math.min(
369
- this.options.baseIntervalMs * 2 ** exponent,
370
- this.options.maxBackoffMs
371
- );
372
- return backoffMs + jitter;
373
- }
374
- get totalBudgetRestoreTime() {
375
- return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
376
- }
377
- consumeBudget(user) {
378
- this.stopLeak(user);
379
- this.budgetConsumed.set(user, this.getBudgetConsumed(user) + 1);
380
- }
381
- getBudgetConsumed(user) {
382
- return this.budgetConsumed.get(user) ?? 0;
383
- }
384
- hasBudget(user) {
385
- return this.getBudgetConsumed(user) < this.options.attemptBudgetCapacity;
386
- }
387
- startRestoringBudget(user) {
388
- if (this.intervalHandles.has(user)) {
389
- return;
390
- }
391
- const restoreBudgetForUser = () => {
392
- const currentBudget = this.budgetConsumed.get(user);
393
- if (!currentBudget) {
394
- this.stopLeak(user);
395
- return;
396
- }
397
- const newBudget = currentBudget - 1;
398
- if (newBudget === 0) {
399
- this.budgetConsumed.delete(user);
400
- return;
401
- }
402
- this.budgetConsumed.set(user, newBudget);
403
- };
404
- const intervalHandle = setInterval(
405
- restoreBudgetForUser,
406
- this.options.budgetRestoreIntervalMs
407
- );
408
- this.intervalHandles.set(user, intervalHandle);
409
- }
410
- stopLeak(user) {
411
- if (!this.intervalHandles.has(user)) {
412
- return;
413
- }
414
- clearInterval(this.intervalHandles.get(user));
415
- this.intervalHandles.delete(user);
416
- }
417
- close() {
418
- for (const user of this.intervalHandles.keys()) {
419
- this.stopLeak(user);
420
- }
421
- }
422
- };
423
-
424
- // transport/transport.ts
425
- import { SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
426
- var defaultTransportOptions = {
427
- heartbeatIntervalMs: 1e3,
428
- heartbeatsUntilDead: 2,
429
- sessionDisconnectGraceMs: 5e3,
430
- codec: NaiveJsonCodec
431
- };
432
- var defaultConnectionRetryOptions = {
433
- baseIntervalMs: 250,
434
- maxJitterMs: 200,
435
- maxBackoffMs: 32e3,
436
- attemptBudgetCapacity: 5,
437
- budgetRestoreIntervalMs: 200
438
- };
439
- var defaultClientTransportOptions = {
440
- ...defaultTransportOptions,
441
- ...defaultConnectionRetryOptions
442
- };
443
- var defaultServerTransportOptions = {
444
- ...defaultTransportOptions
445
- };
446
- var Transport = class {
447
- /**
448
- * The status of the transport.
449
- */
450
- status;
451
- /**
452
- * The {@link Codec} used to encode and decode messages.
453
- */
454
- codec;
455
- /**
456
- * The client ID of this transport.
457
- */
458
- clientId;
459
- /**
460
- * The map of {@link Session}s managed by this transport.
461
- */
462
- sessions;
463
- /**
464
- * The map of {@link Connection}s managed by this transport.
465
- */
466
- get connections() {
467
- return new Map(
468
- [...this.sessions].map(([client, session]) => [client, session.connection]).filter((entry) => entry[1] !== void 0)
469
- );
470
- }
471
- /**
472
- * The event dispatcher for handling events of type EventTypes.
473
- */
474
- eventDispatcher;
475
- /**
476
- * The options for this transport.
477
- */
478
- options;
479
- log;
480
- /**
481
- * Creates a new Transport instance.
482
- * This should also set up {@link onConnect}, and {@link onDisconnect} listeners.
483
- * @param codec The codec used to encode and decode messages.
484
- * @param clientId The client ID of this transport.
485
- */
486
- constructor(clientId, providedOptions) {
487
- this.options = { ...defaultTransportOptions, ...providedOptions };
488
- this.eventDispatcher = new EventDispatcher();
489
- this.sessions = /* @__PURE__ */ new Map();
490
- this.codec = this.options.codec;
491
- this.clientId = clientId;
492
- this.status = "open";
493
- }
494
- bindLogger(fn, level) {
495
- if (typeof fn === "function") {
496
- this.log = createLogProxy(new BaseLogger(fn, level));
497
- return;
498
- }
499
- this.log = createLogProxy(fn);
500
- }
501
- /**
502
- * Called when a new connection is established
503
- * and we know the identity of the connected client.
504
- * @param conn The connection object.
505
- */
506
- onConnect(conn, session, isTransparentReconnect) {
507
- this.eventDispatcher.dispatchEvent("connectionStatus", {
508
- status: "connect",
509
- conn
510
- });
511
- conn.telemetry = createConnectionTelemetryInfo(conn, session.telemetry);
512
- session.replaceWithNewConnection(conn, isTransparentReconnect);
513
- this.log?.info(`connected to ${session.to}`, {
514
- ...conn.loggingMetadata,
515
- ...session.loggingMetadata
516
- });
517
- }
518
- createSession(to, conn, propagationCtx) {
519
- const session = new Session(
520
- conn,
521
- this.clientId,
522
- to,
523
- this.options,
524
- propagationCtx
525
- );
526
- if (this.log) {
527
- session.bindLogger(this.log);
528
- }
529
- this.sessions.set(session.to, session);
530
- this.eventDispatcher.dispatchEvent("sessionStatus", {
531
- status: "connect",
532
- session
533
- });
534
- return session;
535
- }
536
- getOrCreateSession({
537
- to,
538
- conn,
539
- handshakingConn,
540
- sessionId,
541
- propagationCtx
542
- }) {
543
- let session = this.sessions.get(to);
544
- const isReconnect = session !== void 0;
545
- let isTransparentReconnect = isReconnect;
546
- if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
547
- this.log?.info(
548
- `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
549
- session.loggingMetadata
550
- );
551
- this.deleteSession({
552
- session,
553
- closeHandshakingConnection: handshakingConn !== void 0,
554
- handshakingConn
555
- });
556
- isTransparentReconnect = false;
557
- session = void 0;
558
- }
559
- if (!session) {
560
- session = this.createSession(to, conn, propagationCtx);
561
- this.log?.info(
562
- `no session for ${to}, created a new one`,
563
- session.loggingMetadata
564
- );
565
- }
566
- if (sessionId !== void 0) {
567
- session.advertisedSessionId = sessionId;
568
- }
569
- if (handshakingConn !== void 0) {
570
- session.replaceWithNewHandshakingConnection(handshakingConn);
571
- }
572
- return { session, isReconnect, isTransparentReconnect };
573
- }
574
- deleteSession({
575
- session,
576
- closeHandshakingConnection,
577
- handshakingConn
578
- }) {
579
- if (closeHandshakingConnection) {
580
- session.closeHandshakingConnection(handshakingConn);
581
- }
582
- session.close();
583
- session.telemetry.span.end();
584
- this.sessions.delete(session.to);
585
- this.log?.info(
586
- `session ${session.id} disconnect from ${session.to}`,
587
- session.loggingMetadata
588
- );
589
- this.eventDispatcher.dispatchEvent("sessionStatus", {
590
- status: "disconnect",
591
- session
592
- });
593
- }
594
- /**
595
- * The downstream implementation needs to call this when a connection is closed.
596
- * @param conn The connection object.
597
- * @param connectedTo The peer we are connected to.
598
- */
599
- onDisconnect(conn, session) {
600
- conn.telemetry?.span.end();
601
- this.eventDispatcher.dispatchEvent("connectionStatus", {
602
- status: "disconnect",
603
- conn
604
- });
605
- session.connection = void 0;
606
- session.beginGrace(() => {
607
- session.telemetry.span.addEvent("session grace period expired");
608
- this.deleteSession({
609
- session,
610
- closeHandshakingConnection: true,
611
- handshakingConn: conn
612
- });
613
- });
614
- }
615
- /**
616
- * Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
617
- * @param msg The message to parse.
618
- * @returns The parsed message, or null if the message is malformed or invalid.
619
- */
620
- parseMsg(msg, conn) {
621
- const parsedMsg = this.codec.fromBuffer(msg);
622
- if (parsedMsg === null) {
623
- const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));
624
- this.log?.error(
625
- `received malformed msg, killing conn: ${decodedBuffer}`,
626
- {
627
- clientId: this.clientId,
628
- ...conn.loggingMetadata
629
- }
630
- );
631
- return null;
632
- }
633
- if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
634
- this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
635
- clientId: this.clientId,
636
- ...conn.loggingMetadata,
637
- validationErrors: [
638
- ...Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
639
- ]
640
- });
641
- return null;
642
- }
643
- return parsedMsg;
644
- }
645
- /**
646
- * Called when a message is received by this transport.
647
- * You generally shouldn't need to override this in downstream transport implementations.
648
- * @param msg The received message.
649
- */
650
- handleMsg(msg, conn) {
651
- if (this.getStatus() !== "open")
652
- return;
653
- const session = this.sessions.get(msg.from);
654
- if (!session) {
655
- this.log?.error(`received message for unknown session from ${msg.from}`, {
656
- clientId: this.clientId,
657
- transportMessage: msg,
658
- ...conn.loggingMetadata,
659
- tags: ["invariant-violation"]
660
- });
661
- return;
662
- }
663
- session.cancelGrace();
664
- this.log?.debug(`received msg`, {
665
- clientId: this.clientId,
666
- transportMessage: msg,
667
- ...conn.loggingMetadata
668
- });
669
- if (msg.seq !== session.nextExpectedSeq) {
670
- if (msg.seq < session.nextExpectedSeq) {
671
- this.log?.debug(
672
- `received duplicate msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq}), discarding`,
673
- {
674
- clientId: this.clientId,
675
- transportMessage: msg,
676
- ...conn.loggingMetadata
677
- }
678
- );
679
- } else {
680
- const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;
681
- this.log?.error(`${errMsg}, marking connection as dead`, {
682
- clientId: this.clientId,
683
- transportMessage: msg,
684
- ...conn.loggingMetadata,
685
- tags: ["invariant-violation"]
686
- });
687
- this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
688
- session.telemetry.span.setStatus({
689
- code: SpanStatusCode2.ERROR,
690
- message: "message order violated"
691
- });
692
- this.deleteSession({ session, closeHandshakingConnection: true });
693
- }
694
- return;
695
- }
696
- session.updateBookkeeping(msg.ack, msg.seq);
697
- if (!isAck(msg.controlFlags)) {
698
- this.eventDispatcher.dispatchEvent("message", msg);
699
- } else {
700
- this.log?.debug(`discarding msg (ack bit set)`, {
701
- clientId: this.clientId,
702
- transportMessage: msg,
703
- ...conn.loggingMetadata
704
- });
705
- }
706
- }
707
- /**
708
- * Adds a listener to this transport.
709
- * @param the type of event to listen for
710
- * @param handler The message handler to add.
711
- */
712
- addEventListener(type, handler) {
713
- this.eventDispatcher.addEventListener(type, handler);
714
- }
715
- /**
716
- * Removes a listener from this transport.
717
- * @param the type of event to un-listen on
718
- * @param handler The message handler to remove.
719
- */
720
- removeEventListener(type, handler) {
721
- this.eventDispatcher.removeEventListener(type, handler);
722
- }
723
- /**
724
- * Sends a message over this transport, delegating to the appropriate connection to actually
725
- * send the message.
726
- * @param msg The message to send.
727
- * @returns The ID of the sent message or undefined if it wasn't sent
728
- */
729
- send(to, msg) {
730
- if (this.getStatus() === "closed") {
731
- const err = "transport is closed, cant send";
732
- this.log?.error(err, {
733
- clientId: this.clientId,
734
- transportMessage: msg,
735
- tags: ["invariant-violation"]
736
- });
737
- throw new Error(err);
738
- }
739
- return this.getOrCreateSession({ to }).session.send(msg);
740
- }
741
- // control helpers
742
- sendCloseStream(to, streamId) {
743
- return this.send(to, {
744
- streamId,
745
- controlFlags: 4 /* StreamClosedBit */,
746
- payload: {
747
- type: "CLOSE"
748
- }
749
- });
750
- }
751
- protocolError(type, message) {
752
- this.eventDispatcher.dispatchEvent("protocolError", { type, message });
753
- }
754
- /**
755
- * Default close implementation for transports. You should override this in the downstream
756
- * implementation if you need to do any additional cleanup and call super.close() at the end.
757
- * Closes the transport. Any messages sent while the transport is closed will be silently discarded.
758
- */
759
- close() {
760
- this.status = "closed";
761
- for (const session of this.sessions.values()) {
762
- this.deleteSession({ session, closeHandshakingConnection: true });
763
- }
764
- this.eventDispatcher.dispatchEvent("transportStatus", {
765
- status: this.status
766
- });
767
- this.eventDispatcher.removeAllListeners();
768
- this.log?.info(`manually closed transport`, { clientId: this.clientId });
769
- }
770
- getStatus() {
771
- return this.status;
772
- }
773
- };
774
- var ClientTransport = class extends Transport {
775
- /**
776
- * The options for this transport.
777
- */
778
- options;
779
- /**
780
- * The map of reconnect promises for each client ID.
781
- */
782
- inflightConnectionPromises;
783
- retryBudget;
784
- /**
785
- * A flag indicating whether the transport should automatically reconnect
786
- * when a connection is dropped.
787
- * Realistically, this should always be true for clients unless you are writing
788
- * tests or a special case where you don't want to reconnect.
789
- */
790
- reconnectOnConnectionDrop = true;
791
- /**
792
- * Optional handshake options for this client.
793
- */
794
- handshakeExtensions;
795
- constructor(clientId, providedOptions) {
796
- super(clientId, providedOptions);
797
- this.options = {
798
- ...defaultClientTransportOptions,
799
- ...providedOptions
800
- };
801
- this.inflightConnectionPromises = /* @__PURE__ */ new Map();
802
- this.retryBudget = new LeakyBucketRateLimit(this.options);
803
- }
804
- extendHandshake(options) {
805
- this.handshakeExtensions = options;
806
- }
807
- handleConnection(conn, to) {
808
- if (this.getStatus() !== "open")
809
- return;
810
- let session = void 0;
811
- const handshakeTimeout = setTimeout(() => {
812
- if (session)
813
- return;
814
- this.log?.warn(
815
- `connection to ${to} timed out waiting for handshake, closing`,
816
- { ...conn.loggingMetadata, clientId: this.clientId, connectedTo: to }
817
- );
818
- conn.close();
819
- }, this.options.sessionDisconnectGraceMs);
820
- const handshakeHandler = (data) => {
821
- const maybeSession = this.receiveHandshakeResponseMessage(data, conn);
822
- clearTimeout(handshakeTimeout);
823
- if (!maybeSession) {
824
- conn.close();
825
- return;
826
- } else {
827
- session = maybeSession;
828
- }
829
- conn.removeDataListener(handshakeHandler);
830
- conn.addDataListener((data2) => {
831
- const parsed = this.parseMsg(data2, conn);
832
- if (!parsed) {
833
- conn.telemetry?.span.setStatus({
834
- code: SpanStatusCode2.ERROR,
835
- message: "message parse failure"
836
- });
837
- conn.close();
838
- return;
839
- }
840
- this.handleMsg(parsed, conn);
841
- });
842
- };
843
- conn.addDataListener(handshakeHandler);
844
- conn.addCloseListener(() => {
845
- if (session) {
846
- this.onDisconnect(conn, session);
847
- }
848
- const willReconnect = this.reconnectOnConnectionDrop && this.getStatus() === "open";
849
- this.log?.info(
850
- `connection to ${to} disconnected` + (willReconnect ? ", reconnecting" : ""),
851
- {
852
- ...conn.loggingMetadata,
853
- ...session?.loggingMetadata,
854
- clientId: this.clientId,
855
- connectedTo: to
856
- }
857
- );
858
- this.inflightConnectionPromises.delete(to);
859
- if (this.reconnectOnConnectionDrop) {
860
- void this.connect(to);
861
- }
862
- });
863
- conn.addErrorListener((err) => {
864
- conn.telemetry?.span.setStatus({
865
- code: SpanStatusCode2.ERROR,
866
- message: "connection error"
867
- });
868
- this.log?.warn(
869
- `error in connection to ${to}: ${coerceErrorString(err)}`,
870
- {
871
- ...conn.loggingMetadata,
872
- ...session?.loggingMetadata,
873
- clientId: this.clientId,
874
- connectedTo: to
875
- }
876
- );
877
- });
878
- }
879
- receiveHandshakeResponseMessage(data, conn) {
880
- const parsed = this.parseMsg(data, conn);
881
- if (!parsed) {
882
- conn.telemetry?.span.setStatus({
883
- code: SpanStatusCode2.ERROR,
884
- message: "non-transport message"
885
- });
886
- this.protocolError(
887
- ProtocolError.HandshakeFailed,
888
- "received non-transport message"
889
- );
890
- return false;
891
- }
892
- if (!Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
893
- conn.telemetry?.span.setStatus({
894
- code: SpanStatusCode2.ERROR,
895
- message: "invalid handshake response"
896
- });
897
- this.log?.warn(`received invalid handshake resp`, {
898
- ...conn.loggingMetadata,
899
- clientId: this.clientId,
900
- connectedTo: parsed.from,
901
- transportMessage: parsed,
902
- validationErrors: [
903
- ...Value.Errors(
904
- ControlMessageHandshakeResponseSchema,
905
- parsed.payload
906
- )
907
- ]
908
- });
909
- this.protocolError(
910
- ProtocolError.HandshakeFailed,
911
- "invalid handshake resp"
912
- );
913
- return false;
914
- }
915
- if (!parsed.payload.status.ok) {
916
- conn.telemetry?.span.setStatus({
917
- code: SpanStatusCode2.ERROR,
918
- message: "handshake rejected"
919
- });
920
- this.log?.warn(`received handshake rejection`, {
921
- ...conn.loggingMetadata,
922
- clientId: this.clientId,
923
- connectedTo: parsed.from,
924
- transportMessage: parsed
925
- });
926
- this.protocolError(
927
- ProtocolError.HandshakeFailed,
928
- parsed.payload.status.reason
929
- );
930
- return false;
931
- }
932
- const previousSession = this.sessions.get(parsed.from);
933
- if (previousSession?.advertisedSessionId && previousSession.advertisedSessionId !== parsed.payload.status.sessionId) {
934
- this.deleteSession({
935
- session: previousSession,
936
- closeHandshakingConnection: true
937
- });
938
- conn.telemetry?.span.setStatus({
939
- code: SpanStatusCode2.ERROR,
940
- message: "session id mismatch"
941
- });
942
- this.log?.warn(`handshake from ${parsed.from} session id mismatch`, {
943
- ...conn.loggingMetadata,
944
- clientId: this.clientId,
945
- connectedTo: parsed.from,
946
- transportMessage: parsed
947
- });
948
- this.protocolError(ProtocolError.HandshakeFailed, "session id mismatch");
949
- return false;
950
- }
951
- this.log?.debug(`handshake from ${parsed.from} ok`, {
952
- ...conn.loggingMetadata,
953
- clientId: this.clientId,
954
- connectedTo: parsed.from,
955
- transportMessage: parsed
956
- });
957
- const { session, isTransparentReconnect } = this.getOrCreateSession({
958
- to: parsed.from,
959
- conn,
960
- sessionId: parsed.payload.status.sessionId
961
- });
962
- this.onConnect(conn, session, isTransparentReconnect);
963
- this.retryBudget.startRestoringBudget(session.to);
964
- return session;
965
- }
966
- /**
967
- * Manually attempts to connect to a client.
968
- * @param to The client ID of the node to connect to.
969
- */
970
- async connect(to) {
971
- if (this.connections.has(to)) {
972
- this.log?.info(`already connected to ${to}, skipping connect attempt`, {
973
- clientId: this.clientId,
974
- connectedTo: to
975
- });
976
- return;
977
- }
978
- const canProceedWithConnection = () => this.getStatus() === "open";
979
- if (!canProceedWithConnection()) {
980
- this.log?.info(
981
- `transport state is no longer open, cancelling attempt to connect to ${to}`,
982
- { clientId: this.clientId, connectedTo: to }
983
- );
984
- return;
985
- }
986
- let reconnectPromise = this.inflightConnectionPromises.get(to);
987
- if (!reconnectPromise) {
988
- if (!this.retryBudget.hasBudget(to)) {
989
- const budgetConsumed = this.retryBudget.getBudgetConsumed(to);
990
- const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
991
- this.log?.error(errMsg, { clientId: this.clientId, connectedTo: to });
992
- this.protocolError(ProtocolError.RetriesExceeded, errMsg);
993
- return;
994
- }
995
- let sleep = Promise.resolve();
996
- const backoffMs = this.retryBudget.getBackoffMs(to);
997
- if (backoffMs > 0) {
998
- sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
999
- }
1000
- this.log?.info(
1001
- `attempting connection to ${to} (${backoffMs}ms backoff)`,
1002
- {
1003
- clientId: this.clientId,
1004
- connectedTo: to
1005
- }
1006
- );
1007
- this.retryBudget.consumeBudget(to);
1008
- reconnectPromise = tracing_default.startActiveSpan("connect", async (span) => {
1009
- try {
1010
- span.addEvent("backoff", { backoffMs });
1011
- await sleep;
1012
- if (!canProceedWithConnection()) {
1013
- throw new Error("transport state is no longer open");
1014
- }
1015
- span.addEvent("connecting");
1016
- const conn = await this.createNewOutgoingConnection(to);
1017
- if (!canProceedWithConnection()) {
1018
- this.log?.info(
1019
- `transport state is no longer open, closing pre-handshake connection to ${to}`,
1020
- {
1021
- ...conn.loggingMetadata,
1022
- clientId: this.clientId,
1023
- connectedTo: to
1024
- }
1025
- );
1026
- conn.close();
1027
- throw new Error("transport state is no longer open");
1028
- }
1029
- span.addEvent("sending handshake");
1030
- const ok = await this.sendHandshake(to, conn);
1031
- if (!ok) {
1032
- conn.close();
1033
- throw new Error("failed to send handshake");
1034
- }
1035
- return conn;
1036
- } catch (err) {
1037
- const errStr = coerceErrorString(err);
1038
- span.recordException(errStr);
1039
- span.setStatus({ code: SpanStatusCode2.ERROR });
1040
- throw err;
1041
- } finally {
1042
- span.end();
1043
- }
1044
- });
1045
- this.inflightConnectionPromises.set(to, reconnectPromise);
1046
- } else {
1047
- this.log?.info(
1048
- `attempting connection to ${to} (reusing previous attempt)`,
1049
- {
1050
- clientId: this.clientId,
1051
- connectedTo: to
1052
- }
1053
- );
1054
- }
1055
- try {
1056
- await reconnectPromise;
1057
- } catch (error) {
1058
- this.inflightConnectionPromises.delete(to);
1059
- const errStr = coerceErrorString(error);
1060
- if (!this.reconnectOnConnectionDrop || !canProceedWithConnection()) {
1061
- this.log?.warn(`connection to ${to} failed (${errStr})`, {
1062
- clientId: this.clientId,
1063
- connectedTo: to
1064
- });
1065
- } else {
1066
- this.log?.warn(`connection to ${to} failed (${errStr}), retrying`, {
1067
- clientId: this.clientId,
1068
- connectedTo: to
1069
- });
1070
- await this.connect(to);
1071
- }
1072
- }
1073
- }
1074
- deleteSession({
1075
- session,
1076
- closeHandshakingConnection,
1077
- handshakingConn
1078
- }) {
1079
- this.inflightConnectionPromises.delete(session.to);
1080
- super.deleteSession({
1081
- session,
1082
- closeHandshakingConnection,
1083
- handshakingConn
1084
- });
1085
- }
1086
- async sendHandshake(to, conn) {
1087
- let metadata = void 0;
1088
- if (this.handshakeExtensions) {
1089
- metadata = await this.handshakeExtensions.construct();
1090
- if (!Value.Check(this.handshakeExtensions.schema, metadata)) {
1091
- this.log?.error(`constructed handshake metadata did not match schema`, {
1092
- ...conn.loggingMetadata,
1093
- clientId: this.clientId,
1094
- connectedTo: to,
1095
- validationErrors: [
1096
- ...Value.Errors(this.handshakeExtensions.schema, metadata)
1097
- ],
1098
- tags: ["invariant-violation"]
1099
- });
1100
- this.protocolError(
1101
- ProtocolError.HandshakeFailed,
1102
- "handshake metadata did not match schema"
1103
- );
1104
- conn.telemetry?.span.setStatus({
1105
- code: SpanStatusCode2.ERROR,
1106
- message: "handshake meta mismatch"
1107
- });
1108
- return false;
1109
- }
1110
- }
1111
- const { session } = this.getOrCreateSession({ to, handshakingConn: conn });
1112
- const requestMsg = handshakeRequestMessage(
1113
- this.clientId,
1114
- to,
1115
- session.id,
1116
- metadata,
1117
- getPropagationContext(session.telemetry.ctx)
1118
- );
1119
- this.log?.debug(`sending handshake request to ${to}`, {
1120
- ...conn.loggingMetadata,
1121
- clientId: this.clientId,
1122
- connectedTo: to,
1123
- transportMessage: requestMsg
1124
- });
1125
- conn.send(this.codec.toBuffer(requestMsg));
1126
- return true;
1127
- }
1128
- close() {
1129
- this.retryBudget.close();
1130
- super.close();
1131
- }
1132
- };
1133
- var ServerTransport = class extends Transport {
1134
- /**
1135
- * The options for this transport.
1136
- */
1137
- options;
1138
- /**
1139
- * Optional handshake options for the server.
1140
- */
1141
- handshakeExtensions;
1142
- /**
1143
- * A map of session handshake data for each session.
1144
- */
1145
- sessionHandshakeMetadata;
1146
- constructor(clientId, providedOptions) {
1147
- super(clientId, providedOptions);
1148
- this.options = {
1149
- ...defaultServerTransportOptions,
1150
- ...providedOptions
1151
- };
1152
- this.sessionHandshakeMetadata = /* @__PURE__ */ new WeakMap();
1153
- this.log?.info(`initiated server transport`, {
1154
- clientId: this.clientId,
1155
- protocolVersion: PROTOCOL_VERSION
1156
- });
1157
- }
1158
- extendHandshake(options) {
1159
- this.handshakeExtensions = options;
1160
- }
1161
- handleConnection(conn) {
1162
- if (this.getStatus() !== "open")
1163
- return;
1164
- this.log?.info(`new incoming connection`, {
1165
- ...conn.loggingMetadata,
1166
- clientId: this.clientId
1167
- });
1168
- let session = void 0;
1169
- const client = () => session?.to ?? "unknown";
1170
- const handshakeTimeout = setTimeout(() => {
1171
- if (!session) {
1172
- this.log?.warn(
1173
- `connection to ${client()} timed out waiting for handshake, closing`,
1174
- {
1175
- ...conn.loggingMetadata,
1176
- clientId: this.clientId,
1177
- connectedTo: client()
1178
- }
1179
- );
1180
- conn.telemetry?.span.setStatus({
1181
- code: SpanStatusCode2.ERROR,
1182
- message: "handshake timeout"
1183
- });
1184
- conn.close();
1185
- }
1186
- }, this.options.sessionDisconnectGraceMs);
1187
- const buffer = [];
1188
- let receivedHandshakeMessage = false;
1189
- const handshakeHandler = (data) => {
1190
- if (receivedHandshakeMessage) {
1191
- buffer.push(data);
1192
- return;
1193
- }
1194
- receivedHandshakeMessage = true;
1195
- clearTimeout(handshakeTimeout);
1196
- void this.receiveHandshakeRequestMessage(data, conn).then(
1197
- (maybeSession) => {
1198
- if (!maybeSession) {
1199
- conn.close();
1200
- return;
1201
- }
1202
- session = maybeSession;
1203
- const dataHandler = (data2) => {
1204
- const parsed = this.parseMsg(data2, conn);
1205
- if (!parsed) {
1206
- conn.close();
1207
- return;
1208
- }
1209
- this.handleMsg(parsed, conn);
1210
- };
1211
- for (const data2 of buffer) {
1212
- dataHandler(data2);
1213
- }
1214
- conn.removeDataListener(handshakeHandler);
1215
- conn.addDataListener(dataHandler);
1216
- buffer.length = 0;
1217
- }
1218
- );
1219
- };
1220
- conn.addDataListener(handshakeHandler);
1221
- conn.addCloseListener(() => {
1222
- if (!session)
1223
- return;
1224
- this.log?.info(`connection to ${client()} disconnected`, {
1225
- ...conn.loggingMetadata,
1226
- clientId: this.clientId
1227
- });
1228
- this.onDisconnect(conn, session);
1229
- });
1230
- conn.addErrorListener((err) => {
1231
- conn.telemetry?.span.setStatus({
1232
- code: SpanStatusCode2.ERROR,
1233
- message: "connection error"
1234
- });
1235
- if (!session)
1236
- return;
1237
- this.log?.warn(
1238
- `connection to ${client()} got an error: ${coerceErrorString(err)}`,
1239
- { ...conn.loggingMetadata, clientId: this.clientId }
1240
- );
1241
- });
1242
- }
1243
- async validateHandshakeMetadata(conn, session, rawMetadata, from) {
1244
- let parsedMetadata = {};
1245
- if (this.handshakeExtensions) {
1246
- if (!Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
1247
- conn.telemetry?.span.setStatus({
1248
- code: SpanStatusCode2.ERROR,
1249
- message: "malformed handshake meta"
1250
- });
1251
- const reason = "received malformed handshake metadata";
1252
- const responseMsg = handshakeResponseMessage(this.clientId, from, {
1253
- ok: false,
1254
- reason
1255
- });
1256
- conn.send(this.codec.toBuffer(responseMsg));
1257
- this.log?.warn(`received malformed handshake metadata from ${from}`, {
1258
- ...conn.loggingMetadata,
1259
- clientId: this.clientId,
1260
- validationErrors: [
1261
- ...Value.Errors(this.handshakeExtensions.schema, rawMetadata)
1262
- ]
1263
- });
1264
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1265
- return false;
1266
- }
1267
- const previousParsedMetadata = session ? this.sessionHandshakeMetadata.get(session) : void 0;
1268
- parsedMetadata = await this.handshakeExtensions.validate(
1269
- rawMetadata,
1270
- previousParsedMetadata
1271
- );
1272
- if (parsedMetadata === false) {
1273
- const reason = "rejected by handshake handler";
1274
- conn.telemetry?.span.setStatus({
1275
- code: SpanStatusCode2.ERROR,
1276
- message: reason
1277
- });
1278
- const responseMsg = handshakeResponseMessage(this.clientId, from, {
1279
- ok: false,
1280
- reason
1281
- });
1282
- conn.send(this.codec.toBuffer(responseMsg));
1283
- this.log?.warn(`rejected handshake from ${from}`, {
1284
- ...conn.loggingMetadata,
1285
- clientId: this.clientId
1286
- });
1287
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1288
- return false;
1289
- }
1290
- }
1291
- return parsedMetadata;
1292
- }
1293
- async receiveHandshakeRequestMessage(data, conn) {
1294
- const parsed = this.parseMsg(data, conn);
1295
- if (!parsed) {
1296
- conn.telemetry?.span.setStatus({
1297
- code: SpanStatusCode2.ERROR,
1298
- message: "non-transport message"
1299
- });
1300
- this.protocolError(
1301
- ProtocolError.HandshakeFailed,
1302
- "received non-transport message"
1303
- );
1304
- return false;
1305
- }
1306
- if (!Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
1307
- conn.telemetry?.span.setStatus({
1308
- code: SpanStatusCode2.ERROR,
1309
- message: "invalid handshake request"
1310
- });
1311
- const reason = "received invalid handshake msg";
1312
- const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1313
- ok: false,
1314
- reason
1315
- });
1316
- conn.send(this.codec.toBuffer(responseMsg2));
1317
- this.log?.warn(reason, {
1318
- ...conn.loggingMetadata,
1319
- clientId: this.clientId,
1320
- // safe to this.log metadata here as we remove the payload
1321
- // before passing it to user-land
1322
- transportMessage: parsed,
1323
- validationErrors: [
1324
- ...Value.Errors(ControlMessageHandshakeRequestSchema, parsed.payload)
1325
- ]
1326
- });
1327
- this.protocolError(
1328
- ProtocolError.HandshakeFailed,
1329
- "invalid handshake request"
1330
- );
1331
- return false;
1332
- }
1333
- const gotVersion = parsed.payload.protocolVersion;
1334
- if (gotVersion !== PROTOCOL_VERSION) {
1335
- conn.telemetry?.span.setStatus({
1336
- code: SpanStatusCode2.ERROR,
1337
- message: "incorrect protocol version"
1338
- });
1339
- const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
1340
- const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1341
- ok: false,
1342
- reason
1343
- });
1344
- conn.send(this.codec.toBuffer(responseMsg2));
1345
- this.log?.warn(
1346
- `received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`,
1347
- { ...conn.loggingMetadata, clientId: this.clientId }
1348
- );
1349
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1350
- return false;
1351
- }
1352
- const oldSession = this.sessions.get(parsed.from);
1353
- const parsedMetadata = await this.validateHandshakeMetadata(
1354
- conn,
1355
- oldSession,
1356
- parsed.payload.metadata,
1357
- parsed.from
1358
- );
1359
- if (parsedMetadata === false) {
1360
- return false;
1361
- }
1362
- const { session, isTransparentReconnect } = this.getOrCreateSession({
1363
- to: parsed.from,
1364
- conn,
1365
- sessionId: parsed.payload.sessionId,
1366
- propagationCtx: parsed.tracing
1367
- });
1368
- this.sessionHandshakeMetadata.set(session, parsedMetadata);
1369
- this.log?.debug(
1370
- `handshake from ${parsed.from} ok, responding with handshake success`,
1371
- conn.loggingMetadata
1372
- );
1373
- const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
1374
- ok: true,
1375
- sessionId: session.id
1376
- });
1377
- conn.send(this.codec.toBuffer(responseMsg));
1378
- this.onConnect(conn, session, isTransparentReconnect);
1379
- return session;
1380
- }
1381
- };
1382
-
1383
- export {
1384
- Connection,
1385
- Session,
1386
- ProtocolError,
1387
- defaultTransportOptions,
1388
- Transport,
1389
- ClientTransport,
1390
- ServerTransport
1391
- };
1392
- //# sourceMappingURL=chunk-VRU4IKRT.js.map