@replit/river 0.23.13 → 0.23.15

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 (62) hide show
  1. package/dist/{chunk-2FNLANTJ.js → chunk-5HK7ZQYH.js} +10 -2
  2. package/dist/{chunk-2FNLANTJ.js.map → chunk-5HK7ZQYH.js.map} +1 -1
  3. package/dist/{chunk-KFTGQ3QC.js → chunk-AEY7BBOZ.js} +2 -2
  4. package/dist/{chunk-S4DUN7KK.js → chunk-IJTGEBLG.js} +41 -20
  5. package/dist/chunk-IJTGEBLG.js.map +1 -0
  6. package/dist/{chunk-ZUKDZY54.js → chunk-JMVKSGND.js} +89 -25
  7. package/dist/chunk-JMVKSGND.js.map +1 -0
  8. package/dist/{chunk-XM656KMN.js → chunk-MD4S7GO2.js} +71 -3
  9. package/dist/chunk-MD4S7GO2.js.map +1 -0
  10. package/dist/{chunk-ES4XO2XD.js → chunk-OXVWMLID.js} +33 -4
  11. package/dist/chunk-OXVWMLID.js.map +1 -0
  12. package/dist/{chunk-SX6HI63Q.js → chunk-RQQZUQGE.js} +2 -2
  13. package/dist/{chunk-4QZOW4DH.js → chunk-XYEOXPZQ.js} +2 -2
  14. package/dist/{client-dd5c9dd0.d.ts → client-e13979ac.d.ts} +1 -1
  15. package/dist/{connection-39816c00.d.ts → connection-5d0978ce.d.ts} +1 -1
  16. package/dist/{connection-40318f22.d.ts → connection-e57e98ea.d.ts} +1 -1
  17. package/dist/{handshake-e428d1c8.d.ts → handshake-5665ffd3.d.ts} +13 -0
  18. package/dist/router/index.cjs +16 -1
  19. package/dist/router/index.cjs.map +1 -1
  20. package/dist/router/index.d.cts +7 -7
  21. package/dist/router/index.d.ts +7 -7
  22. package/dist/router/index.js +2 -2
  23. package/dist/{server-ebf80863.d.ts → server-1cfc88d1.d.ts} +1 -1
  24. package/dist/{services-f406b3aa.d.ts → services-86c4d10d.d.ts} +2 -2
  25. package/dist/transport/impls/uds/client.cjs +138 -18
  26. package/dist/transport/impls/uds/client.cjs.map +1 -1
  27. package/dist/transport/impls/uds/client.d.cts +3 -3
  28. package/dist/transport/impls/uds/client.d.ts +3 -3
  29. package/dist/transport/impls/uds/client.js +5 -5
  30. package/dist/transport/impls/uds/server.cjs +182 -23
  31. package/dist/transport/impls/uds/server.cjs.map +1 -1
  32. package/dist/transport/impls/uds/server.d.cts +3 -3
  33. package/dist/transport/impls/uds/server.d.ts +3 -3
  34. package/dist/transport/impls/uds/server.js +5 -5
  35. package/dist/transport/impls/ws/client.cjs +138 -18
  36. package/dist/transport/impls/ws/client.cjs.map +1 -1
  37. package/dist/transport/impls/ws/client.d.cts +3 -3
  38. package/dist/transport/impls/ws/client.d.ts +3 -3
  39. package/dist/transport/impls/ws/client.js +5 -5
  40. package/dist/transport/impls/ws/server.cjs +182 -23
  41. package/dist/transport/impls/ws/server.cjs.map +1 -1
  42. package/dist/transport/impls/ws/server.d.cts +3 -3
  43. package/dist/transport/impls/ws/server.d.ts +3 -3
  44. package/dist/transport/impls/ws/server.js +5 -5
  45. package/dist/transport/index.cjs +227 -40
  46. package/dist/transport/index.cjs.map +1 -1
  47. package/dist/transport/index.d.cts +3 -3
  48. package/dist/transport/index.d.ts +3 -3
  49. package/dist/transport/index.js +5 -5
  50. package/dist/util/testHelpers.cjs +9 -1
  51. package/dist/util/testHelpers.cjs.map +1 -1
  52. package/dist/util/testHelpers.d.cts +3 -3
  53. package/dist/util/testHelpers.d.ts +3 -3
  54. package/dist/util/testHelpers.js +3 -3
  55. package/package.json +13 -14
  56. package/dist/chunk-ES4XO2XD.js.map +0 -1
  57. package/dist/chunk-S4DUN7KK.js.map +0 -1
  58. package/dist/chunk-XM656KMN.js.map +0 -1
  59. package/dist/chunk-ZUKDZY54.js.map +0 -1
  60. /package/dist/{chunk-KFTGQ3QC.js.map → chunk-AEY7BBOZ.js.map} +0 -0
  61. /package/dist/{chunk-SX6HI63Q.js.map → chunk-RQQZUQGE.js.map} +0 -0
  62. /package/dist/{chunk-4QZOW4DH.js.map → chunk-XYEOXPZQ.js.map} +0 -0
