@replit/river 0.23.8 → 0.23.10

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 (54) hide show
  1. package/dist/{chunk-WQRQFAP6.js → chunk-B323CECK.js} +473 -15
  2. package/dist/chunk-B323CECK.js.map +1 -0
  3. package/dist/{chunk-ELZRZNA5.js → chunk-FRICSBDW.js} +2 -2
  4. package/dist/chunk-FRICSBDW.js.map +1 -0
  5. package/dist/{chunk-RJ6CXPBM.js → chunk-KBAZ5TWE.js} +129 -65
  6. package/dist/chunk-KBAZ5TWE.js.map +1 -0
  7. package/dist/{chunk-DXTG3E3B.js → chunk-UXQMGZKP.js} +2 -2
  8. package/dist/{chunk-CBNCT4B3.js → chunk-Z4G27Y2I.js} +2 -2
  9. package/dist/{connection-6ce35bd5.d.ts → connection-700340c4.d.ts} +1 -1
  10. package/dist/{connection-a3fdfa3a.d.ts → connection-efcd4e1a.d.ts} +1 -1
  11. package/dist/router/index.cjs +473 -14
  12. package/dist/router/index.cjs.map +1 -1
  13. package/dist/router/index.d.cts +41 -7
  14. package/dist/router/index.d.ts +41 -7
  15. package/dist/router/index.js +4 -2
  16. package/dist/{services-fd8a9894.d.ts → services-409c5545.d.ts} +10 -9
  17. package/dist/transport/impls/uds/client.cjs +122 -58
  18. package/dist/transport/impls/uds/client.cjs.map +1 -1
  19. package/dist/transport/impls/uds/client.d.cts +2 -2
  20. package/dist/transport/impls/uds/client.d.ts +2 -2
  21. package/dist/transport/impls/uds/client.js +3 -3
  22. package/dist/transport/impls/uds/server.cjs +103 -47
  23. package/dist/transport/impls/uds/server.cjs.map +1 -1
  24. package/dist/transport/impls/uds/server.d.cts +2 -2
  25. package/dist/transport/impls/uds/server.d.ts +2 -2
  26. package/dist/transport/impls/uds/server.js +3 -3
  27. package/dist/transport/impls/ws/client.cjs +125 -58
  28. package/dist/transport/impls/ws/client.cjs.map +1 -1
  29. package/dist/transport/impls/ws/client.d.cts +2 -2
  30. package/dist/transport/impls/ws/client.d.ts +2 -2
  31. package/dist/transport/impls/ws/client.js +6 -3
  32. package/dist/transport/impls/ws/client.js.map +1 -1
  33. package/dist/transport/impls/ws/server.cjs +103 -47
  34. package/dist/transport/impls/ws/server.cjs.map +1 -1
  35. package/dist/transport/impls/ws/server.d.cts +2 -2
  36. package/dist/transport/impls/ws/server.d.ts +2 -2
  37. package/dist/transport/impls/ws/server.js +3 -3
  38. package/dist/transport/index.cjs +128 -64
  39. package/dist/transport/index.cjs.map +1 -1
  40. package/dist/transport/index.d.cts +1 -1
  41. package/dist/transport/index.d.ts +1 -1
  42. package/dist/transport/index.js +2 -2
  43. package/dist/{transport-3d34f714.d.ts → transport-cf856c41.d.ts} +46 -24
  44. package/dist/util/testHelpers.cjs +46 -4
  45. package/dist/util/testHelpers.cjs.map +1 -1
  46. package/dist/util/testHelpers.d.cts +2 -2
  47. package/dist/util/testHelpers.d.ts +2 -2
  48. package/dist/util/testHelpers.js +3 -3
  49. package/package.json +3 -3
  50. package/dist/chunk-ELZRZNA5.js.map +0 -1
  51. package/dist/chunk-RJ6CXPBM.js.map +0 -1
  52. package/dist/chunk-WQRQFAP6.js.map +0 -1
  53. /package/dist/{chunk-DXTG3E3B.js.map → chunk-UXQMGZKP.js.map} +0 -0
  54. /package/dist/{chunk-CBNCT4B3.js.map → chunk-Z4G27Y2I.js.map} +0 -0
