@replit/river 0.200.0-rc.9 → 0.200.2

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 (72) hide show
  1. package/README.md +8 -8
  2. package/dist/{chunk-42Z2FQIU.js → chunk-6BH2CXVE.js} +21 -13
  3. package/dist/chunk-6BH2CXVE.js.map +1 -0
  4. package/dist/{chunk-4HT6P2ZG.js → chunk-A4JKES5A.js} +22 -30
  5. package/dist/chunk-A4JKES5A.js.map +1 -0
  6. package/dist/{chunk-4PVU7J25.js → chunk-AJGIY2UB.js} +1 -1
  7. package/dist/chunk-AJGIY2UB.js.map +1 -0
  8. package/dist/{chunk-EETL2L77.js → chunk-GJUUVID2.js} +14 -32
  9. package/dist/chunk-GJUUVID2.js.map +1 -0
  10. package/dist/{chunk-GR3AQKHL.js → chunk-HRKM7BIE.js} +14 -4
  11. package/dist/chunk-HRKM7BIE.js.map +1 -0
  12. package/dist/{chunk-ZXZE253M.js → chunk-PJB2Y2AV.js} +24 -37
  13. package/dist/chunk-PJB2Y2AV.js.map +1 -0
  14. package/dist/{chunk-I75XYO5W.js → chunk-QIDEN5PP.js} +82 -20
  15. package/dist/chunk-QIDEN5PP.js.map +1 -0
  16. package/dist/{chunk-VXYHC666.js → chunk-YTMS7OP6.js} +1 -1
  17. package/dist/chunk-YTMS7OP6.js.map +1 -0
  18. package/dist/chunk-Z4PX66JO.js +307 -0
  19. package/dist/chunk-Z4PX66JO.js.map +1 -0
  20. package/dist/{client-22a47343.d.ts → client-9292552a.d.ts} +3 -4
  21. package/dist/codec/index.cjs.map +1 -1
  22. package/dist/codec/index.js +1 -1
  23. package/dist/connection-94dea547.d.ts +32 -0
  24. package/dist/{context-b4aff18f.d.ts → context-69f37ac1.d.ts} +48 -43
  25. package/dist/logging/index.cjs.map +1 -1
  26. package/dist/logging/index.d.cts +1 -1
  27. package/dist/logging/index.d.ts +1 -1
  28. package/dist/logging/index.js +1 -1
  29. package/dist/{message-7d135e38.d.ts → message-57bb8187.d.ts} +5 -3
  30. package/dist/router/index.cjs +649 -709
  31. package/dist/router/index.cjs.map +1 -1
  32. package/dist/router/index.d.cts +22 -12
  33. package/dist/router/index.d.ts +22 -12
  34. package/dist/router/index.js +502 -404
  35. package/dist/router/index.js.map +1 -1
  36. package/dist/{server-dd6a9853.d.ts → server-8fdd7fb2.d.ts} +5 -5
  37. package/dist/{services-1b5ac5bc.d.ts → services-259f39a3.d.ts} +191 -194
  38. package/dist/transport/impls/ws/client.cjs +129 -62
  39. package/dist/transport/impls/ws/client.cjs.map +1 -1
  40. package/dist/transport/impls/ws/client.d.cts +4 -4
  41. package/dist/transport/impls/ws/client.d.ts +4 -4
  42. package/dist/transport/impls/ws/client.js +7 -7
  43. package/dist/transport/impls/ws/client.js.map +1 -1
  44. package/dist/transport/impls/ws/server.cjs +146 -70
  45. package/dist/transport/impls/ws/server.cjs.map +1 -1
  46. package/dist/transport/impls/ws/server.d.cts +6 -5
  47. package/dist/transport/impls/ws/server.d.ts +6 -5
  48. package/dist/transport/impls/ws/server.js +21 -9
  49. package/dist/transport/impls/ws/server.js.map +1 -1
  50. package/dist/transport/index.cjs +138 -92
  51. package/dist/transport/index.cjs.map +1 -1
  52. package/dist/transport/index.d.cts +4 -4
  53. package/dist/transport/index.d.ts +4 -4
  54. package/dist/transport/index.js +7 -7
  55. package/dist/util/testHelpers.cjs +265 -327
  56. package/dist/util/testHelpers.cjs.map +1 -1
  57. package/dist/util/testHelpers.d.cts +36 -31
  58. package/dist/util/testHelpers.d.ts +36 -31
  59. package/dist/util/testHelpers.js +82 -52
  60. package/dist/util/testHelpers.js.map +1 -1
  61. package/package.json +4 -3
  62. package/dist/chunk-42Z2FQIU.js.map +0 -1
  63. package/dist/chunk-4HT6P2ZG.js.map +0 -1
  64. package/dist/chunk-4PVU7J25.js.map +0 -1
  65. package/dist/chunk-EETL2L77.js.map +0 -1
  66. package/dist/chunk-GR3AQKHL.js.map +0 -1
  67. package/dist/chunk-I75XYO5W.js.map +0 -1
  68. package/dist/chunk-MQ6ANR3H.js +0 -451
  69. package/dist/chunk-MQ6ANR3H.js.map +0 -1
  70. package/dist/chunk-VXYHC666.js.map +0 -1
  71. package/dist/chunk-ZXZE253M.js.map +0 -1
  72. package/dist/connection-260e45a8.d.ts +0 -11
