@replit/river 0.21.1 → 0.22.0

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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-5WFL722S.js → chunk-3MFX6NXA.js} +94 -3
  3. package/dist/chunk-3MFX6NXA.js.map +1 -0
  4. package/dist/{chunk-NCXUFDVL.js → chunk-GCLEWC26.js} +328 -500
  5. package/dist/chunk-GCLEWC26.js.map +1 -0
  6. package/dist/chunk-HUBFYN37.js +60 -0
  7. package/dist/chunk-HUBFYN37.js.map +1 -0
  8. package/dist/{chunk-FDLAPYCK.js → chunk-S3YKQT4J.js} +2 -2
  9. package/dist/{chunk-JMXO5L2X.js → chunk-ZPBWKBM5.js} +344 -384
  10. package/dist/chunk-ZPBWKBM5.js.map +1 -0
  11. package/dist/{connection-76c5ed01.d.ts → connection-8b059ac4.d.ts} +6 -4
  12. package/dist/{connection-975b25c9.d.ts → connection-bbfe1147.d.ts} +1 -1
  13. package/dist/{index-dfad460e.d.ts → index-2ece5234.d.ts} +16 -7
  14. package/dist/logging/index.d.cts +2 -1
  15. package/dist/logging/index.d.ts +2 -1
  16. package/dist/router/index.cjs +373 -486
  17. package/dist/router/index.cjs.map +1 -1
  18. package/dist/router/index.d.cts +5 -4
  19. package/dist/router/index.d.ts +5 -4
  20. package/dist/router/index.js +4 -3
  21. package/dist/{services-7b716dcf.d.ts → services-acbcc441.d.ts} +1 -1
  22. package/dist/{services-9c496c6e.d.ts → services-cb01a7a8.d.ts} +1 -1
  23. package/dist/transport/impls/uds/client.cjs +186 -145
  24. package/dist/transport/impls/uds/client.cjs.map +1 -1
  25. package/dist/transport/impls/uds/client.d.cts +3 -2
  26. package/dist/transport/impls/uds/client.d.ts +3 -2
  27. package/dist/transport/impls/uds/client.js +3 -3
  28. package/dist/transport/impls/uds/server.cjs +281 -256
  29. package/dist/transport/impls/uds/server.cjs.map +1 -1
  30. package/dist/transport/impls/uds/server.d.cts +3 -2
  31. package/dist/transport/impls/uds/server.d.ts +3 -2
  32. package/dist/transport/impls/uds/server.js +3 -3
  33. package/dist/transport/impls/ws/client.cjs +240 -204
  34. package/dist/transport/impls/ws/client.cjs.map +1 -1
  35. package/dist/transport/impls/ws/client.d.cts +6 -6
  36. package/dist/transport/impls/ws/client.d.ts +6 -6
  37. package/dist/transport/impls/ws/client.js +33 -48
  38. package/dist/transport/impls/ws/client.js.map +1 -1
  39. package/dist/transport/impls/ws/server.cjs +303 -270
  40. package/dist/transport/impls/ws/server.cjs.map +1 -1
  41. package/dist/transport/impls/ws/server.d.cts +5 -4
  42. package/dist/transport/impls/ws/server.d.ts +5 -4
  43. package/dist/transport/impls/ws/server.js +3 -3
  44. package/dist/transport/impls/ws/server.js.map +1 -1
  45. package/dist/transport/index.cjs +390 -382
  46. package/dist/transport/index.cjs.map +1 -1
  47. package/dist/transport/index.d.cts +5 -5
  48. package/dist/transport/index.d.ts +5 -5
  49. package/dist/transport/index.js +2 -2
  50. package/dist/util/testHelpers.cjs +57 -7
  51. package/dist/util/testHelpers.cjs.map +1 -1
  52. package/dist/util/testHelpers.d.cts +14 -5
  53. package/dist/util/testHelpers.d.ts +14 -5
  54. package/dist/util/testHelpers.js +10 -4
  55. package/dist/util/testHelpers.js.map +1 -1
  56. package/dist/wslike-e0b32dd5.d.ts +40 -0
  57. package/package.json +4 -5
  58. package/dist/chunk-3Y7AB5EB.js +0 -42
  59. package/dist/chunk-3Y7AB5EB.js.map +0 -1
  60. package/dist/chunk-5WFL722S.js.map +0 -1
  61. package/dist/chunk-JMXO5L2X.js.map +0 -1
  62. package/dist/chunk-NCXUFDVL.js.map +0 -1
  63. /package/dist/{chunk-FDLAPYCK.js.map → chunk-S3YKQT4J.js.map} +0 -0
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // transport/impls/ws/server.ts
@@ -36,7 +26,6 @@ module.exports = __toCommonJS(server_exports);
36
26
 