@@ -184,11 +184,13 @@ var createLogProxy = (log) => ({
184
184
  var ProtocolError = {
185
185
  RetriesExceeded: "conn_retry_exceeded",
186
186
  HandshakeFailed: "handshake_failed",
187
- UseAfterDestroy: "use_after_destroy",
188
187
  MessageOrderingViolated: "message_ordering_violated"
189
188
  };
190
189
  var EventDispatcher = class {
191
190
  eventListeners = {};
191
+ removeAllListeners() {
192
+ this.eventListeners = {};
193
+ }
192
194
  numberOfListeners(eventType) {
193
195
  return this.eventListeners[eventType]?.size ?? 0;
194
196
  }
@@ -207,7 +209,8 @@ var EventDispatcher = class {
207
209
  dispatchEvent(eventType, event) {
208
210
  const handlers = this.eventListeners[eventType];
209
211
  if (handlers) {
210
- for (const handler of handlers) {
212
+ const copy = [...handlers];
213
+ for (const handler of copy) {
211
214
  handler(event);
212
215
  }
213
216
  }
@@ -221,7 +224,7 @@ var import_nanoid2 = require("nanoid");
221
224
  var import_api = require("@opentelemetry/api");
222
225
 
223
226
  // package.json
224
- var version = "0.23.8";
227
+ var version = "0.23.10";
225
228
 
226
229
  // tracing/index.ts
227
230
  function getPropagationContext(ctx) {
@@ -280,7 +283,7 @@ var Connection = class {
280
283
  get loggingMetadata() {
281
284
  const metadata = { connId: this.id };
282
285
  const spanContext = this.telemetry?.span.spanContext();
283
- if (spanContext) {
286
+ if (this.telemetry?.span.isRecording() && spanContext) {
284
287
  metadata.telemetry = {
285
288
  traceId: spanContext.traceId,
286
289
  spanId: spanContext.spanId
@@ -301,6 +304,11 @@ var Session = class {
301
304
  * The active connection associated with this session
302
305
  */
303
306
  connection;
307
+ /**
308
+ * A connection that is currently undergoing handshaking. Used to distinguish between the active
309
+ * connection, but still be able to close it if needed.
310
+ */
311
+ handshakingConnection;
304
312
  from;
305
313
  to;
306
314
  /**
@@ -480,23 +488,60 @@ var Session = class {
480
488
  this.cancelGrace();
481
489
  this.sendBufferedMessages(newConn);
482
490
  this.connection = newConn;
491
+ this.handshakingConnection = void 0;
492
+ }
493
+ replaceWithNewHandshakingConnection(newConn) {
494
+ this.handshakingConnection = newConn;
483
495
  }
484
496
  beginGrace(cb) {
485
497
  this.log?.info(
486
498
  `starting ${this.options.sessionDisconnectGraceMs}ms grace period until session to ${this.to} is closed`,
487
499
  this.loggingMetadata
488
500
  );
501
+ this.cancelGrace({ keepHeartbeatMisses: true });
489
502
  this.disconnectionGrace = setTimeout(() => {
490
- this.close();
503
+ if (this.connection !== void 0) {
504
+ this.log?.warn(
505
+ `grace period for ${this.to} elapsed while connected. not calling callback`,
506
+ {
507
+ ...this.loggingMetadata,
508
+ connId: this.connection.id,
509
+ tags: ["invariant-violation"]
510
+ }
511
+ );
512
+ return;
513
+ }
514
+ this.log?.info(
515
+ `grace period for ${this.to} elapsed`,
516
+ this.loggingMetadata
517
+ );
491
518
  cb();
492
519
  }, this.options.sessionDisconnectGraceMs);
493
520
  }
494
521
  // called on reconnect of the underlying session
495
- cancelGrace() {
496
- this.heartbeatMisses = 0;
522
+ cancelGrace({ keepHeartbeatMisses } = {
523
+ keepHeartbeatMisses: false
524
+ }) {
525
+ if (!keepHeartbeatMisses) {
526
+ this.heartbeatMisses = 0;
527
+ }
528
+ if (this.disconnectionGrace === void 0)
529
+ return;
497
530
  clearTimeout(this.disconnectionGrace);
498
531
  this.disconnectionGrace = void 0;
499
532
  }
533
+ /**
534
+ * Used to close the handshaking connection, if set.
535
+ */
536
+ closeHandshakingConnection(expectedHandshakingConn) {
537
+ if (this.handshakingConnection === void 0)
538
+ return;
539
+ if (expectedHandshakingConn !== void 0 && this.handshakingConnection === expectedHandshakingConn) {
540
+ return;
541
+ }
542
+ this.handshakingConnection.close();
543
+ this.handshakingConnection = void 0;
544
+ }
500
545
  // closed when we want to discard the whole session
501
546
  // (i.e. shutdown or session disconnect)
502
547
  close() {
@@ -684,10 +729,9 @@ var defaultServerTransportOptions = {
684
729
  };
685
730
  var Transport = class {
686
731
  /**
687
- * A flag indicating whether the transport has been destroyed.
688
- * A destroyed transport will not attempt to reconnect and cannot be used again.
732
+ * The status of the transport.
689
733
  */
690
- state;
734
+ status;
691
735
  /**
692
736
  * The {@link Codec} used to encode and decode messages.
693
737
  */
@@ -729,7 +773,7 @@ var Transport = class {
729
773
  this.sessions = /* @__PURE__ */ new Map();
730
774
  this.codec = this.options.codec;
731
775
  this.clientId = clientId;
732
- this.state = "open";
776
+ this.status = "open";
733
777
  }
734
778
  bindLogger(fn, level) {
735
779
  if (typeof fn === "function") {
@@ -777,7 +821,13 @@ var Transport = class {
777
821
  });
778
822
  return session;
779
823
  }
780
- getOrCreateSession(to, conn, sessionId, propagationCtx) {
824
+ getOrCreateSession({
825
+ to,
826
+ conn,
827
+ handshakingConn,
828
+ sessionId,
829
+ propagationCtx
830
+ }) {
781
831
  let session = this.sessions.get(to);
782
832
  let isReconnect = session !== void 0;
783
833
  if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
@@ -785,7 +835,11 @@ var Transport = class {
785
835
  `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
786
836
  session.loggingMetadata
787
837
  );
788
- this.deleteSession(session);
838
+ this.deleteSession({
839
+ session,
840
+ closeHandshakingConnection: handshakingConn !== void 0,
841
+ handshakingConn
842
+ });
789
843
  isReconnect = false;
790
844
  session = void 0;
791
845
  }
@@ -799,9 +853,19 @@ var Transport = class {
799
853
  if (sessionId !== void 0) {
800
854
  session.advertisedSessionId = sessionId;
801
855
  }
856
+ if (handshakingConn !== void 0) {
857
+ session.replaceWithNewHandshakingConnection(handshakingConn);
858
+ }
802
859
  return { session, isReconnect };
803
860
  }
804
- deleteSession(session) {
861
+ deleteSession({
862
+ session,
863
+ closeHandshakingConnection,
864
+ handshakingConn
865
+ }) {
866
+ if (closeHandshakingConnection) {
867
+ session.closeHandshakingConnection(handshakingConn);
868
+ }
805
869
  session.close();
806
870
  session.telemetry.span.end();
807
871
  this.sessions.delete(session.to);
@@ -828,7 +892,11 @@ var Transport = class {
828
892
  session.connection = void 0;
829
893
  session.beginGrace(() => {
830
894
  session.telemetry.span.addEvent("session grace period expired");
831
- this.deleteSession(session);
895
+ this.deleteSession({
896
+ session,
897
+ closeHandshakingConnection: true,
898
+ handshakingConn: conn
899
+ });
832
900
  });
833
901
  }
834
902
  /**
@@ -867,7 +935,7 @@ var Transport = class {
867
935
  * @param msg The received message.
868
936
  */
869
937
  handleMsg(msg, conn) {
870
- if (this.state !== "open")
938
+ if (this.getStatus() !== "open")
871
939
  return;
872
940
  const session = this.sessions.get(msg.from);
873
941
  if (!session) {
@@ -908,7 +976,7 @@ var Transport = class {
908
976
  code: import_api3.SpanStatusCode.ERROR,
909
977
  message: "message order violated"
910
978
  });
911
- session.close();
979
+ this.deleteSession({ session, closeHandshakingConnection: true });
912
980
  }
913
981
  return;
914
982
  }
@@ -946,23 +1014,16 @@ var Transport = class {
946
1014
  * @returns The ID of the sent message or undefined if it wasn't sent
947
1015
  */
948
1016
  send(to, msg) {
949
- if (this.state === "destroyed") {
950
- const err = "transport is destroyed, cant send";
1017
+ if (this.getStatus() === "closed") {
1018
+ const err = "transport is closed, cant send";
951
1019
  this.log?.error(err, {
952
1020
  clientId: this.clientId,
953
1021
  transportMessage: msg,
954
1022
  tags: ["invariant-violation"]
955
1023
  });
956
- this.protocolError(ProtocolError.UseAfterDestroy, err);
957
- return void 0;
958
- } else if (this.state === "closed") {
959
- this.log?.info(`transport closed when sending, discarding`, {
960
- clientId: this.clientId,
961
- transportMessage: msg
962
- });
963
- return void 0;
1024
+ throw new Error(err);
964
1025
  }
965
- return this.getOrCreateSession(to).session.send(msg);
1026
+ return this.getOrCreateSession({ to }).session.send(msg);
966
1027
  }
967
1028
  // control helpers
968
1029
  sendCloseStream(to, streamId) {
@@ -983,23 +1044,18 @@ var Transport = class {
983
1044
  * Closes the transport. Any messages sent while the transport is closed will be silently discarded.
984
1045
  */
985
1046
  close() {
986
- this.state = "closed";
1047
+ this.status = "closed";
987
1048
  for (const session of this.sessions.values()) {
988
- this.deleteSession(session);
1049
+ this.deleteSession({ session, closeHandshakingConnection: true });
989
1050
  }
1051
+ this.eventDispatcher.dispatchEvent("transportStatus", {
1052
+ status: this.status
1053
+ });
1054
+ this.eventDispatcher.removeAllListeners();
990
1055
  this.log?.info(`manually closed transport`, { clientId: this.clientId });
991
1056
  }
992
- /**
993
- * Default destroy implementation for transports. You should override this in the downstream
994
- * implementation if you need to do any additional cleanup and call super.destroy() at the end.
995
- * Destroys the transport. Any messages sent while the transport is destroyed will throw an error.
996
- */
997
- destroy() {
998
- this.state = "destroyed";
999
- for (const session of this.sessions.values()) {
1000
- this.deleteSession(session);
1001
- }
1002
- this.log?.info(`manually destroyed transport`, { clientId: this.clientId });
1057
+ getStatus() {
1058
+ return this.status;
1003
1059
  }
1004
1060
  };
1005
1061
  var ClientTransport = class extends Transport {
@@ -1036,26 +1092,26 @@ var ClientTransport = class extends Transport {
1036
1092
  this.handshakeExtensions = options;
1037
1093
  }
1038
1094
  handleConnection(conn, to) {
1039
- if (this.state !== "open")
1095
+ if (this.getStatus() !== "open")
1040
1096
  return;
1041
1097
  let session = void 0;
1042
1098
  const handshakeTimeout = setTimeout(() => {
1043
- if (!session) {
1044
- this.log?.warn(
1045
- `connection to ${to} timed out waiting for handshake, closing`,
1046
- { ...conn.loggingMetadata, clientId: this.clientId, connectedTo: to }
1047
- );
1048
- conn.close();
1049
- }
1099
+ if (session)
1100
+ return;
1101
+ this.log?.warn(
1102
+ `connection to ${to} timed out waiting for handshake, closing`,
1103
+ { ...conn.loggingMetadata, clientId: this.clientId, connectedTo: to }
1104
+ );
1105
+ conn.close();
1050
1106
  }, this.options.sessionDisconnectGraceMs);
1051
1107
  const handshakeHandler = (data) => {
1052
1108
  const maybeSession = this.receiveHandshakeResponseMessage(data, conn);
1109
+ clearTimeout(handshakeTimeout);
1053
1110
  if (!maybeSession) {
1054
1111
  conn.close();
1055
1112
  return;
1056
1113
  } else {
1057
1114
  session = maybeSession;
1058
- clearTimeout(handshakeTimeout);
1059
1115
  }
1060
1116
  conn.removeDataListener(handshakeHandler);
1061
1117
  conn.addDataListener((data2) => {
@@ -1162,11 +1218,11 @@ var ClientTransport = class extends Transport {
1162
1218
  connectedTo: parsed.from,
1163
1219
  transportMessage: parsed
1164
1220
  });
1165
- const { session, isReconnect } = this.getOrCreateSession(
1166
- parsed.from,
1221
+ const { session, isReconnect } = this.getOrCreateSession({
1222
+ to: parsed.from,
1167
1223
  conn,
1168
- parsed.payload.status.sessionId
1169
- );
1224
+ sessionId: parsed.payload.status.sessionId
1225
+ });
1170
1226
  this.onConnect(conn, parsed.from, session, isReconnect);
1171
1227
  this.retryBudget.startRestoringBudget(parsed.from);
1172
1228
  return session;
@@ -1176,7 +1232,7 @@ var ClientTransport = class extends Transport {
1176
1232
  * @param to The client ID of the node to connect to.
1177
1233
  */
1178
1234
  async connect(to) {
1179
- const canProceedWithConnection = () => this.state === "open";
1235
+ const canProceedWithConnection = () => this.getStatus() === "open";
1180
1236
  if (!canProceedWithConnection()) {
1181
1237
  this.log?.info(
1182
1238
  `transport state is no longer open, cancelling attempt to connect to ${to}`,
@@ -1272,9 +1328,17 @@ var ClientTransport = class extends Transport {
1272
1328
  }
1273
1329
  }
1274
1330
  }
1275
- deleteSession(session) {
1331
+ deleteSession({
1332
+ session,
1333
+ closeHandshakingConnection,
1334
+ handshakingConn
1335
+ }) {
1276
1336
  this.inflightConnectionPromises.delete(session.to);
1277
- super.deleteSession(session);
1337
+ super.deleteSession({
1338
+ session,
1339
+ closeHandshakingConnection,
1340
+ handshakingConn
1341
+ });
1278
1342
  }
1279
1343
  async sendHandshake(to, conn) {
1280
1344
  let metadata = void 0;
@@ -1301,7 +1365,7 @@ var ClientTransport = class extends Transport {
1301
1365
  return false;
1302
1366
  }
1303
1367
  }
1304
- const { session } = this.getOrCreateSession(to);
1368
+ const { session } = this.getOrCreateSession({ to, handshakingConn: conn });
1305
1369
  const requestMsg = handshakeRequestMessage(
1306
1370
  this.clientId,
1307
1371
  to,
@@ -1352,7 +1416,7 @@ var ServerTransport = class extends Transport {
1352
1416
  this.handshakeExtensions = options;
1353
1417
  }
1354
1418
  handleConnection(conn) {
1355
- if (this.state !== "open")
1419
+ if (this.getStatus() !== "open")
1356
1420
  return;
1357
1421
  this.log?.info(`new incoming connection`, {
1358
1422
  ...conn.loggingMetadata,
@@ -1552,12 +1616,12 @@ var ServerTransport = class extends Transport {
1552
1616
  if (parsedMetadata === false) {
1553
1617
  return false;
1554
1618
  }
1555
- const { session, isReconnect } = this.getOrCreateSession(
1556
- parsed.from,
1619
+ const { session, isReconnect } = this.getOrCreateSession({
1620
+ to: parsed.from,
1557
1621
  conn,
1558
- parsed.payload.sessionId,
1559
- parsed.tracing
1560
- );
1622
+ sessionId: parsed.payload.sessionId,
1623
+ propagationCtx: parsed.tracing
1624
+ });
1561
1625
  this.sessionHandshakeMetadata.set(session, parsedMetadata);
1562
1626
  this.log?.debug(
1563
1627
  `handshake from ${parsed.from} ok, responding with handshake success`,