@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
@@ -1,9 +1,10 @@
1
- import { c as TransportClientId } from '../../../message-7d135e38.js';
1
+ import { c as TransportClientId } from '../../../message-57bb8187.js';
2
2
  import { WebSocketServer } from 'ws';
3
- import { W as WebSocketConnection } from '../../../connection-260e45a8.js';
3
+ import { W as WebSocketConnection } from '../../../connection-94dea547.js';
4
4
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
5
- import { S as ServerTransport } from '../../../server-dd6a9853.js';
6
- import { c as ProvidedServerTransportOptions } from '../../../context-b4aff18f.js';
5
+ import { S as ServerTransport } from '../../../server-8fdd7fb2.js';
6
+ import { c as ProvidedServerTransportOptions } from '../../../context-69f37ac1.js';
7
+ import { IncomingMessage } from 'http';
7
8
  import '@sinclair/typebox/value';
8
9
  import '@sinclair/typebox';
9
10
  import '@opentelemetry/api';
@@ -13,7 +14,7 @@ import '../../../types-3e5768ec.js';
13
14
  declare class WebSocketServerTransport extends ServerTransport<WebSocketConnection> {
14
15
  wss: WebSocketServer;
15
16
  constructor(wss: WebSocketServer, clientId: TransportClientId, providedOptions?: ProvidedServerTransportOptions);
16
- connectionHandler: (ws: WsLike) => void;
17
+ connectionHandler: (ws: WsLike, req: IncomingMessage) => void;
17
18
  close(): void;
18
19
  }
19
20
 
@@ -1,9 +1,10 @@
1
- import { c as TransportClientId } from '../../../message-7d135e38.js';
1
+ import { c as TransportClientId } from '../../../message-57bb8187.js';
2
2
  import { WebSocketServer } from 'ws';
3
- import { W as WebSocketConnection } from '../../../connection-260e45a8.js';
3
+ import { W as WebSocketConnection } from '../../../connection-94dea547.js';
4
4
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
5
- import { S as ServerTransport } from '../../../server-dd6a9853.js';
6
- import { c as ProvidedServerTransportOptions } from '../../../context-b4aff18f.js';
5
+ import { S as ServerTransport } from '../../../server-8fdd7fb2.js';
6
+ import { c as ProvidedServerTransportOptions } from '../../../context-69f37ac1.js';
7
+ import { IncomingMessage } from 'http';
7
8
  import '@sinclair/typebox/value';
8
9
  import '@sinclair/typebox';
9
10
  import '@opentelemetry/api';
@@ -13,7 +14,7 @@ import '../../../types-3e5768ec.js';
13
14
  declare class WebSocketServerTransport extends ServerTransport<WebSocketConnection> {
14
15
  wss: WebSocketServer;
15
16
  constructor(wss: WebSocketServer, clientId: TransportClientId, providedOptions?: ProvidedServerTransportOptions);
16
- connectionHandler: (ws: WsLike) => void;
17
+ connectionHandler: (ws: WsLike, req: IncomingMessage) => void;
17
18
  close(): void;
18
19
  }
19
20
 
@@ -1,16 +1,26 @@
1
1
  import {
2
2
  ServerTransport
3
- } from "../../../chunk-ZXZE253M.js";
3
+ } from "../../../chunk-PJB2Y2AV.js";
4
4
  import {
5
5
  WebSocketConnection
6
- } from "../../../chunk-GR3AQKHL.js";
7
- import "../../../chunk-I75XYO5W.js";
8
- import "../../../chunk-VXYHC666.js";
9
- import "../../../chunk-42Z2FQIU.js";
10
- import "../../../chunk-EETL2L77.js";
11
- import "../../../chunk-4PVU7J25.js";
6
+ } from "../../../chunk-HRKM7BIE.js";
7
+ import "../../../chunk-QIDEN5PP.js";
8
+ import "../../../chunk-YTMS7OP6.js";
9
+ import "../../../chunk-6BH2CXVE.js";
10
+ import "../../../chunk-GJUUVID2.js";
11
+ import "../../../chunk-AJGIY2UB.js";
12
12
 
13
13
  // transport/impls/ws/server.ts