37
27
  // transport/transport.ts
38
28
  var import_value = require("@sinclair/typebox/value");
39
- var import_api2 = require("@opentelemetry/api");
40
29
 
41
30
  // transport/message.ts
42
31
  var import_typebox = require("@sinclair/typebox");
@@ -152,17 +141,62 @@ var EventDispatcher = class {
152
141
 
153
142
  // transport/session.ts
154
143
  var import_nanoid2 = require("nanoid");
144
+
145
+ // tracing/index.ts
146
+ var import_api = require("@opentelemetry/api");
147
+
148
+ // package.json
149
+ var version = "0.22.0";
150
+
151
+ // tracing/index.ts
152
+ function createSessionTelemetryInfo(session, propagationCtx) {
153
+ const ctx = propagationCtx ? import_api.propagation.extract(import_api.context.active(), propagationCtx) : import_api.context.active();
154
+ const span = tracer.startSpan(
155
+ `session ${session.id}`,
156
+ {
157
+ attributes: {
158
+ component: "river",
159
+ "river.session.id": session.id,
160
+ "river.session.to": session.to,
161
+ "river.session.from": session.from
162
+ }
163
+ },
164
+ ctx
165
+ );
166
+ return { span, ctx };
167
+ }
168
+ function createConnectionTelemetryInfo(connection, sessionSpan) {
169
+ const ctx = import_api.trace.setSpan(import_api.context.active(), sessionSpan);
170
+ const span = tracer.startSpan(
171
+ `connection ${connection.id}`,
172
+ {
173
+ attributes: {
174
+ component: "river",
175
+ "river.connection.id": connection.id
176
+ },
177
+ links: [{ context: sessionSpan.spanContext() }]
178
+ },
179
+ ctx
180
+ );
181
+ return { span, ctx };
182
+ }
183
+ var tracer = import_api.trace.getTracer("river", version);
184
+
185
+ // transport/session.ts
186
+ var import_api2 = require("@opentelemetry/api");
155
187
  var nanoid2 = (0, import_nanoid2.customAlphabet)("1234567890abcdefghijklmnopqrstuvxyz", 6);
156
188
  var unsafeId = () => nanoid2();
157
189
  var Connection = class {
158
- debugId;
190
+ id;
191
+ telemetry;
159
192
  constructor() {
160
- this.debugId = `conn-${unsafeId()}`;
193
+ this.id = `conn-${nanoid2(12)}`;
161
194
  }
162
195
  };
163
196
  var Session = class {
164
197
  codec;
165
198
  options;
199
+ telemetry;
166
200
  /**
167
201
  * The buffer of messages that have been sent but not yet acknowledged.
168
202
  */
@@ -209,7 +243,7 @@ var Session = class {
209
243
  * The interval for sending heartbeats.
210
244
  */
211
245
  heartbeat;
212
- constructor(conn, from, to, options) {
246
+ constructor(conn, from, to, options, propagationCtx) {
213
247
  this.id = `session-${nanoid2(12)}`;
214
248
  this.options = options;
215
249
  this.from = from;
@@ -221,13 +255,14 @@ var Session = class {
221
255
  () => this.sendHeartbeat(),
222
256
  options.heartbeatIntervalMs
223
257
  );
258
+ this.telemetry = createSessionTelemetryInfo(this, propagationCtx);
224
259
  }
225
260
  get loggingMetadata() {
226
261
  return {
227
262
  clientId: this.from,
228
263
  connectedTo: this.to,
229
264
  sessionId: this.id,
230
- connId: this.connection?.debugId
265
+ connId: this.connection?.id
231
266
  };
232
267
  }
233
268
  /**
@@ -272,6 +307,7 @@ var Session = class {
272
307
  `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
273
308
  this.loggingMetadata
274
309
  );
310
+ this.telemetry.span.addEvent("closing connection due to inactivity");
275
311
  this.closeStaleConnection();
276
312
  }
277
313
  return;
@@ -293,21 +329,25 @@ var Session = class {
293
329
  sendBufferedMessages(conn) {
294
330
  log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
295
331
  ...this.loggingMetadata,
296
- connId: conn.debugId
332
+ connId: conn.id
297
333
  });
298
334
  for (const msg of this.sendBuffer) {
299
335
  log?.debug(`resending msg`, {
300
336
  ...this.loggingMetadata,
301
337
  fullTransportMessage: msg,
302
- connId: conn.debugId
338
+ connId: conn.id
303
339
  });
304
340
  const ok = conn.send(this.codec.toBuffer(msg));
305
341
  if (!ok) {
306
342
  const errMsg = `failed to send buffered message to ${this.to} (sus, this is a fresh connection)`;
343
+ conn.telemetry?.span.setStatus({
344
+ code: import_api2.SpanStatusCode.ERROR,
345
+ message: errMsg
346
+ });
307
347
  log?.error(errMsg, {
308
348
  ...this.loggingMetadata,
309
349
  fullTransportMessage: msg,
310
- connId: conn.debugId,
350
+ connId: conn.id,
311
351
  tags: ["invariant-violation"]
312
352
  });
313
353
  conn.close();
@@ -390,11 +430,6 @@ var Session = class {
390
430
  }
391
431
  };
392
432
 
393
- // tracing/index.ts
394
- var import_api = require("@opentelemetry/api");
395
- var tracer = import_api.trace.getTracer("river");
396
- var tracing_default = tracer;
397
-
398
433
  // util/stringify.ts
399
434
  function coerceErrorString(err) {
400
435
  if (err instanceof Error) {
@@ -456,6 +491,7 @@ var NaiveJsonCodec = {
456
491
  };
457
492
 
458
493
  // transport/transport.ts
494
+ var import_api3 = require("@opentelemetry/api");
459
495
  var defaultTransportOptions = {
460
496
  heartbeatIntervalMs: 1e3,
461
497
  heartbeatsUntilDead: 2,
@@ -534,17 +570,22 @@ var Transport = class {
534
570
  status: "connect",
535
571
  conn
536
572
  });
573
+ conn.telemetry = createConnectionTelemetryInfo(
574
+ conn,
575
+ session.telemetry.span
576
+ );
537
577
  if (isReconnect) {
538
578
  session.replaceWithNewConnection(conn);
539
579
  log?.info(`reconnected to ${connectedTo}`, session.loggingMetadata);
540
580
  }
541
581
  }
542
- createSession(to, conn) {
582
+ createSession(to, conn, propagationCtx) {
543
583
  const session = new Session(
544
584
  conn,
545
585
  this.clientId,
546
586
  to,
547
- this.options
587
+ this.options,
588
+ propagationCtx
548
589
  );
549
590
  this.sessions.set(session.to, session);
550
591
  this.eventDispatcher.dispatchEvent("sessionStatus", {
@@ -553,11 +594,11 @@ var Transport = class {
553
594
  });
554
595
  return session;
555
596
  }
556
- getOrCreateSession(to, conn, sessionId) {
597
+ getOrCreateSession(to, conn, sessionId, propagationCtx) {
557
598
  let session = this.sessions.get(to);
558
599
  let isReconnect = session !== void 0;
559
600
  if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
560
- log?.warn(
601
+ log?.info(
561
602
  `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
562
603
  session.loggingMetadata
563
604
  );
@@ -566,7 +607,7 @@ var Transport = class {
566
607
  session = void 0;
567
608
  }
568
609
  if (!session) {
569
- session = this.createSession(to, conn);
610
+ session = this.createSession(to, conn, propagationCtx);
570
611
  log?.info(
571
612
  `no session for ${to}, created a new one`,
572
613
  session.loggingMetadata
@@ -579,6 +620,7 @@ var Transport = class {
579
620
  }
580
621
  deleteSession(session) {
581
622
  session.close();
623
+ session.telemetry.span.end();
582
624
  this.sessions.delete(session.to);
583
625
  log?.info(
584
626
  `session ${session.id} disconnect from ${session.to}`,
@@ -595,12 +637,16 @@ var Transport = class {
595
637
  * @param connectedTo The peer we are connected to.
596
638
  */
597
639
  onDisconnect(conn, session) {
640
+ conn.telemetry?.span.end();
598
641
  this.eventDispatcher.dispatchEvent("connectionStatus", {
599
642
  status: "disconnect",
600
643
  conn
601
644
  });
602
645
  session.connection = void 0;
603
- session.beginGrace(() => this.deleteSession(session));
646
+ session.beginGrace(() => {
647
+ session.telemetry.span.addEvent("session grace period expired");
648
+ this.deleteSession(session);
649
+ });
604
650
  }
605
651
  /**
606
652
  * Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
@@ -660,6 +706,10 @@ var Transport = class {
660
706
  tags: ["invariant-violation"]
661
707
  });
662
708
  this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
709
+ session.telemetry.span.setStatus({
710
+ code: import_api3.SpanStatusCode.ERROR,
711
+ message: "message order violated"
712
+ });
663
713
  session.close();
664
714
  }
665
715
  return;
@@ -770,279 +820,262 @@ var ServerTransport = class extends Transport {
770
820
  });
771
821
  }
772
822
  handleConnection(conn) {
773
- tracing_default.startActiveSpan(
774
- "handleConnection",
775
- {
776
- attributes: {
777
- component: "river",
778
- "span.kind": "server"
779
- },
780
- kind: import_api2.SpanKind.SERVER
781
- },
782
- (span) => {
783
- if (this.state !== "open")
784
- return;
785
- log?.info(`new incoming connection`, {
786
- clientId: this.clientId,
787
- connId: conn.debugId
823
+ if (this.state !== "open")
824
+ return;
825
+ log?.info(`new incoming connection`, {
826
+ clientId: this.clientId,
827
+ connId: conn.id
828
+ });
829
+ let session = void 0;
830
+ const client = () => session?.to ?? "unknown";
831
+ const handshakeTimeout = setTimeout(() => {
832
+ if (!session) {
833
+ log?.warn(
834
+ `connection to ${client()} timed out waiting for handshake, closing`,
835
+ {
836
+ clientId: this.clientId,
837
+ connectedTo: client(),
838
+ connId: conn.id
839
+ }
840
+ );
841
+ conn.telemetry?.span.setStatus({
842
+ code: import_api3.SpanStatusCode.ERROR,
843
+ message: "handshake timeout"
788
844
  });
789
- let session = void 0;
790
- const client = () => session?.to ?? "unknown";
791
- const handshakeTimeout = setTimeout(() => {
792
- if (!session) {
793
- log?.warn(
794
- `connection to ${client()} timed out waiting for handshake, closing`,
795
- {
796
- clientId: this.clientId,
797
- connectedTo: client(),
798
- connId: conn.debugId
799
- }
800
- );
801
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
802
- span.end();
845
+ conn.close();
846
+ }
847
+ }, this.options.sessionDisconnectGraceMs);
848
+ const buffer = [];
849
+ let receivedHandshakeMessage = false;
850
+ const handshakeHandler = (data) => {
851
+ if (receivedHandshakeMessage) {
852
+ buffer.push(data);
853
+ return;
854
+ }
855
+ receivedHandshakeMessage = true;
856
+ clearTimeout(handshakeTimeout);
857
+ void this.receiveHandshakeRequestMessage(data, conn).then(
858
+ (maybeSession) => {
859
+ if (!maybeSession) {
803
860
  conn.close();
804
- }
805
- }, this.options.sessionDisconnectGraceMs);
806
- const buffer = [];
807
- let receivedHandshakeMessage = false;
808
- const handshakeHandler = (data) => {
809
- if (receivedHandshakeMessage) {
810
- buffer.push(data);
811
861
  return;
812
862
  }
813
- receivedHandshakeMessage = true;
814
- clearTimeout(handshakeTimeout);
815
- void this.receiveHandshakeRequestMessage(data, conn).then(
816
- (maybeSession) => {
817
- if (!maybeSession) {
818
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
819
- span.end();
820
- conn.close();
821
- return;
822
- }
823
- session = maybeSession;
824
- const dataHandler = (data2) => {
825
- const parsed = this.parseMsg(data2);
826
- if (!parsed) {
827
- conn.close();
828
- return;
829
- }
830
- this.handleMsg(parsed);
831
- };
832
- conn.removeDataListener(handshakeHandler);
833
- conn.addDataListener(dataHandler);
834
- for (const data2 of buffer) {
835
- dataHandler(data2);
836
- }
837
- buffer.length = 0;
863
+ session = maybeSession;
864
+ const dataHandler = (data2) => {
865
+ const parsed = this.parseMsg(data2);
866
+ if (!parsed) {
867
+ conn.close();
868
+ return;
838
869
  }
839
- );
840
- };
841
- conn.addDataListener(handshakeHandler);
842
- conn.addCloseListener(() => {
843
- if (session) {
844
- log?.info(`connection to ${client()} disconnected`, {
845
- clientId: this.clientId,
846
- connId: conn.debugId
847
- });
848
- this.onDisconnect(conn, session);
849
- }
850
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
851
- span.end();
852
- });
853
- conn.addErrorListener((err) => {
854
- if (session) {
855
- log?.warn(
856
- `connection to ${client()} got an error: ${coerceErrorString(
857
- err
858
- )}`,
859
- { clientId: this.clientId, connId: conn.debugId }
860
- );
870
+ this.handleMsg(parsed);
871
+ };
872
+ for (const data2 of buffer) {
873
+ dataHandler(data2);
861
874
  }
862
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
863
- span.end();
864
- });
865
- }
866
- );
875
+ conn.removeDataListener(handshakeHandler);
876
+ conn.addDataListener(dataHandler);
877
+ buffer.length = 0;
878
+ }
879
+ );
880
+ };
881
+ conn.addDataListener(handshakeHandler);
882
+ conn.addCloseListener(() => {
883
+ if (!session)
884
+ return;
885
+ log?.info(`connection to ${client()} disconnected`, {
886
+ clientId: this.clientId,
887
+ connId: conn.id
888
+ });
889
+ this.onDisconnect(conn, session);
890
+ });
891
+ conn.addErrorListener((err) => {
892
+ conn.telemetry?.span.setStatus({
893
+ code: import_api3.SpanStatusCode.ERROR,
894
+ message: "connection error"
895
+ });
896
+ if (!session)
897
+ return;
898
+ log?.warn(
899
+ `connection to ${client()} got an error: ${coerceErrorString(err)}`,
900
+ { clientId: this.clientId, connId: conn.id }
901
+ );
902
+ });
867
903
  }
868
904
  async receiveHandshakeRequestMessage(data, conn) {
869
905
  const parsed = this.parseMsg(data);
870
906
  if (!parsed) {
907
+ conn.telemetry?.span.setStatus({
908
+ code: import_api3.SpanStatusCode.ERROR,
909
+ message: "non-transport message"
910
+ });
871
911
  this.protocolError(
872
912
  ProtocolError.HandshakeFailed,
873
913
  "received non-transport message"
874
914
  );
875
915
  return false;
876
916
  }
877
- let activeContext = import_api2.context.active();
878
- if (parsed.tracing) {
879
- activeContext = import_api2.propagation.extract(activeContext, parsed.tracing);
917
+ if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
918
+ conn.telemetry?.span.setStatus({
919
+ code: import_api3.SpanStatusCode.ERROR,
920
+ message: "invalid handshake request"
921
+ });
922
+ const reason = "received invalid handshake msg";
923
+ const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
924
+ ok: false,
925
+ reason
926
+ });
927
+ conn.send(this.codec.toBuffer(responseMsg2));
928
+ const logData = { ...parsed.payload ?? {}, metadata: "redacted" };
929
+ log?.warn(reason, {
930
+ clientId: this.clientId,
931
+ connId: conn.id,
932
+ partialTransportMessage: { ...parsed, payload: logData }
933
+ });
934
+ this.protocolError(
935
+ ProtocolError.HandshakeFailed,
936
+ "invalid handshake request"
937
+ );
938
+ return false;
880
939
  }
881
- return tracing_default.startActiveSpan(
882
- "receiveHandshakeRequestMessage",
883
- {
884
- attributes: {
885
- component: "river",
886
- "span.kind": "server"
887
- },
888
- kind: import_api2.SpanKind.SERVER
889
- },
890
- activeContext,
891
- async (span) => {
892
- if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
893
- const reason = "received invalid handshake msg";
894
- const responseMsg2 = handshakeResponseMessage(
895
- this.clientId,
896
- parsed.from,
897
- {
898
- ok: false,
899
- reason
900
- }
901
- );
902
- conn.send(this.codec.toBuffer(responseMsg2));
903
- const logData = typeof parsed.payload === "object" ? {
904
- ...parsed,
905
- payload: { ...parsed.payload, metadata: "redacted" }
906
- } : { ...parsed };
907
- log?.warn(`${reason}: ${JSON.stringify(logData)}`, {
908
- clientId: this.clientId,
909
- connId: conn.debugId
910
- });
911
- this.protocolError(
912
- ProtocolError.HandshakeFailed,
913
- "invalid handshake request"
914
- );
915
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
916
- span.end();
917
- return false;
918
- }
919
- const gotVersion = parsed.payload.protocolVersion;
920
- if (gotVersion !== PROTOCOL_VERSION) {
921
- const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
922
- const responseMsg2 = handshakeResponseMessage(
923
- this.clientId,
924
- parsed.from,
925
- {
926
- ok: false,
927
- reason
928
- }
929
- );
930
- conn.send(this.codec.toBuffer(responseMsg2));
931
- log?.warn(
932
- `received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`,
933
- { clientId: this.clientId, connId: conn.debugId }
934
- );
935
- this.protocolError(ProtocolError.HandshakeFailed, reason);
936
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
937
- span.end();
938
- return false;
939
- }
940
- const { session, isReconnect } = this.getOrCreateSession(
940
+ const gotVersion = parsed.payload.protocolVersion;
941
+ if (gotVersion !== PROTOCOL_VERSION) {
942
+ conn.telemetry?.span.setStatus({
943
+ code: import_api3.SpanStatusCode.ERROR,
944
+ message: "incorrect protocol version"
945
+ });
946
+ const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
947
+ const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
948
+ ok: false,
949
+ reason
950
+ });
951
+ conn.send(this.codec.toBuffer(responseMsg2));
952
+ log?.warn(
953
+ `received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`,
954
+ { clientId: this.clientId, connId: conn.id }
955
+ );
956
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
957
+ return false;
958
+ }
959
+ const { session, isReconnect } = this.getOrCreateSession(
960
+ parsed.from,
961
+ conn,
962
+ parsed.payload.sessionId,
963
+ parsed.tracing
964
+ );
965
+ let handshakeMetadata;
966
+ if (this.options.handshake) {
967
+ if (!import_value.Value.Check(
968
+ this.options.handshake.requestSchema,
969
+ parsed.payload.metadata
970
+ )) {
971
+ conn.telemetry?.span.setStatus({
972
+ code: import_api3.SpanStatusCode.ERROR,
973
+ message: "malformed handshake meta"
974
+ });
975
+ const reason = "received malformed handshake metadata";
976
+ const responseMsg2 = handshakeResponseMessage(
977
+ this.clientId,
941
978
  parsed.from,
942
- conn,
943
- parsed.payload.sessionId
979
+ { ok: false, reason }
944
980
  );
945
- let handshakeMetadata;
946
- if (this.options.handshake) {
947
- if (!import_value.Value.Check(
948
- this.options.handshake.requestSchema,
949
- parsed.payload.metadata
950
- )) {
951
- const reason = "received malformed handshake metadata";
952
- const responseMsg2 = handshakeResponseMessage(
953
- this.clientId,
954
- parsed.from,
955
- { ok: false, reason }
956
- );
957
- conn.send(this.codec.toBuffer(responseMsg2));
958
- log?.warn(
959
- `received malformed handshake metadata from ${parsed.from}`,
960
- {
961
- clientId: this.clientId,
962
- connId: conn.debugId
963
- }
964
- );
965
- this.protocolError(ProtocolError.HandshakeFailed, reason);
966
- this.deleteSession(session);
967
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
968
- span.end();
969
- return false;
970
- }
971
- const parsedMetadata = await this.options.handshake.parse(
972
- parsed.payload.metadata,
973
- session,
974
- isReconnect
975
- );
976
- if (parsedMetadata === false) {
977
- const reason = "rejected by server";
978
- const responseMsg2 = handshakeResponseMessage(
979
- this.clientId,
980
- parsed.from,
981
- { ok: false, reason }
982
- );
983
- conn.send(this.codec.toBuffer(responseMsg2));
984
- log?.warn(`rejected handshake from ${parsed.from}`, {
985
- clientId: this.clientId,
986
- connId: conn.debugId
987
- });
988
- this.protocolError(ProtocolError.HandshakeFailed, reason);
989
- this.deleteSession(session);
990
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
991
- span.end();
992
- return false;
993
- }
994
- if (!import_value.Value.Check(this.options.handshake.parsedSchema, parsedMetadata)) {
995
- const reason = "failed to parse handshake metadata";
996
- const responseMsg2 = handshakeResponseMessage(
997
- this.clientId,
998
- parsed.from,
999
- { ok: false, reason }
1000
- );
1001
- conn.send(this.codec.toBuffer(responseMsg2));
1002
- log?.error(`failed to parse handshake metadata`, {
1003
- clientId: this.clientId,
1004
- connId: conn.debugId,
1005
- tags: ["invariant-violation"]
1006
- });
1007
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1008
- this.deleteSession(session);
1009
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
1010
- span.end();
1011
- return false;
1012
- }
1013
- handshakeMetadata = parsedMetadata;
1014
- }
1015
- handshakeMetadata ??= {};
1016
- session.metadata = handshakeMetadata;
1017
- log?.debug(
1018
- `handshake from ${parsed.from} ok, responding with handshake success`,
1019
- { clientId: this.clientId, connId: conn.debugId }
981
+ conn.send(this.codec.toBuffer(responseMsg2));
982
+ log?.warn(`received malformed handshake metadata from ${parsed.from}`, {
983
+ clientId: this.clientId,
984
+ connId: conn.id
985
+ });
986
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
987
+ this.deleteSession(session);
988
+ return false;
989
+ }
990
+ const parsedMetadata = await this.options.handshake.parse(
991
+ parsed.payload.metadata,
992
+ session,
993
+ isReconnect
994
+ );
995
+ if (parsedMetadata === false) {
996
+ conn.telemetry?.span.setStatus({
997
+ code: import_api3.SpanStatusCode.ERROR,
998
+ message: "rejected by handshake handler"
999
+ });
1000
+ const reason = "rejected by handshake handler";
1001
+ const responseMsg2 = handshakeResponseMessage(
1002
+ this.clientId,
1003
+ parsed.from,
1004
+ { ok: false, reason }
1020
1005
  );
1021
- const responseMsg = handshakeResponseMessage(
1006
+ conn.send(this.codec.toBuffer(responseMsg2));
1007
+ log?.warn(`rejected handshake from ${parsed.from}`, {
1008
+ clientId: this.clientId,
1009
+ connId: conn.id
1010
+ });
1011
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
1012
+ this.deleteSession(session);
1013
+ return false;
1014
+ }
1015
+ if (!import_value.Value.Check(this.options.handshake.parsedSchema, parsedMetadata)) {
1016
+ conn.telemetry?.span.setStatus({
1017
+ code: import_api3.SpanStatusCode.ERROR,
1018
+ message: "malformed handshake meta"
1019
+ });
1020
+ const reason = "failed to parse handshake metadata";
1021
+ const responseMsg2 = handshakeResponseMessage(
1022
1022
  this.clientId,
1023
1023
  parsed.from,
1024
- {
1025
- ok: true,
1026
- sessionId: session.id
1027
- }
1024
+ { ok: false, reason }
1028
1025
  );
1029
- conn.send(this.codec.toBuffer(responseMsg));
1030
- this.onConnect(conn, parsed.from, session, isReconnect);
1031
- span.end();
1032
- return session;
1026
+ conn.send(this.codec.toBuffer(responseMsg2));
1027
+ log?.error(`failed to parse handshake metadata`, {
1028
+ clientId: this.clientId,
1029
+ connId: conn.id
1030
+ });
1031
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
1032
+ this.deleteSession(session);
1033
+ return false;
1033
1034
  }
1035
+ handshakeMetadata = parsedMetadata;
1036
+ }
1037
+ handshakeMetadata ??= {};
1038
+ session.metadata = handshakeMetadata;
1039
+ log?.debug(
1040
+ `handshake from ${parsed.from} ok, responding with handshake success`,
1041
+ { clientId: this.clientId, connId: conn.id }
1034
1042
  );
1043
+ const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
1044
+ ok: true,
1045
+ sessionId: session.id
1046
+ });
1047
+ conn.send(this.codec.toBuffer(responseMsg));
1048
+ this.onConnect(conn, parsed.from, session, isReconnect);
1049
+ return session;
1035
1050
  }
1036
1051
  };
1037
1052
 
1038
1053
  // transport/impls/ws/connection.ts
1039
- var import_agnostic_ws = __toESM(require("agnostic-ws"), 1);
1040
1054
  var WebSocketConnection = class extends Connection {
1055
+ errorCb = null;
1056
+ closeCb = null;
1041
1057
  ws;
1042
1058
  constructor(ws) {
1043
1059
  super();
1044
1060
  this.ws = ws;
1045
1061
  this.ws.binaryType = "arraybuffer";
1062
+ let didError = false;
1063
+ this.ws.onerror = () => {
1064
+ didError = true;
1065
+ };
1066
+ this.ws.onclose = ({ code, reason }) => {
1067
+ if (didError && this.errorCb) {
1068
+ this.errorCb(
1069
+ new Error(
1070
+ `websocket closed with code and reason: ${code} - ${reason}`
1071
+ )
1072
+ );
1073
+ return;
1074
+ }
1075
+ if (this.closeCb) {
1076
+ this.closeCb();
1077
+ }
1078
+ };
1046
1079
  }
1047
1080
  addDataListener(cb) {
1048
1081
  this.ws.onmessage = (msg) => cb(msg.data);
@@ -1051,13 +1084,13 @@ var WebSocketConnection = class extends Connection {
1051
1084
  this.ws.onmessage = null;
1052
1085
  }
1053
1086
  addCloseListener(cb) {
1054
- this.ws.onclose = cb;
1087
+ this.closeCb = cb;
1055
1088
  }
1056
1089
  addErrorListener(cb) {
1057
- this.ws.onerror = (err) => cb(err.error);
1090
+ this.errorCb = cb;
1058
1091
  }
1059
1092
  send(payload) {
1060
- if (this.ws.readyState === import_agnostic_ws.default.OPEN) {
1093
+ if (this.ws.readyState === this.ws.OPEN) {
1061
1094
  this.ws.send(payload);
1062
1095
  return true;
1063
1096
  } else {