@replit/river 0.21.1 → 0.23.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-FDLAPYCK.js → chunk-DZOATC6M.js} +2 -2
  3. package/dist/{chunk-JMXO5L2X.js → chunk-MJUFKPBT.js} +354 -398
  4. package/dist/chunk-MJUFKPBT.js.map +1 -0
  5. package/dist/{chunk-5WFL722S.js → chunk-PCKHBAVP.js} +94 -3
  6. package/dist/chunk-PCKHBAVP.js.map +1 -0
  7. package/dist/{chunk-NCXUFDVL.js → chunk-VOJVLWVX.js} +360 -516
  8. package/dist/chunk-VOJVLWVX.js.map +1 -0
  9. package/dist/chunk-ZF2UFTNN.js +60 -0
  10. package/dist/chunk-ZF2UFTNN.js.map +1 -0
  11. package/dist/{connection-76c5ed01.d.ts → connection-5685d817.d.ts} +6 -4
  12. package/dist/{connection-975b25c9.d.ts → connection-7582fb92.d.ts} +1 -1
  13. package/dist/{index-dfad460e.d.ts → index-a6fe0edd.d.ts} +55 -59
  14. package/dist/logging/index.d.cts +2 -1
  15. package/dist/logging/index.d.ts +2 -1
  16. package/dist/router/index.cjs +405 -502
  17. package/dist/router/index.cjs.map +1 -1
  18. package/dist/router/index.d.cts +12 -6
  19. package/dist/router/index.d.ts +12 -6
  20. package/dist/router/index.js +4 -3
  21. package/dist/{services-9c496c6e.d.ts → services-be91b485.d.ts} +21 -52
  22. package/dist/{services-7b716dcf.d.ts → services-eb9326a1.d.ts} +21 -52
  23. package/dist/transport/impls/uds/client.cjs +197 -155
  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 +280 -266
  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 +251 -214
  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 +302 -280
  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 +400 -396
  46. package/dist/transport/index.cjs.map +1 -1
  47. package/dist/transport/index.d.cts +25 -14
  48. package/dist/transport/index.d.ts +25 -14
  49. package/dist/transport/index.js +2 -2
  50. package/dist/util/testHelpers.cjs +59 -14
  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 +12 -5
  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-DZOATC6M.js.map} +0 -0
@@ -26,7 +26,6 @@ module.exports = __toCommonJS(server_exports);
26
26
 
27
27
  // transport/transport.ts
28
28
  var import_value = require("@sinclair/typebox/value");
29
- var import_api2 = require("@opentelemetry/api");
30
29
 
31
30
  // transport/message.ts
32
31
  var import_typebox = require("@sinclair/typebox");