14
+ function cleanHeaders(headers) {
15
+ const cleanedHeaders = {};
16
+ for (const [key, value] of Object.entries(headers)) {
17
+ if (!key.startsWith("sec-") && value) {
18
+ const cleanedValue = Array.isArray(value) ? value[0] : value;
19
+ cleanedHeaders[key] = cleanedValue;
20
+ }
21
+ }
22
+ return cleanedHeaders;
23
+ }
14
24
  var WebSocketServerTransport = class extends ServerTransport {
15
25
  wss;
16
26
  constructor(wss, clientId, providedOptions) {
@@ -18,8 +28,10 @@ var WebSocketServerTransport = class extends ServerTransport {
18
28
  this.wss = wss;
19
29
  this.wss.on("connection", this.connectionHandler);
20
30
  }
21
- connectionHandler = (ws) => {
22
- const conn = new WebSocketConnection(ws);
31
+ connectionHandler = (ws, req) => {
32
+ const conn = new WebSocketConnection(ws, {
33
+ headers: cleanHeaders(req.headersDistinct)
34
+ });
23
35
  this.handleConnection(conn);
24
36
  };
25
37
  close() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../transport/impls/ws/server.ts"],"sourcesContent":["import { TransportClientId } from '../../message';\nimport { WebSocketServer } from 'ws';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\nimport { ServerTransport } from '../../server';\nimport { ProvidedServerTransportOptions } from '../../options';\n\nexport class WebSocketServerTransport extends ServerTransport<WebSocketConnection> {\n wss: WebSocketServer;\n\n constructor(\n wss: WebSocketServer,\n clientId: TransportClientId,\n providedOptions?: ProvidedServerTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wss = wss;\n this.wss.on('connection', this.connectionHandler);\n }\n\n connectionHandler = (ws: WsLike) => {\n const conn = new WebSocketConnection(ws);\n this.handleConnection(conn);\n };\n\n close() {\n super.close();\n this.wss.off('connection', this.connectionHandler);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAOO,IAAM,2BAAN,cAAuC,gBAAqC;AAAA,EACjF;AAAA,EAEA,YACE,KACA,UACA,iBACA;AACA,UAAM,UAAU,eAAe;AAC/B,SAAK,MAAM;AACX,SAAK,IAAI,GAAG,cAAc,KAAK,iBAAiB;AAAA,EAClD;AAAA,EAEA,oBAAoB,CAAC,OAAe;AAClC,UAAM,OAAO,IAAI,oBAAoB,EAAE;AACvC,SAAK,iBAAiB,IAAI;AAAA,EAC5B;AAAA,EAEA,QAAQ;AACN,UAAM,MAAM;AACZ,SAAK,IAAI,IAAI,cAAc,KAAK,iBAAiB;AAAA,EACnD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../transport/impls/ws/server.ts"],"sourcesContent":["import { TransportClientId } from '../../message';\nimport { WebSocketServer } from 'ws';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\nimport { ServerTransport } from '../../server';\nimport { ProvidedServerTransportOptions } from '../../options';\nimport { type IncomingMessage } from 'http';\n\nfunction cleanHeaders(\n headers: IncomingMessage['headers'],\n): Record<string, string> {\n const cleanedHeaders: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (!key.startsWith('sec-') && value) {\n const cleanedValue = Array.isArray(value) ? value[0] : value;\n cleanedHeaders[key] = cleanedValue;\n }\n }\n\n return cleanedHeaders;\n}\n\nexport class WebSocketServerTransport extends ServerTransport<WebSocketConnection> {\n wss: WebSocketServer;\n\n constructor(\n wss: WebSocketServer,\n clientId: TransportClientId,\n providedOptions?: ProvidedServerTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wss = wss;\n this.wss.on('connection', this.connectionHandler);\n }\n\n connectionHandler = (ws: WsLike, req: IncomingMessage) => {\n const conn = new WebSocketConnection(ws, {\n headers: cleanHeaders(req.headersDistinct),\n });\n\n this.handleConnection(conn);\n };\n\n close() {\n super.close();\n this.wss.off('connection', this.connectionHandler);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAQA,SAAS,aACP,SACwB;AACxB,QAAM,iBAAyC,CAAC;AAEhD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,CAAC,IAAI,WAAW,MAAM,KAAK,OAAO;AACpC,YAAM,eAAe,MAAM,QAAQ,KAAK,IAAI,MAAM,CAAC,IAAI;AACvD,qBAAe,GAAG,IAAI;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,2BAAN,cAAuC,gBAAqC;AAAA,EACjF;AAAA,EAEA,YACE,KACA,UACA,iBACA;AACA,UAAM,UAAU,eAAe;AAC/B,SAAK,MAAM;AACX,SAAK,IAAI,GAAG,cAAc,KAAK,iBAAiB;AAAA,EAClD;AAAA,EAEA,oBAAoB,CAAC,IAAY,QAAyB;AACxD,UAAM,OAAO,IAAI,oBAAoB,IAAI;AAAA,MACvC,SAAS,aAAa,IAAI,eAAe;AAAA,IAC3C,CAAC;AAED,SAAK,iBAAiB,IAAI;AAAA,EAC5B;AAAA,EAEA,QAAQ;AACN,UAAM,MAAM;AACZ,SAAK,IAAI,IAAI,cAAc,KAAK,iBAAiB;AAAA,EACnD;AACF;","names":[]}
@@ -88,7 +88,8 @@ var createLogProxy = (log) => ({
88
88
  var ProtocolError = {
89
89
  RetriesExceeded: "conn_retry_exceeded",
90
90
  HandshakeFailed: "handshake_failed",
91
- MessageOrderingViolated: "message_ordering_violated"
91
+ MessageOrderingViolated: "message_ordering_violated",
92
+ InvalidMessage: "invalid_message"
92
93
  };
93
94
  var EventDispatcher = class {
94
95
  eventListeners = {};
@@ -235,6 +236,9 @@ var ControlMessageCloseSchema = import_typebox.Type.Object({
235
236
  });
236
237
  var currentProtocolVersion = "v2.0";
237
238
  var acceptedProtocolVersions = ["v1.1", currentProtocolVersion];
239
+ function isAcceptedProtocolVersion(version2) {
240
+ return acceptedProtocolVersions.includes(version2);
241
+ }
238
242
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
239
243
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
240
244
  protocolVersion: import_typebox.Type.String(),
@@ -247,10 +251,7 @@ var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
247
251
  expectedSessionState: import_typebox.Type.Object({
248
252
  // what the client expects the server to send next
249
253
  nextExpectedSeq: import_typebox.Type.Integer(),
250
- // TODO: remove optional once we know all servers
251
- // are nextSentSeq here
252
- // what the server expects the client to send next
253
- nextSentSeq: import_typebox.Type.Optional(import_typebox.Type.Integer())
254
+ nextSentSeq: import_typebox.Type.Integer()
254
255
  }),
255
256
  metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
256
257
  });
@@ -286,9 +287,7 @@ var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
286
287
  import_typebox.Type.Object({
287
288
  ok: import_typebox.Type.Literal(false),
288
289
  reason: import_typebox.Type.String(),
289
- // TODO: remove optional once we know all servers
290
- // are sending code here
291
- code: import_typebox.Type.Optional(HandshakeErrorResponseCodes)
290
+ code: HandshakeErrorResponseCodes
292
291
  })
293
292
  ])
294
293
  });
@@ -604,7 +603,7 @@ var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
604
603
  var import_api = require("@opentelemetry/api");
605
604
 
606
605
  // package.json
607
- var version = "0.200.0-rc.9";
606
+ var version = "0.200.2";
608
607
 
609
608
  // tracing/index.ts
610
609
  function getPropagationContext(ctx) {
@@ -766,13 +765,13 @@ var SessionConnected = class extends IdentifiedSession {
766
765
  this.conn.addCloseListener(this.listeners.onConnectionClosed);
767
766
  this.conn.addErrorListener(this.listeners.onConnectionErrored);
768
767
  if (this.sendBuffer.length > 0) {
769
- this.log?.debug(
770
- `sending ${this.sendBuffer.length} buffered messages`,
768
+ this.log?.info(
769
+ `sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
771
770
  this.loggingMetadata
772
771
  );
773
- }
774
- for (const msg of this.sendBuffer) {
775
- this.conn.send(this.options.codec.toBuffer(msg));
772
+ for (const msg of this.sendBuffer) {
773
+ this.conn.send(this.options.codec.toBuffer(msg));
774
+ }
776
775
  }
777
776
  this.isActivelyHeartbeating = false;
778
777
  this.heartbeatHandle = setInterval(() => {
@@ -814,6 +813,12 @@ var SessionConnected = class extends IdentifiedSession {
814
813
  }
815
814
  });
816
815
  }
816
+ closeConnection() {
817
+ this.conn.removeDataListener(this.onMessageData);
818
+ this.conn.removeCloseListener(this.listeners.onConnectionClosed);
819
+ this.conn.removeErrorListener(this.listeners.onConnectionErrored);
820
+ this.conn.close();
821
+ }
817
822
  onMessageData = (msg) => {
818
823
  const parsedMsg = this.parseMsg(msg);
819
824
  if (parsedMsg === null) {
@@ -830,8 +835,8 @@ var SessionConnected = class extends IdentifiedSession {
830
835
  }
831
836
  );
832
837
  } else {
833
- const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
834
- this.log?.error(reason, {
838
+ const reason = `received out-of-order msg, closing connection (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
839
+ this.log?.warn(reason, {
835
840
  ...this.loggingMetadata,
836
841
  transportMessage: parsedMsg,
837
842
  tags: ["invariant-violation"]
@@ -840,7 +845,7 @@ var SessionConnected = class extends IdentifiedSession {
840
845
  code: import_api2.SpanStatusCode.ERROR,
841
846
  message: reason
842
847
  });
843
- this.listeners.onInvalidMessage(reason);
848
+ this.closeConnection();
844
849
  }
845
850
  return;
846
851
  }
@@ -866,8 +871,10 @@ var SessionConnected = class extends IdentifiedSession {
866
871
  this.conn.removeDataListener(this.onMessageData);
867
872
  this.conn.removeCloseListener(this.listeners.onConnectionClosed);
868
873
  this.conn.removeErrorListener(this.listeners.onConnectionErrored);
869
- clearInterval(this.heartbeatHandle);
870
- this.heartbeatHandle = void 0;
874
+ if (this.heartbeatHandle) {
875
+ clearInterval(this.heartbeatHandle);
876
+ this.heartbeatHandle = void 0;
877
+ }
871
878
  }
872
879
  _handleClose() {
873
880
  super._handleClose();
@@ -1234,12 +1241,12 @@ var Transport = class {
1234
1241
  /**
1235
1242
  * Called when a message is received by this transport.
1236
1243
  * You generally shouldn't need to override this in downstream transport implementations.
1237
- * @param msg The received message.
1244
+ * @param message The received message.
1238
1245
  */
1239
- handleMsg(msg) {
1246
+ handleMsg(message) {
1240
1247
  if (this.getStatus() !== "open")
1241
1248
  return;
1242
- this.eventDispatcher.dispatchEvent("message", msg);
1249
+ this.eventDispatcher.dispatchEvent("message", message);
1243
1250
  }
1244
1251
  /**
1245
1252
  * Adds a listener to this transport.
@@ -1279,28 +1286,59 @@ var Transport = class {
1279
1286
  getStatus() {
1280
1287
  return this.status;
1281
1288
  }
1282
- updateSession(session) {
1289
+ // state transitions
1290
+ createSession(session) {
1283
1291
  const activeSession = this.sessions.get(session.to);
1284
- if (activeSession && activeSession.id !== session.id) {
1285
- const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1292
+ if (activeSession) {
1293
+ const msg = `attempt to create session for ${session.to} but active session (${activeSession.id}) already exists`;
1294
+ this.log?.error(msg, {
1295
+ ...session.loggingMetadata,
1296
+ tags: ["invariant-violation"]
1297
+ });
1286
1298
  throw new Error(msg);
1287
1299
  }
1288
1300
  this.sessions.set(session.to, session);
1301
+ this.eventDispatcher.dispatchEvent("sessionStatus", {
1302
+ status: "connect",
1303
+ session
1304
+ });
1305
+ this.eventDispatcher.dispatchEvent("sessionTransition", {
1306
+ state: session.state,
1307
+ session
1308
+ });
1309
+ }
1310
+ updateSession(session) {
1311
+ const activeSession = this.sessions.get(session.to);
1289
1312
  if (!activeSession) {
1290
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1291
- status: "connect",
1292
- session
1313
+ const msg = `attempt to transition session for ${session.to} but no active session exists`;
1314
+ this.log?.error(msg, {
1315
+ ...session.loggingMetadata,
1316
+ tags: ["invariant-violation"]
1293
1317
  });
1318
+ throw new Error(msg);
1294
1319
  }
1320
+ if (activeSession.id !== session.id) {
1321
+ const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1322
+ this.log?.error(msg, {
1323
+ ...session.loggingMetadata,
1324
+ tags: ["invariant-violation"]
1325
+ });
1326
+ throw new Error(msg);
1327
+ }
1328
+ this.sessions.set(session.to, session);
1295
1329
  this.eventDispatcher.dispatchEvent("sessionTransition", {
1296
1330
  state: session.state,
1297
1331
  session
1298
1332
  });
1299
- return session;
1300
1333
  }
1301
- // state transitions
1302
- deleteSession(session) {
1303
- session.log?.info(`closing session ${session.id}`, session.loggingMetadata);
1334
+ deleteSession(session, options) {
1335
+ if (session._isConsumed)
1336
+ return;
1337
+ const loggingMetadata = session.loggingMetadata;
1338
+ if (loggingMetadata.tags && options?.unhealthy) {
1339
+ loggingMetadata.tags.push("unhealthy-session");
1340
+ }
1341
+ session.log?.info(`closing session ${session.id}`, loggingMetadata);
1304
1342
  this.eventDispatcher.dispatchEvent("sessionStatus", {
1305
1343
  status: "disconnect",
1306
1344
  session
@@ -1323,7 +1361,8 @@ var Transport = class {
1323
1361
  this.onSessionGracePeriodElapsed(noConnectionSession);
1324
1362
  }
1325
1363
  });
1326
- return this.updateSession(noConnectionSession);
1364
+ this.updateSession(noConnectionSession);
1365
+ return noConnectionSession;
1327
1366
  }
1328
1367
  onConnClosed(session) {
1329
1368
  let noConnectionSession;
@@ -1340,7 +1379,36 @@ var Transport = class {
1340
1379
  }
1341
1380
  });
1342
1381
  }
1343
- return this.updateSession(noConnectionSession);
1382
+ this.updateSession(noConnectionSession);
1383
+ return noConnectionSession;
1384
+ }
1385
+ /**
1386
+ * Gets a send closure scoped to a specific session. Sending using the returned
1387
+ * closure after the session has transitioned to a different state will be a noop.
1388
+ *
1389
+ * Session objects themselves can become stale as they transition between
1390
+ * states. As stale sessions cannot be used again (and will throw), holding
1391
+ * onto a session object is not recommended.
1392
+ */
1393
+ getSessionBoundSendFn(to, sessionId) {
1394
+ if (this.getStatus() !== "open") {
1395
+ throw new Error("cannot get a bound send function on a closed transport");
1396
+ }
1397
+ return (msg) => {
1398
+ const session = this.sessions.get(to);
1399
+ if (!session) {
1400
+ throw new Error(
1401
+ `session scope for ${sessionId} has ended (close), can't send`
1402
+ );
1403
+ }
1404
+ const sameSession = session.id === sessionId;
1405
+ if (!sameSession) {
1406
+ throw new Error(
1407
+ `session scope for ${sessionId} has ended (transition), can't send`
1408
+ );
1409
+ }
1410
+ return session.send(msg);
1411
+ };
1344
1412
  }
1345
1413
  };
1346
1414
 
@@ -1463,22 +1531,10 @@ var ClientTransport = class extends Transport {
1463
1531
  this.connect(to);
1464
1532
  }
1465
1533
  }
1466
- send(to, msg) {
1467
- if (this.getStatus() === "closed") {
1468
- const err = "transport is closed, cant send";
1469
- this.log?.error(err, {
1470
- clientId: this.clientId,
1471
- transportMessage: msg,
1472
- tags: ["invariant-violation"]
1473
- });
1474
- throw new Error(err);
1475
- }
1476
- let session = this.sessions.get(to);
1477
- if (!session) {
1478
- session = this.createUnconnectedSession(to);
1479
- }
1480
- return session.send(msg);
1481
- }
1534
+ /*
1535
+ * Creates a raw unconnected session object.
1536
+ * This is mostly a River internal, you shouldn't need to use this directly.
1537
+ */
1482
1538
  createUnconnectedSession(to) {
1483
1539
  const session = ClientSessionStateGraph.entrypoint(
1484
1540
  to,
@@ -1492,7 +1548,7 @@ var ClientTransport = class extends Transport {
1492
1548
  currentProtocolVersion,
1493
1549
  this.log
1494
1550
  );
1495
- this.updateSession(session);
1551
+ this.createSession(session);
1496
1552
  return session;
1497
1553
  }
1498
1554
  // listeners
@@ -1533,7 +1589,7 @@ var ClientTransport = class extends Transport {
1533
1589
  `invalid handshake: ${reason}`,
1534
1590
  handshakingSession.loggingMetadata
1535
1591
  );
1536
- this.deleteSession(session);
1592
+ this.deleteSession(session, { unhealthy: true });
1537
1593
  this.protocolError({
1538
1594
  type: ProtocolError.HandshakeFailed,
1539
1595
  code,
@@ -1562,7 +1618,7 @@ var ClientTransport = class extends Transport {
1562
1618
  message: reason
1563
1619
  });
1564
1620
  this.log?.warn(reason, metadata);
1565
- this.deleteSession(session);
1621
+ this.deleteSession(session, { unhealthy: true });
1566
1622
  }
1567
1623
  onHandshakeResponse(session, msg) {
1568
1624
  if (!import_value2.Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
@@ -1577,10 +1633,10 @@ var ClientTransport = class extends Transport {
1577
1633
  return;
1578
1634
  }
1579
1635
  if (!msg.payload.status.ok) {
1580
- const retriable = msg.payload.status.code ? import_value2.Value.Check(
1636
+ const retriable = import_value2.Value.Check(
1581
1637
  HandshakeErrorRetriableResponseCodes,
1582
1638
  msg.payload.status.code
1583
- ) : false;
1639
+ );
1584
1640
  const reason = `handshake failed: ${msg.payload.status.reason}`;
1585
1641
  const to = session.to;
1586
1642
  this.rejectHandshakeResponse(session, reason, {
@@ -1625,11 +1681,13 @@ var ClientTransport = class extends Transport {
1625
1681
  );
1626
1682
  this.onConnClosed(connectedSession);
1627
1683
  },
1628
- onMessage: (msg2) => this.handleMsg(msg2),
1684
+ onMessage: (msg2) => {
1685
+ this.handleMsg(msg2);
1686
+ },
1629
1687
  onInvalidMessage: (reason) => {
1630
- this.deleteSession(connectedSession);
1688
+ this.deleteSession(connectedSession, { unhealthy: true });
1631
1689
  this.protocolError({
1632
- type: ProtocolError.MessageOrderingViolated,
1690
+ type: ProtocolError.InvalidMessage,
1633
1691
  message: reason
1634
1692
  });
1635
1693
  }
@@ -1648,8 +1706,7 @@ var ClientTransport = class extends Transport {
1648
1706
  );
1649
1707
  return;
1650
1708
  }
1651
- let session = this.sessions.get(to);
1652
- session ??= this.createUnconnectedSession(to);
1709
+ const session = this.sessions.get(to) ?? this.createUnconnectedSession(to);
1653
1710
  if (session.state !== "NoConnection" /* NoConnection */) {
1654
1711
  this.log?.debug(
1655
1712
  `session to ${to} has state ${session.state}, skipping connect attempt`,
@@ -1741,6 +1798,9 @@ var ClientTransport = class extends Transport {
1741
1798
  if (this.handshakeExtensions) {
1742
1799
  metadata = await this.handshakeExtensions.construct();
1743
1800
  }
1801
+ if (session._isConsumed) {
1802
+ return;
1803
+ }
1744
1804
  const requestMsg = handshakeRequestMessage({
1745
1805
  from: this.clientId,
1746
1806
  to: session.to,
@@ -1797,35 +1857,13 @@ var ServerTransport = class extends Transport {
1797
1857
  extendHandshake(options) {
1798
1858
  this.handshakeExtensions = options;
1799
1859
  }
1800
- send(to, msg) {
1801
- if (this.getStatus() === "closed") {
1802
- const err = "transport is closed, cant send";
1803
- this.log?.error(err, {
1804
- clientId: this.clientId,
1805
- transportMessage: msg,
1806
- tags: ["invariant-violation"]
1807
- });
1808
- throw new Error(err);
1809
- }
1810
- const session = this.sessions.get(to);
1811
- if (!session) {
1812
- const err = `session to ${to} does not exist`;
1813
- this.log?.error(err, {
1814
- clientId: this.clientId,
1815
- transportMessage: msg,
1816
- tags: ["invariant-violation"]
1817
- });
1818
- throw new Error(err);
1819
- }
1820
- return session.send(msg);
1821
- }
1822
1860
  deletePendingSession(pendingSession) {
1823
1861
  pendingSession.close();
1824
1862
  this.pendingSessions.delete(pendingSession);
1825
1863
  }
1826
- deleteSession(session) {
1864
+ deleteSession(session, options) {
1827
1865
  this.sessionHandshakeMetadata.delete(session.to);
1828
- super.deleteSession(session);
1866
+ super.deleteSession(session, options);
1829
1867
  }
1830
1868
  handleConnection(conn) {
1831
1869
  if (this.getStatus() !== "open")
@@ -1938,7 +1976,7 @@ var ServerTransport = class extends Transport {
1938
1976
  return;
1939
1977
  }
1940
1978
  const gotVersion = msg.payload.protocolVersion;
1941
- if (!acceptedProtocolVersions.includes(gotVersion)) {
1979
+ if (!isAcceptedProtocolVersion(gotVersion)) {
1942
1980
  this.rejectHandshakeRequest(
1943
1981
  session,
1944
1982
  msg.from,
@@ -1952,7 +1990,6 @@ var ServerTransport = class extends Transport {
1952
1990
  );
1953
1991
  return;
1954
1992
  }
1955
- let oldSession = this.sessions.get(msg.from);
1956
1993
  let parsedMetadata = {};
1957
1994
  if (this.handshakeExtensions) {
1958
1995
  if (!import_value3.Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {
@@ -1974,7 +2011,9 @@ var ServerTransport = class extends Transport {
1974
2011
  );
1975
2012
  return;
1976
2013
  }
1977
- const previousParsedMetadata = oldSession ? this.sessionHandshakeMetadata.get(oldSession.to) : void 0;
2014
+ const previousParsedMetadata = this.sessionHandshakeMetadata.get(
2015
+ msg.from
2016
+ );
1978
2017
  const parsedMetadataOrFailureCode = await this.handshakeExtensions.validate(
1979
2018
  msg.payload.metadata,
1980
2019
  previousParsedMetadata
@@ -2003,7 +2042,8 @@ var ServerTransport = class extends Transport {
2003
2042
  }
2004
2043
  let connectCase = "new session";
2005
2044
  const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
2006
- const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
2045
+ const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq;
2046
+ let oldSession = this.sessions.get(msg.from);
2007
2047
  if (this.options.enableTransparentSessionReconnects && oldSession && oldSession.id === msg.payload.sessionId) {
2008
2048
  connectCase = "transparent reconnection";
2009
2049
  const ourNextSeq = oldSession.nextSeq();
@@ -2116,19 +2156,25 @@ var ServerTransport = class extends Transport {
2116
2156
  );
2117
2157
  this.onConnClosed(connectedSession);
2118
2158
  },
2119
- onMessage: (msg2) => this.handleMsg(msg2),
2159
+ onMessage: (msg2) => {
2160
+ this.handleMsg(msg2);
2161
+ },
2120
2162
  onInvalidMessage: (reason) => {
2121
2163
  this.protocolError({
2122
- type: ProtocolError.MessageOrderingViolated,
2164
+ type: ProtocolError.InvalidMessage,
2123
2165
  message: reason
2124
2166
  });
2125
- this.deleteSession(connectedSession);
2167
+ this.deleteSession(connectedSession, { unhealthy: true });
2126
2168
  }
2127
2169
  },
2128
2170
  gotVersion
2129
2171
  );
2130
2172
  this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
2131
- this.updateSession(connectedSession);
2173
+ if (oldSession) {
2174
+ this.updateSession(connectedSession);
2175
+ } else {
2176
+ this.createSession(connectedSession);
2177
+ }
2132
2178
  this.pendingSessions.delete(session);
2133
2179
  connectedSession.startActiveHeartbeat();
2134
2180
  }