@@ -75,10 +75,7 @@ var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
75
75
  expectedSessionState: import_typebox.Type.Object({
76
76
  // what the client expects the server to send next
77
77
  nextExpectedSeq: import_typebox.Type.Integer(),
78
- // TODO: remove optional once we know all servers
79
- // are nextSentSeq here
80
- // what the server expects the client to send next
81
- nextSentSeq: import_typebox.Type.Optional(import_typebox.Type.Integer())
78
+ nextSentSeq: import_typebox.Type.Integer()
82
79
  }),
83
80
  metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
84
81
  });
@@ -114,9 +111,7 @@ var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
114
111
  import_typebox.Type.Object({
115
112
  ok: import_typebox.Type.Literal(false),
116
113
  reason: import_typebox.Type.String(),
117
- // TODO: remove optional once we know all servers
118
- // are sending code here
119
- code: import_typebox.Type.Optional(HandshakeErrorResponseCodes)
114
+ code: HandshakeErrorResponseCodes
120
115
  })
121
116
  ])
122
117
  });
@@ -360,7 +355,8 @@ var createLogProxy = (log) => ({
360
355
  var ProtocolError = {
361
356
  RetriesExceeded: "conn_retry_exceeded",
362
357
  HandshakeFailed: "handshake_failed",
363
- MessageOrderingViolated: "message_ordering_violated"
358
+ MessageOrderingViolated: "message_ordering_violated",
359
+ InvalidMessage: "invalid_message"
364
360
  };
365
361
  var EventDispatcher = class {
366
362
  eventListeners = {};
@@ -638,7 +634,7 @@ var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
638
634
  var import_api = require("@opentelemetry/api");
639
635
 
640
636
  // package.json
641
- var version = "0.200.0-rc.9";
637
+ var version = "0.200.2";
642
638
 
643
639
  // tracing/index.ts
644
640
  function getPropagationContext(ctx) {
@@ -800,13 +796,13 @@ var SessionConnected = class extends IdentifiedSession {
800
796
  this.conn.addCloseListener(this.listeners.onConnectionClosed);
801
797
  this.conn.addErrorListener(this.listeners.onConnectionErrored);
802
798
  if (this.sendBuffer.length > 0) {
803
- this.log?.debug(
804
- `sending ${this.sendBuffer.length} buffered messages`,
799
+ this.log?.info(
800
+ `sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
805
801
  this.loggingMetadata
806
802
  );
807
- }
808
- for (const msg of this.sendBuffer) {
809
- this.conn.send(this.options.codec.toBuffer(msg));
803
+ for (const msg of this.sendBuffer) {
804
+ this.conn.send(this.options.codec.toBuffer(msg));
805
+ }
810
806
  }
811
807
  this.isActivelyHeartbeating = false;
812
808
  this.heartbeatHandle = setInterval(() => {
@@ -848,6 +844,12 @@ var SessionConnected = class extends IdentifiedSession {
848
844
  }
849
845
  });
850
846
  }
847
+ closeConnection() {
848
+ this.conn.removeDataListener(this.onMessageData);
849
+ this.conn.removeCloseListener(this.listeners.onConnectionClosed);
850
+ this.conn.removeErrorListener(this.listeners.onConnectionErrored);
851
+ this.conn.close();
852
+ }
851
853
  onMessageData = (msg) => {
852
854
  const parsedMsg = this.parseMsg(msg);
853
855
  if (parsedMsg === null) {
@@ -864,8 +866,8 @@ var SessionConnected = class extends IdentifiedSession {
864
866
  }
865
867
  );
866
868
  } else {
867
- const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
868
- this.log?.error(reason, {
869
+ const reason = `received out-of-order msg, closing connection (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
870
+ this.log?.warn(reason, {
869
871
  ...this.loggingMetadata,
870
872
  transportMessage: parsedMsg,
871
873
  tags: ["invariant-violation"]
@@ -874,7 +876,7 @@ var SessionConnected = class extends IdentifiedSession {
874
876
  code: import_api2.SpanStatusCode.ERROR,
875
877
  message: reason
876
878
  });
877
- this.listeners.onInvalidMessage(reason);
879
+ this.closeConnection();
878
880
  }
879
881
  return;
880
882
  }
@@ -900,8 +902,10 @@ var SessionConnected = class extends IdentifiedSession {
900
902
  this.conn.removeDataListener(this.onMessageData);
901
903
  this.conn.removeCloseListener(this.listeners.onConnectionClosed);
902
904
  this.conn.removeErrorListener(this.listeners.onConnectionErrored);
903
- clearInterval(this.heartbeatHandle);
904
- this.heartbeatHandle = void 0;
905
+ if (this.heartbeatHandle) {
906
+ clearInterval(this.heartbeatHandle);
907
+ this.heartbeatHandle = void 0;
908
+ }
905
909
  }
906
910
  _handleClose() {
907
911
  super._handleClose();
@@ -1268,12 +1272,12 @@ var Transport = class {
1268
1272
  /**
1269
1273
  * Called when a message is received by this transport.
1270
1274
  * You generally shouldn't need to override this in downstream transport implementations.
1271
- * @param msg The received message.
1275
+ * @param message The received message.
1272
1276
  */
1273
- handleMsg(msg) {
1277
+ handleMsg(message) {
1274
1278
  if (this.getStatus() !== "open")
1275
1279
  return;
1276
- this.eventDispatcher.dispatchEvent("message", msg);
1280
+ this.eventDispatcher.dispatchEvent("message", message);
1277
1281
  }
1278
1282
  /**
1279
1283
  * Adds a listener to this transport.
@@ -1313,28 +1317,59 @@ var Transport = class {
1313
1317
  getStatus() {
1314
1318
  return this.status;
1315
1319
  }
1316
- updateSession(session) {
1320
+ // state transitions
1321
+ createSession(session) {
1317
1322
  const activeSession = this.sessions.get(session.to);
1318
- if (activeSession && activeSession.id !== session.id) {
1319
- const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1323
+ if (activeSession) {
1324
+ const msg = `attempt to create session for ${session.to} but active session (${activeSession.id}) already exists`;
1325
+ this.log?.error(msg, {
1326
+ ...session.loggingMetadata,
1327
+ tags: ["invariant-violation"]
1328
+ });
1320
1329
  throw new Error(msg);
1321
1330
  }
1322
1331
  this.sessions.set(session.to, session);
1332
+ this.eventDispatcher.dispatchEvent("sessionStatus", {
1333
+ status: "connect",
1334
+ session
1335
+ });
1336
+ this.eventDispatcher.dispatchEvent("sessionTransition", {
1337
+ state: session.state,
1338
+ session
1339
+ });
1340
+ }
1341
+ updateSession(session) {
1342
+ const activeSession = this.sessions.get(session.to);
1323
1343
  if (!activeSession) {
1324
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1325
- status: "connect",
1326
- session
1344
+ const msg = `attempt to transition session for ${session.to} but no active session exists`;
1345
+ this.log?.error(msg, {
1346
+ ...session.loggingMetadata,
1347
+ tags: ["invariant-violation"]
1348
+ });
1349
+ throw new Error(msg);
1350
+ }
1351
+ if (activeSession.id !== session.id) {
1352
+ const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1353
+ this.log?.error(msg, {
1354
+ ...session.loggingMetadata,
1355
+ tags: ["invariant-violation"]
1327
1356
  });
1357
+ throw new Error(msg);
1328
1358
  }
1359
+ this.sessions.set(session.to, session);
1329
1360
  this.eventDispatcher.dispatchEvent("sessionTransition", {
1330
1361
  state: session.state,
1331
1362
  session
1332
1363
  });
1333
- return session;
1334
1364
  }
1335
- // state transitions
1336
- deleteSession(session) {
1337
- session.log?.info(`closing session ${session.id}`, session.loggingMetadata);
1365
+ deleteSession(session, options) {
1366
+ if (session._isConsumed)
1367
+ return;
1368
+ const loggingMetadata = session.loggingMetadata;
1369
+ if (loggingMetadata.tags && options?.unhealthy) {
1370
+ loggingMetadata.tags.push("unhealthy-session");
1371
+ }
1372
+ session.log?.info(`closing session ${session.id}`, loggingMetadata);
1338
1373
  this.eventDispatcher.dispatchEvent("sessionStatus", {
1339
1374
  status: "disconnect",
1340
1375
  session
@@ -1357,7 +1392,8 @@ var Transport = class {
1357
1392
  this.onSessionGracePeriodElapsed(noConnectionSession);
1358
1393
  }
1359
1394
  });
1360
- return this.updateSession(noConnectionSession);
1395
+ this.updateSession(noConnectionSession);
1396
+ return noConnectionSession;
1361
1397
  }
1362
1398
  onConnClosed(session) {
1363
1399
  let noConnectionSession;
@@ -1374,7 +1410,36 @@ var Transport = class {
1374
1410
  }
1375
1411
  });
1376
1412
  }
1377
- return this.updateSession(noConnectionSession);
1413
+ this.updateSession(noConnectionSession);
1414
+ return noConnectionSession;
1415
+ }
1416
+ /**
1417
+ * Gets a send closure scoped to a specific session. Sending using the returned
1418
+ * closure after the session has transitioned to a different state will be a noop.
1419
+ *
1420
+ * Session objects themselves can become stale as they transition between
1421
+ * states. As stale sessions cannot be used again (and will throw), holding
1422
+ * onto a session object is not recommended.
1423
+ */
1424
+ getSessionBoundSendFn(to, sessionId) {
1425
+ if (this.getStatus() !== "open") {
1426
+ throw new Error("cannot get a bound send function on a closed transport");
1427
+ }
1428
+ return (msg) => {
1429
+ const session = this.sessions.get(to);
1430
+ if (!session) {
1431
+ throw new Error(
1432
+ `session scope for ${sessionId} has ended (close), can't send`
1433
+ );
1434
+ }
1435
+ const sameSession = session.id === sessionId;
1436
+ if (!sameSession) {
1437
+ throw new Error(
1438
+ `session scope for ${sessionId} has ended (transition), can't send`
1439
+ );
1440
+ }
1441
+ return session.send(msg);
1442
+ };
1378
1443
  }
1379
1444
  };
1380
1445
 
@@ -1427,22 +1492,10 @@ var ClientTransport = class extends Transport {
1427
1492
  this.connect(to);
1428
1493
  }
1429
1494
  }
1430
- send(to, msg) {
1431
- if (this.getStatus() === "closed") {
1432
- const err = "transport is closed, cant send";
1433
- this.log?.error(err, {
1434
- clientId: this.clientId,
1435
- transportMessage: msg,
1436
- tags: ["invariant-violation"]
1437
- });
1438
- throw new Error(err);
1439
- }
1440
- let session = this.sessions.get(to);
1441
- if (!session) {
1442
- session = this.createUnconnectedSession(to);
1443
- }
1444
- return session.send(msg);
1445
- }
1495
+ /*
1496
+ * Creates a raw unconnected session object.
1497
+ * This is mostly a River internal, you shouldn't need to use this directly.
1498
+ */
1446
1499
  createUnconnectedSession(to) {
1447
1500
  const session = ClientSessionStateGraph.entrypoint(
1448
1501
  to,
@@ -1456,7 +1509,7 @@ var ClientTransport = class extends Transport {
1456
1509
  currentProtocolVersion,
1457
1510
  this.log
1458
1511
  );
1459
- this.updateSession(session);
1512
+ this.createSession(session);
1460
1513
  return session;
1461
1514
  }
1462
1515
  // listeners
@@ -1497,7 +1550,7 @@ var ClientTransport = class extends Transport {
1497
1550
  `invalid handshake: ${reason}`,
1498
1551
  handshakingSession.loggingMetadata
1499
1552
  );
1500
- this.deleteSession(session);
1553
+ this.deleteSession(session, { unhealthy: true });
1501
1554
  this.protocolError({
1502
1555
  type: ProtocolError.HandshakeFailed,
1503
1556
  code,
@@ -1526,7 +1579,7 @@ var ClientTransport = class extends Transport {
1526
1579
  message: reason
1527
1580
  });
1528
1581
  this.log?.warn(reason, metadata);
1529
- this.deleteSession(session);
1582
+ this.deleteSession(session, { unhealthy: true });
1530
1583
  }
1531
1584
  onHandshakeResponse(session, msg) {
1532
1585
  if (!import_value2.Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
@@ -1541,10 +1594,10 @@ var ClientTransport = class extends Transport {
1541
1594
  return;
1542
1595
  }
1543
1596
  if (!msg.payload.status.ok) {
1544
- const retriable = msg.payload.status.code ? import_value2.Value.Check(
1597
+ const retriable = import_value2.Value.Check(
1545
1598
  HandshakeErrorRetriableResponseCodes,
1546
1599
  msg.payload.status.code
1547
- ) : false;
1600
+ );
1548
1601
  const reason = `handshake failed: ${msg.payload.status.reason}`;
1549
1602
  const to = session.to;
1550
1603
  this.rejectHandshakeResponse(session, reason, {
@@ -1589,11 +1642,13 @@ var ClientTransport = class extends Transport {
1589
1642
  );
1590
1643
  this.onConnClosed(connectedSession);
1591
1644
  },
1592
- onMessage: (msg2) => this.handleMsg(msg2),
1645
+ onMessage: (msg2) => {
1646
+ this.handleMsg(msg2);
1647
+ },
1593
1648
  onInvalidMessage: (reason) => {
1594
- this.deleteSession(connectedSession);
1649
+ this.deleteSession(connectedSession, { unhealthy: true });
1595
1650
  this.protocolError({
1596
- type: ProtocolError.MessageOrderingViolated,
1651
+ type: ProtocolError.InvalidMessage,
1597
1652
  message: reason
1598
1653
  });
1599
1654
  }
@@ -1612,8 +1667,7 @@ var ClientTransport = class extends Transport {
1612
1667
  );
1613
1668
  return;
1614
1669
  }
1615
- let session = this.sessions.get(to);
1616
- session ??= this.createUnconnectedSession(to);
1670
+ const session = this.sessions.get(to) ?? this.createUnconnectedSession(to);
1617
1671
  if (session.state !== "NoConnection" /* NoConnection */) {
1618
1672
  this.log?.debug(
1619
1673
  `session to ${to} has state ${session.state}, skipping connect attempt`,
@@ -1705,6 +1759,9 @@ var ClientTransport = class extends Transport {
1705
1759
  if (this.handshakeExtensions) {
1706
1760
  metadata = await this.handshakeExtensions.construct();
1707
1761
  }
1762
+ if (session._isConsumed) {
1763
+ return;
1764
+ }
1708
1765
  const requestMsg = handshakeRequestMessage({
1709
1766
  from: this.clientId,
1710
1767
  to: session.to,
@@ -1800,11 +1857,21 @@ var Connection = class {
1800
1857
  };
1801
1858
 
1802
1859
  // transport/impls/ws/connection.ts
1860
+ var WS_HEALTHY_CLOSE_CODE = 1e3;
1803
1861
  var WebSocketConnection = class extends Connection {
1804
1862
  ws;
1805
- constructor(ws) {
1863
+ extras;
1864
+ get loggingMetadata() {
1865
+ const metadata = super.loggingMetadata;
1866
+ if (this.extras) {
1867
+ metadata.extras = this.extras;
1868
+ }
1869
+ return metadata;
1870
+ }
1871
+ constructor(ws, extras) {
1806
1872
  super();
1807
1873
  this.ws = ws;
1874
+ this.extras = extras;
1808
1875
  this.ws.binaryType = "arraybuffer";
1809
1876
  let didError = false;
1810
1877
  this.ws.onerror = () => {
@@ -1837,7 +1904,7 @@ var WebSocketConnection = class extends Connection {
1837
1904
  return true;
1838
1905
  }
1839
1906
  close() {
1840
- this.ws.close();
1907
+ this.ws.close(WS_HEALTHY_CLOSE_CODE);
1841
1908
  }
1842
1909
  };
1843
1910