@@ -142,17 +141,62 @@ var EventDispatcher = class {
142
141
 
143
142
  // transport/session.ts
144
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.23.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");
145
187
  var nanoid2 = (0, import_nanoid2.customAlphabet)("1234567890abcdefghijklmnopqrstuvxyz", 6);
146
188
  var unsafeId = () => nanoid2();
147
189
  var Connection = class {
148
- debugId;
190
+ id;
191
+ telemetry;
149
192
  constructor() {
150
- this.debugId = `conn-${unsafeId()}`;
193
+ this.id = `conn-${nanoid2(12)}`;
151
194
  }
152
195
  };
153
196
  var Session = class {
154
197
  codec;
155
198
  options;
199
+ telemetry;
156
200
  /**
157
201
  * The buffer of messages that have been sent but not yet acknowledged.
158
202
  */
@@ -172,12 +216,6 @@ var Session = class {
172
216
  * for this session.
173
217
  */
174
218
  advertisedSessionId;
175
- /**
176
- * The metadata for this session, as parsed from the handshake.
177
- *
178
- * Will only ever be populated on the server side.
179
- */
180
- metadata;
181
219
  /**
182
220
  * Number of messages we've sent along this session (excluding handshake and acks)
183
221
  */
@@ -199,7 +237,7 @@ var Session = class {
199
237
  * The interval for sending heartbeats.
200
238
  */
201
239
  heartbeat;
202
- constructor(conn, from, to, options) {
240
+ constructor(conn, from, to, options, propagationCtx) {
203
241
  this.id = `session-${nanoid2(12)}`;
204
242
  this.options = options;
205
243
  this.from = from;
@@ -211,13 +249,14 @@ var Session = class {
211
249
  () => this.sendHeartbeat(),
212
250
  options.heartbeatIntervalMs
213
251
  );
252
+ this.telemetry = createSessionTelemetryInfo(this, propagationCtx);
214
253
  }
215
254
  get loggingMetadata() {
216
255
  return {
217
256
  clientId: this.from,
218
257
  connectedTo: this.to,
219
258
  sessionId: this.id,
220
- connId: this.connection?.debugId
259
+ connId: this.connection?.id
221
260
  };
222
261
  }
223
262
  /**
@@ -262,6 +301,7 @@ var Session = class {
262
301
  `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
263
302
  this.loggingMetadata
264
303
  );
304
+ this.telemetry.span.addEvent("closing connection due to inactivity");
265
305
  this.closeStaleConnection();
266
306
  }
267
307
  return;
@@ -283,21 +323,25 @@ var Session = class {
283
323
  sendBufferedMessages(conn) {
284
324
  log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
285
325
  ...this.loggingMetadata,
286
- connId: conn.debugId
326
+ connId: conn.id
287
327
  });
288
328
  for (const msg of this.sendBuffer) {
289
329
  log?.debug(`resending msg`, {
290
330
  ...this.loggingMetadata,
291
331
  fullTransportMessage: msg,
292
- connId: conn.debugId
332
+ connId: conn.id
293
333
  });
294
334
  const ok = conn.send(this.codec.toBuffer(msg));
295
335
  if (!ok) {
296
336
  const errMsg = `failed to send buffered message to ${this.to} (sus, this is a fresh connection)`;
337
+ conn.telemetry?.span.setStatus({
338
+ code: import_api2.SpanStatusCode.ERROR,
339
+ message: errMsg
340
+ });
297
341
  log?.error(errMsg, {
298
342
  ...this.loggingMetadata,
299
343
  fullTransportMessage: msg,
300
- connId: conn.debugId,
344
+ connId: conn.id,
301
345
  tags: ["invariant-violation"]
302
346
  });
303
347
  conn.close();
@@ -380,11 +424,6 @@ var Session = class {
380
424
  }
381
425
  };
382
426
 
383
- // tracing/index.ts
384
- var import_api = require("@opentelemetry/api");
385
- var tracer = import_api.trace.getTracer("river");
386
- var tracing_default = tracer;
387
-
388
427
  // util/stringify.ts
389
428
  function coerceErrorString(err) {
390
429
  if (err instanceof Error) {
@@ -446,6 +485,7 @@ var NaiveJsonCodec = {
446
485
  };
447
486
 
448
487
  // transport/transport.ts
488
+ var import_api3 = require("@opentelemetry/api");
449
489
  var defaultTransportOptions = {
450
490
  heartbeatIntervalMs: 1e3,
451
491
  heartbeatsUntilDead: 2,
@@ -524,17 +564,22 @@ var Transport = class {
524
564
  status: "connect",
525
565
  conn
526
566
  });
567
+ conn.telemetry = createConnectionTelemetryInfo(
568
+ conn,
569
+ session.telemetry.span
570
+ );
527
571
  if (isReconnect) {
528
572
  session.replaceWithNewConnection(conn);
529
573
  log?.info(`reconnected to ${connectedTo}`, session.loggingMetadata);
530
574
  }
531
575
  }
532
- createSession(to, conn) {
576
+ createSession(to, conn, propagationCtx) {
533
577
  const session = new Session(
534
578
  conn,
535
579
  this.clientId,
536
580
  to,
537
- this.options
581
+ this.options,
582
+ propagationCtx
538
583
  );
539
584
  this.sessions.set(session.to, session);
540
585
  this.eventDispatcher.dispatchEvent("sessionStatus", {
@@ -543,11 +588,11 @@ var Transport = class {
543
588
  });
544
589
  return session;
545
590
  }
546
- getOrCreateSession(to, conn, sessionId) {
591
+ getOrCreateSession(to, conn, sessionId, propagationCtx) {
547
592
  let session = this.sessions.get(to);
548
593
  let isReconnect = session !== void 0;
549
594
  if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
550
- log?.warn(
595
+ log?.info(
551
596
  `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
552
597
  session.loggingMetadata
553
598
  );
@@ -556,7 +601,7 @@ var Transport = class {
556
601
  session = void 0;
557
602
  }
558
603
  if (!session) {
559
- session = this.createSession(to, conn);
604
+ session = this.createSession(to, conn, propagationCtx);
560
605
  log?.info(
561
606
  `no session for ${to}, created a new one`,
562
607
  session.loggingMetadata
@@ -569,6 +614,7 @@ var Transport = class {
569
614
  }
570
615
  deleteSession(session) {
571
616
  session.close();
617
+ session.telemetry.span.end();
572
618
  this.sessions.delete(session.to);
573
619
  log?.info(
574
620
  `session ${session.id} disconnect from ${session.to}`,
@@ -585,12 +631,16 @@ var Transport = class {
585
631
  * @param connectedTo The peer we are connected to.
586
632
  */
587
633
  onDisconnect(conn, session) {
634
+ conn.telemetry?.span.end();
588
635
  this.eventDispatcher.dispatchEvent("connectionStatus", {
589
636
  status: "disconnect",
590
637
  conn
591
638
  });
592
639
  session.connection = void 0;
593
- session.beginGrace(() => this.deleteSession(session));
640
+ session.beginGrace(() => {
641
+ session.telemetry.span.addEvent("session grace period expired");
642
+ this.deleteSession(session);
643
+ });
594
644
  }
595
645
  /**
596
646
  * Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
@@ -650,6 +700,10 @@ var Transport = class {
650
700
  tags: ["invariant-violation"]
651
701
  });
652
702
  this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
703
+ session.telemetry.span.setStatus({
704
+ code: import_api3.SpanStatusCode.ERROR,
705
+ message: "message order violated"
706
+ });
653
707
  session.close();
654
708
  }
655
709
  return;
@@ -748,280 +802,240 @@ var ServerTransport = class extends Transport {
748
802
  * The options for this transport.
749
803
  */
750
804
  options;
805
+ /**
806
+ * Optional handshake options for the server.
807
+ */
808
+ handshakeExtensions;
809
+ /**
810
+ * A map of session handshake data for each session.
811
+ */
812
+ sessionHandshakeMetadata;
751
813
  constructor(clientId, providedOptions) {
752
814
  super(clientId, providedOptions);
753
815
  this.options = {
754
816
  ...defaultServerTransportOptions,
755
817
  ...providedOptions
756
818
  };
819
+ this.sessionHandshakeMetadata = /* @__PURE__ */ new WeakMap();
757
820
  log?.info(`initiated server transport`, {
758
821
  clientId: this.clientId,
759
822
  protocolVersion: PROTOCOL_VERSION
760
823
  });
761
824
  }
825
+ extendHandshake(options) {
826
+ this.handshakeExtensions = options;
827
+ }
762
828
  handleConnection(conn) {
763
- tracing_default.startActiveSpan(
764
- "handleConnection",
765
- {
766
- attributes: {
767
- component: "river",
768
- "span.kind": "server"
769
- },
770
- kind: import_api2.SpanKind.SERVER
771
- },
772
- (span) => {
773
- if (this.state !== "open")
774
- return;
775
- log?.info(`new incoming connection`, {
776
- clientId: this.clientId,
777
- connId: conn.debugId
829
+ if (this.state !== "open")
830
+ return;
831
+ log?.info(`new incoming connection`, {
832
+ clientId: this.clientId,
833
+ connId: conn.id
834
+ });
835
+ let session = void 0;
836
+ const client = () => session?.to ?? "unknown";
837
+ const handshakeTimeout = setTimeout(() => {
838
+ if (!session) {
839
+ log?.warn(
840
+ `connection to ${client()} timed out waiting for handshake, closing`,
841
+ {
842
+ clientId: this.clientId,
843
+ connectedTo: client(),
844
+ connId: conn.id
845
+ }
846
+ );
847
+ conn.telemetry?.span.setStatus({
848
+ code: import_api3.SpanStatusCode.ERROR,
849
+ message: "handshake timeout"
778
850
  });
779
- let session = void 0;
780
- const client = () => session?.to ?? "unknown";
781
- const handshakeTimeout = setTimeout(() => {
782
- if (!session) {
783
- log?.warn(
784
- `connection to ${client()} timed out waiting for handshake, closing`,
785
- {
786
- clientId: this.clientId,
787
- connectedTo: client(),
788
- connId: conn.debugId
789
- }
790
- );
791
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
792
- span.end();
851
+ conn.close();
852
+ }
853
+ }, this.options.sessionDisconnectGraceMs);
854
+ const buffer = [];
855
+ let receivedHandshakeMessage = false;
856
+ const handshakeHandler = (data) => {
857
+ if (receivedHandshakeMessage) {
858
+ buffer.push(data);
859
+ return;
860
+ }
861
+ receivedHandshakeMessage = true;
862
+ clearTimeout(handshakeTimeout);
863
+ void this.receiveHandshakeRequestMessage(data, conn).then(
864
+ (maybeSession) => {
865
+ if (!maybeSession) {
793
866
  conn.close();
794
- }
795
- }, this.options.sessionDisconnectGraceMs);
796
- const buffer = [];
797
- let receivedHandshakeMessage = false;
798
- const handshakeHandler = (data) => {
799
- if (receivedHandshakeMessage) {
800
- buffer.push(data);
801
867
  return;
802
868
  }
803
- receivedHandshakeMessage = true;
804
- clearTimeout(handshakeTimeout);
805
- void this.receiveHandshakeRequestMessage(data, conn).then(
806
- (maybeSession) => {
807
- if (!maybeSession) {
808
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
809
- span.end();
810
- conn.close();
811
- return;
812
- }
813
- session = maybeSession;
814
- const dataHandler = (data2) => {
815
- const parsed = this.parseMsg(data2);
816
- if (!parsed) {
817
- conn.close();
818
- return;
819
- }
820
- this.handleMsg(parsed);
821
- };
822
- conn.removeDataListener(handshakeHandler);
823
- conn.addDataListener(dataHandler);
824
- for (const data2 of buffer) {
825
- dataHandler(data2);
826
- }
827
- buffer.length = 0;
869
+ session = maybeSession;
870
+ const dataHandler = (data2) => {
871
+ const parsed = this.parseMsg(data2);
872
+ if (!parsed) {
873
+ conn.close();
874
+ return;
828
875
  }
829
- );
830
- };
831
- conn.addDataListener(handshakeHandler);
832
- conn.addCloseListener(() => {
833
- if (session) {
834
- log?.info(`connection to ${client()} disconnected`, {
835
- clientId: this.clientId,
836
- connId: conn.debugId
837
- });
838
- this.onDisconnect(conn, session);
876
+ this.handleMsg(parsed);
877
+ };
878
+ for (const data2 of buffer) {
879
+ dataHandler(data2);
839
880
  }
840
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
841
- span.end();
881
+ conn.removeDataListener(handshakeHandler);
882
+ conn.addDataListener(dataHandler);
883
+ buffer.length = 0;
884
+ }
885
+ );
886
+ };
887
+ conn.addDataListener(handshakeHandler);
888
+ conn.addCloseListener(() => {
889
+ if (!session)
890
+ return;
891
+ log?.info(`connection to ${client()} disconnected`, {
892
+ clientId: this.clientId,
893
+ connId: conn.id
894
+ });
895
+ this.onDisconnect(conn, session);
896
+ });
897
+ conn.addErrorListener((err) => {
898
+ conn.telemetry?.span.setStatus({
899
+ code: import_api3.SpanStatusCode.ERROR,
900
+ message: "connection error"
901
+ });
902
+ if (!session)
903
+ return;
904
+ log?.warn(
905
+ `connection to ${client()} got an error: ${coerceErrorString(err)}`,
906
+ { clientId: this.clientId, connId: conn.id }
907
+ );
908
+ });
909
+ }
910
+ async validateHandshakeMetadata(conn, session, rawMetadata, from) {
911
+ let parsedMetadata = {};
912
+ if (this.handshakeExtensions) {
913
+ if (!import_value.Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
914
+ conn.telemetry?.span.setStatus({
915
+ code: import_api3.SpanStatusCode.ERROR,
916
+ message: "malformed handshake meta"
842
917
  });
843
- conn.addErrorListener((err) => {
844
- if (session) {
845
- log?.warn(
846
- `connection to ${client()} got an error: ${coerceErrorString(
847
- err
848
- )}`,
849
- { clientId: this.clientId, connId: conn.debugId }
850
- );
851
- }
852
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
853
- span.end();
918
+ const reason = "received malformed handshake metadata";
919
+ const responseMsg = handshakeResponseMessage(this.clientId, from, {
920
+ ok: false,
921
+ reason
922
+ });
923
+ conn.send(this.codec.toBuffer(responseMsg));
924
+ log?.warn(`received malformed handshake metadata from ${from}`, {
925
+ clientId: this.clientId,
926
+ connId: conn.id
854
927
  });
928
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
929
+ return false;
855
930
  }
856
- );
931
+ parsedMetadata = await this.handshakeExtensions.validate(
932
+ rawMetadata,
933
+ session
934
+ );
935
+ if (parsedMetadata === false) {
936
+ const reason = "rejected by handshake handler";
937
+ conn.telemetry?.span.setStatus({
938
+ code: import_api3.SpanStatusCode.ERROR,
939
+ message: reason
940
+ });
941
+ const responseMsg = handshakeResponseMessage(this.clientId, from, {
942
+ ok: false,
943
+ reason
944
+ });
945
+ conn.send(this.codec.toBuffer(responseMsg));
946
+ log?.warn(`rejected handshake from ${from}`, {
947
+ clientId: this.clientId,
948
+ connId: conn.id
949
+ });
950
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
951
+ return false;
952
+ }
953
+ }
954
+ return parsedMetadata;
857
955
  }
858
956
  async receiveHandshakeRequestMessage(data, conn) {
859
957
  const parsed = this.parseMsg(data);
860
958
  if (!parsed) {
959
+ conn.telemetry?.span.setStatus({
960
+ code: import_api3.SpanStatusCode.ERROR,
961
+ message: "non-transport message"
962
+ });
861
963
  this.protocolError(
862
964
  ProtocolError.HandshakeFailed,
863
965
  "received non-transport message"
864
966
  );
865
967
  return false;
866
968
  }
867
- let activeContext = import_api2.context.active();
868
- if (parsed.tracing) {
869
- activeContext = import_api2.propagation.extract(activeContext, parsed.tracing);
969
+ if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
970
+ conn.telemetry?.span.setStatus({
971
+ code: import_api3.SpanStatusCode.ERROR,
972
+ message: "invalid handshake request"
973
+ });
974
+ const reason = "received invalid handshake msg";
975
+ const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
976
+ ok: false,
977
+ reason
978
+ });
979
+ conn.send(this.codec.toBuffer(responseMsg2));
980
+ const logData = { ...parsed.payload ?? {}, metadata: "redacted" };
981
+ log?.warn(reason, {
982
+ clientId: this.clientId,
983
+ connId: conn.id,
984
+ partialTransportMessage: { ...parsed, payload: logData }
985
+ });
986
+ this.protocolError(
987
+ ProtocolError.HandshakeFailed,
988
+ "invalid handshake request"
989
+ );
990
+ return false;
870
991
  }
871
- return tracing_default.startActiveSpan(
872
- "receiveHandshakeRequestMessage",
873
- {
874
- attributes: {
875
- component: "river",
876
- "span.kind": "server"
877
- },
878
- kind: import_api2.SpanKind.SERVER
879
- },
880
- activeContext,
881
- async (span) => {
882
- if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
883
- const reason = "received invalid handshake msg";
884
- const responseMsg2 = handshakeResponseMessage(
885
- this.clientId,
886
- parsed.from,
887
- {
888
- ok: false,
889
- reason
890
- }
891
- );
892
- conn.send(this.codec.toBuffer(responseMsg2));
893
- const logData = typeof parsed.payload === "object" ? {
894
- ...parsed,
895
- payload: { ...parsed.payload, metadata: "redacted" }
896
- } : { ...parsed };
897
- log?.warn(`${reason}: ${JSON.stringify(logData)}`, {
898
- clientId: this.clientId,
899
- connId: conn.debugId
900
- });
901
- this.protocolError(
902
- ProtocolError.HandshakeFailed,
903
- "invalid handshake request"
904
- );
905
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
906
- span.end();
907
- return false;
908
- }
909
- const gotVersion = parsed.payload.protocolVersion;
910
- if (gotVersion !== PROTOCOL_VERSION) {
911
- const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
912
- const responseMsg2 = handshakeResponseMessage(
913
- this.clientId,
914
- parsed.from,
915
- {
916
- ok: false,
917
- reason
918
- }
919
- );
920
- conn.send(this.codec.toBuffer(responseMsg2));
921
- log?.warn(
922
- `received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`,
923
- { clientId: this.clientId, connId: conn.debugId }
924
- );
925
- this.protocolError(ProtocolError.HandshakeFailed, reason);
926
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
927
- span.end();
928
- return false;
929
- }
930
- const { session, isReconnect } = this.getOrCreateSession(
931
- parsed.from,
932
- conn,
933
- parsed.payload.sessionId
934
- );
935
- let handshakeMetadata;
936
- if (this.options.handshake) {
937
- if (!import_value.Value.Check(
938
- this.options.handshake.requestSchema,
939
- parsed.payload.metadata
940
- )) {
941
- const reason = "received malformed handshake metadata";
942
- const responseMsg2 = handshakeResponseMessage(
943
- this.clientId,
944
- parsed.from,
945
- { ok: false, reason }
946
- );
947
- conn.send(this.codec.toBuffer(responseMsg2));
948
- log?.warn(
949
- `received malformed handshake metadata from ${parsed.from}`,
950
- {
951
- clientId: this.clientId,
952
- connId: conn.debugId
953
- }
954
- );
955
- this.protocolError(ProtocolError.HandshakeFailed, reason);
956
- this.deleteSession(session);
957
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
958
- span.end();
959
- return false;
960
- }
961
- const parsedMetadata = await this.options.handshake.parse(
962
- parsed.payload.metadata,
963
- session,
964
- isReconnect
965
- );
966
- if (parsedMetadata === false) {
967
- const reason = "rejected by server";
968
- const responseMsg2 = handshakeResponseMessage(
969
- this.clientId,
970
- parsed.from,
971
- { ok: false, reason }
972
- );
973
- conn.send(this.codec.toBuffer(responseMsg2));
974
- log?.warn(`rejected handshake from ${parsed.from}`, {
975
- clientId: this.clientId,
976
- connId: conn.debugId
977
- });
978
- this.protocolError(ProtocolError.HandshakeFailed, reason);
979
- this.deleteSession(session);
980
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
981
- span.end();
982
- return false;
983
- }
984
- if (!import_value.Value.Check(this.options.handshake.parsedSchema, parsedMetadata)) {
985
- const reason = "failed to parse handshake metadata";
986
- const responseMsg2 = handshakeResponseMessage(
987
- this.clientId,
988
- parsed.from,
989
- { ok: false, reason }
990
- );
991
- conn.send(this.codec.toBuffer(responseMsg2));
992
- log?.error(`failed to parse handshake metadata`, {
993
- clientId: this.clientId,
994
- connId: conn.debugId,
995
- tags: ["invariant-violation"]
996
- });
997
- this.protocolError(ProtocolError.HandshakeFailed, reason);
998
- this.deleteSession(session);
999
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
1000
- span.end();
1001
- return false;
1002
- }
1003
- handshakeMetadata = parsedMetadata;
1004
- }
1005
- handshakeMetadata ??= {};
1006
- session.metadata = handshakeMetadata;
1007
- log?.debug(
1008
- `handshake from ${parsed.from} ok, responding with handshake success`,
1009
- { clientId: this.clientId, connId: conn.debugId }
1010
- );
1011
- const responseMsg = handshakeResponseMessage(
1012
- this.clientId,
1013
- parsed.from,
1014
- {
1015
- ok: true,
1016
- sessionId: session.id
1017
- }
1018
- );
1019
- conn.send(this.codec.toBuffer(responseMsg));
1020
- this.onConnect(conn, parsed.from, session, isReconnect);
1021
- span.end();
1022
- return session;
1023
- }
992
+ const gotVersion = parsed.payload.protocolVersion;
993
+ if (gotVersion !== PROTOCOL_VERSION) {
994
+ conn.telemetry?.span.setStatus({
995
+ code: import_api3.SpanStatusCode.ERROR,
996
+ message: "incorrect protocol version"
997
+ });
998
+ const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
999
+ const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1000
+ ok: false,
1001
+ reason
1002
+ });
1003
+ conn.send(this.codec.toBuffer(responseMsg2));
1004
+ log?.warn(
1005
+ `received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`,
1006
+ { clientId: this.clientId, connId: conn.id }
1007
+ );
1008
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
1009
+ return false;
1010
+ }
1011
+ const oldSession = this.sessions.get(parsed.from);
1012
+ const parsedMetadata = await this.validateHandshakeMetadata(
1013
+ conn,
1014
+ oldSession,
1015
+ parsed.payload.metadata,
1016
+ parsed.from
1024
1017
  );
1018
+ if (parsedMetadata === false) {
1019
+ return false;
1020
+ }
1021
+ const { session, isReconnect } = this.getOrCreateSession(
1022
+ parsed.from,
1023
+ conn,
1024
+ parsed.payload.sessionId,
1025
+ parsed.tracing
1026
+ );
1027
+ this.sessionHandshakeMetadata.set(session, parsedMetadata);
1028
+ log?.debug(
1029
+ `handshake from ${parsed.from} ok, responding with handshake success`,
1030
+ { clientId: this.clientId, connId: conn.id }
1031
+ );
1032
+ const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
1033
+ ok: true,
1034
+ sessionId: session.id
1035
+ });
1036
+ conn.send(this.codec.toBuffer(responseMsg));
1037
+ this.onConnect(conn, parsed.from, session, isReconnect);
1038
+ return session;
1025
1039
  }
1026
1040
  };
1027
1041