@@ -66,6 +66,21 @@ var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
66
66
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
67
67
  protocolVersion: import_typebox.Type.String(),
68
68
  sessionId: import_typebox.Type.String(),
69
+ /**
70
+ * Specifies what the server's expected session state (from the pov of the client). This can be
71
+ * used by the server to know whether this is a new or a reestablished connection, and whether it
72
+ * is compatible with what it already has.
73
+ */
74
+ expectedSessionState: import_typebox.Type.Optional(
75
+ import_typebox.Type.Object({
76
+ /**
77
+ * reconnect is set to true if the client explicitly wants to reestablish an existing
78
+ * connection.
79
+ */
80
+ reconnect: import_typebox.Type.Boolean(),
81
+ nextExpectedSeq: import_typebox.Type.Integer()
82
+ })
83
+ ),
69
84
  metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
70
85
  });
71
86
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
@@ -90,7 +105,14 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
90
105
  var OpaqueTransportMessageSchema = TransportMessageSchema(
91
106
  import_typebox.Type.Unknown()
92
107
  );
93
- function handshakeRequestMessage(from, to, sessionId, metadata, tracing) {
108
+ function handshakeRequestMessage({
109
+ from,
110
+ to,
111
+ sessionId,
112
+ expectedSessionState,
113
+ metadata,
114
+ tracing
115
+ }) {
94
116
  return {
95
117
  id: (0, import_nanoid.nanoid)(),
96
118
  from,
@@ -104,11 +126,17 @@ function handshakeRequestMessage(from, to, sessionId, metadata, tracing) {
104
126
  type: "HANDSHAKE_REQ",
105
127
  protocolVersion: PROTOCOL_VERSION,
106
128
  sessionId,
129
+ expectedSessionState,
107
130
  metadata
108
131
  }
109
132
  };
110
133
  }
111
- function handshakeResponseMessage(from, to, status) {
134
+ var SESSION_STATE_MISMATCH = "session state mismatch";
135
+ function handshakeResponseMessage({
136
+ from,
137
+ to,
138
+ status
139
+ }) {
112
140
  return {
113
141
  id: (0, import_nanoid.nanoid)(),
114
142
  from,
@@ -224,7 +252,7 @@ var import_nanoid2 = require("nanoid");
224
252
  var import_api = require("@opentelemetry/api");
225
253
 
226
254
  // package.json
227
- var version = "0.23.13";
255
+ var version = "0.23.15";
228
256
 
229
257
  // tracing/index.ts
230
258
  function getPropagationContext(ctx) {
@@ -538,9 +566,17 @@ var Session = class {
538
566
  get connected() {
539
567
  return this.connection !== void 0;
540
568
  }
569
+ get nextExpectedAck() {
570
+ return this.seq;
571
+ }
541
572
  get nextExpectedSeq() {
542
573
  return this.ack;
543
574
  }
575
+ // This is only used in tests to make the session misbehave.
576
+ /* @internal */
577
+ advanceAckForTesting(by) {
578
+ this.ack += by;
579
+ }
544
580
  constructMsg(partialMsg) {
545
581
  const msg = {
546
582
  ...partialMsg,
@@ -720,6 +756,20 @@ var Transport = class {
720
756
  if (this.log) {
721
757
  session.bindLogger(this.log);
722
758
  }
759
+ const currentSession = this.sessions.get(session.to);
760
+ if (currentSession) {
761
+ this.log?.warn(
762
+ `session ${session.id} from ${session.to} surreptitiously replacing ${currentSession.id}`,
763
+ {
764
+ ...currentSession.loggingMetadata,
765
+ tags: ["invariant-violation"]
766
+ }
767
+ );
768
+ this.deleteSession({
769
+ session: currentSession,
770
+ closeHandshakingConnection: false
771
+ });
772
+ }
723
773
  this.sessions.set(session.to, session);
724
774
  this.eventDispatcher.dispatchEvent("sessionStatus", {
725
775
  status: "connect",
@@ -727,6 +777,49 @@ var Transport = class {
727
777
  });
728
778
  return session;
729
779
  }
780
+ createNewSession({
781
+ to,
782
+ conn,
783
+ sessionId,
784
+ propagationCtx
785
+ }) {
786
+ let session = this.sessions.get(to);
787
+ if (session !== void 0) {
788
+ this.log?.info(
789
+ `session for ${to} already exists, replacing it with a new session as requested`,
790
+ session.loggingMetadata
791
+ );
792
+ this.deleteSession({
793
+ session,
794
+ closeHandshakingConnection: false
795
+ });
796
+ session = void 0;
797
+ }
798
+ session = this.createSession(to, conn, propagationCtx);
799
+ session.advertisedSessionId = sessionId;
800
+ this.log?.info(`created new session for ${to}`, session.loggingMetadata);
801
+ return session;
802
+ }
803
+ getExistingSession({
804
+ to,
805
+ sessionId,
806
+ nextExpectedSeq
807
+ }) {
808
+ const session = this.sessions.get(to);
809
+ if (
810
+ // reject this request if there was no previous session to replace
811
+ session === void 0 || // or if both parties do not agree about the next expected sequence number
812
+ session.nextExpectedAck < nextExpectedSeq || // or if both parties do not agree on the advertised session id
813
+ session.advertisedSessionId !== sessionId
814
+ ) {
815
+ return false;
816
+ }
817
+ this.log?.info(
818
+ `reused existing session for ${to}`,
819
+ session.loggingMetadata
820
+ );
821
+ return session;
822
+ }
730
823
  getOrCreateSession({
731
824
  to,
732
825
  conn,
@@ -775,6 +868,17 @@ var Transport = class {
775
868
  }
776
869
  session.close();
777
870
  session.telemetry.span.end();
871
+ const currentSession = this.sessions.get(session.to);
872
+ if (currentSession && currentSession.id !== session.id) {
873
+ this.log?.warn(
874
+ `session ${session.id} disconnect from ${session.to}, mismatch with ${currentSession.id}`,
875
+ {
876
+ ...session.loggingMetadata,
877
+ tags: ["invariant-violation"]
878
+ }
879
+ );
880
+ return;
881
+ }
778
882
  this.sessions.delete(session.to);
779
883
  this.log?.info(
780
884
  `session ${session.id} disconnect from ${session.to}`,
@@ -1211,24 +1315,40 @@ var ClientTransport = class extends Transport {
1211
1315
  );
1212
1316
  return false;
1213
1317
  }
1318
+ const previousSession = this.sessions.get(parsed.from);
1214
1319
  if (!parsed.payload.status.ok) {
1215
- conn.telemetry?.span.setStatus({
1216
- code: import_api4.SpanStatusCode.ERROR,
1217
- message: "handshake rejected"
1218
- });
1219
- this.log?.warn(`received handshake rejection`, {
1220
- ...conn.loggingMetadata,
1221
- clientId: this.clientId,
1222
- connectedTo: parsed.from,
1223
- transportMessage: parsed
1224
- });
1320
+ if (parsed.payload.status.reason === SESSION_STATE_MISMATCH) {
1321
+ if (previousSession) {
1322
+ this.deleteSession({
1323
+ session: previousSession,
1324
+ closeHandshakingConnection: true
1325
+ });
1326
+ }
1327
+ conn.telemetry?.span.setStatus({
1328
+ code: import_api4.SpanStatusCode.ERROR,
1329
+ message: parsed.payload.status.reason
1330
+ });
1331
+ } else {
1332
+ conn.telemetry?.span.setStatus({
1333
+ code: import_api4.SpanStatusCode.ERROR,
1334
+ message: "handshake rejected"
1335
+ });
1336
+ }
1337
+ this.log?.warn(
1338
+ `received handshake rejection: ${parsed.payload.status.reason}`,
1339
+ {
1340
+ ...conn.loggingMetadata,
1341
+ clientId: this.clientId,
1342
+ connectedTo: parsed.from,
1343
+ transportMessage: parsed
1344
+ }
1345
+ );
1225
1346
  this.protocolError(
1226
1347
  ProtocolError.HandshakeFailed,
1227
1348
  parsed.payload.status.reason
1228
1349
  );
1229
1350
  return false;
1230
1351
  }
1231
- const previousSession = this.sessions.get(parsed.from);
1232
1352
  if (previousSession?.advertisedSessionId && previousSession.advertisedSessionId !== parsed.payload.status.sessionId) {
1233
1353
  this.deleteSession({
1234
1354
  session: previousSession,
@@ -1408,13 +1528,17 @@ var ClientTransport = class extends Transport {
1408
1528
  }
1409
1529
  }
1410
1530
  const { session } = this.getOrCreateSession({ to, handshakingConn: conn });
1411
- const requestMsg = handshakeRequestMessage(
1412
- this.clientId,
1531
+ const requestMsg = handshakeRequestMessage({
1532
+ from: this.clientId,
1413
1533
  to,
1414
- session.id,
1534
+ sessionId: session.id,
1535
+ expectedSessionState: {
1536
+ reconnect: session.advertisedSessionId !== void 0,
1537
+ nextExpectedSeq: session.nextExpectedSeq
1538
+ },
1415
1539
  metadata,
1416
- getPropagationContext(session.telemetry.ctx)
1417
- );
1540
+ tracing: getPropagationContext(session.telemetry.ctx)
1541
+ });
1418
1542
  this.log?.debug(`sending handshake request to ${to}`, {
1419
1543
  ...conn.loggingMetadata,
1420
1544
  clientId: this.clientId,
@@ -1552,9 +1676,13 @@ var ServerTransport = class extends Transport {
1552
1676
  message: "malformed handshake meta"
1553
1677
  });
1554
1678
  const reason = "received malformed handshake metadata";
1555
- const responseMsg = handshakeResponseMessage(this.clientId, from, {
1556
- ok: false,
1557
- reason
1679
+ const responseMsg = handshakeResponseMessage({
1680
+ from: this.clientId,
1681
+ to: from,
1682
+ status: {
1683
+ ok: false,
1684
+ reason
1685
+ }
1558
1686
  });
1559
1687
  conn.send(this.codec.toBuffer(responseMsg));
1560
1688
  this.log?.warn(`received malformed handshake metadata from ${from}`, {
@@ -1578,9 +1706,13 @@ var ServerTransport = class extends Transport {
1578
1706
  code: import_api5.SpanStatusCode.ERROR,
1579
1707
  message: reason
1580
1708
  });
1581
- const responseMsg = handshakeResponseMessage(this.clientId, from, {
1582
- ok: false,
1583
- reason
1709
+ const responseMsg = handshakeResponseMessage({
1710
+ from: this.clientId,
1711
+ to: from,
1712
+ status: {
1713
+ ok: false,
1714
+ reason
1715
+ }
1584
1716
  });
1585
1717
  conn.send(this.codec.toBuffer(responseMsg));
1586
1718
  this.log?.warn(`rejected handshake from ${from}`, {
@@ -1612,9 +1744,13 @@ var ServerTransport = class extends Transport {
1612
1744
  message: "invalid handshake request"
1613
1745
  });
1614
1746
  const reason = "received invalid handshake msg";
1615
- const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1616
- ok: false,
1617
- reason
1747
+ const responseMsg2 = handshakeResponseMessage({
1748
+ from: this.clientId,
1749
+ to: parsed.from,
1750
+ status: {
1751
+ ok: false,
1752
+ reason
1753
+ }
1618
1754
  });
1619
1755
  conn.send(this.codec.toBuffer(responseMsg2));
1620
1756
  this.log?.warn(reason, {
@@ -1640,9 +1776,13 @@ var ServerTransport = class extends Transport {
1640
1776
  message: "incorrect protocol version"
1641
1777
  });
1642
1778
  const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
1643
- const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1644
- ok: false,
1645
- reason
1779
+ const responseMsg2 = handshakeResponseMessage({
1780
+ from: this.clientId,
1781
+ to: parsed.from,
1782
+ status: {
1783
+ ok: false,
1784
+ reason
1785
+ }
1646
1786
  });
1647
1787
  conn.send(this.codec.toBuffer(responseMsg2));
1648
1788
  this.log?.warn(
@@ -1662,20 +1802,67 @@ var ServerTransport = class extends Transport {
1662
1802
  if (parsedMetadata === false) {
1663
1803
  return false;
1664
1804
  }
1665
- const { session, isTransparentReconnect } = this.getOrCreateSession({
1666
- to: parsed.from,
1667
- conn,
1668
- sessionId: parsed.payload.sessionId,
1669
- propagationCtx: parsed.tracing
1670
- });
1805
+ let session;
1806
+ let isTransparentReconnect;
1807
+ if (!parsed.payload.expectedSessionState) {
1808
+ ({ session, isTransparentReconnect } = this.getOrCreateSession({
1809
+ to: parsed.from,
1810
+ conn,
1811
+ sessionId: parsed.payload.sessionId,
1812
+ propagationCtx: parsed.tracing
1813
+ }));
1814
+ } else if (parsed.payload.expectedSessionState.reconnect) {
1815
+ const existingSession = this.getExistingSession({
1816
+ to: parsed.from,
1817
+ sessionId: parsed.payload.sessionId,
1818
+ nextExpectedSeq: parsed.payload.expectedSessionState.nextExpectedSeq
1819
+ });
1820
+ if (existingSession === false) {
1821
+ conn.telemetry?.span.setStatus({
1822
+ code: import_api5.SpanStatusCode.ERROR,
1823
+ message: SESSION_STATE_MISMATCH
1824
+ });
1825
+ const reason = SESSION_STATE_MISMATCH;
1826
+ const responseMsg2 = handshakeResponseMessage({
1827
+ from: this.clientId,
1828
+ to: parsed.from,
1829
+ status: {
1830
+ ok: false,
1831
+ reason
1832
+ }
1833
+ });
1834
+ conn.send(this.codec.toBuffer(responseMsg2));
1835
+ this.log?.warn(
1836
+ `'received handshake msg with incompatible existing session state: ${parsed.payload.sessionId}`,
1837
+ { ...conn.loggingMetadata, clientId: this.clientId }
1838
+ );
1839
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
1840
+ return false;
1841
+ }
1842
+ session = existingSession;
1843
+ isTransparentReconnect = false;
1844
+ } else {
1845
+ const createdSession = this.createNewSession({
1846
+ to: parsed.from,
1847
+ conn,
1848
+ sessionId: parsed.payload.sessionId,
1849
+ propagationCtx: parsed.tracing
1850
+ });
1851
+ session = createdSession;
1852
+ isTransparentReconnect = false;
1853
+ }
1671
1854
  this.sessionHandshakeMetadata.set(session, parsedMetadata);
1672
1855
  this.log?.debug(
1673
1856
  `handshake from ${parsed.from} ok, responding with handshake success`,
1674
1857
  conn.loggingMetadata
1675
1858
  );
1676
- const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
1677
- ok: true,
1678
- sessionId: session.id
1859
+ const responseMsg = handshakeResponseMessage({
1860
+ from: this.clientId,
1861
+ to: parsed.from,
1862
+ status: {
1863
+ ok: true,
1864
+ sessionId: session.id
1865
+ }
1679
1866
  });
1680
1867
  conn.send(this.codec.toBuffer(responseMsg));
1681
1868
  this.onConnect(conn, session, isTransparentReconnect);