@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,7 +1,7 @@
1
- import { C as ClientTransport } from '../../../client-22a47343.js';
2
- import { c as TransportClientId } from '../../../message-7d135e38.js';
3
- import { b as ProvidedClientTransportOptions } from '../../../context-b4aff18f.js';
4
- import { W as WebSocketConnection } from '../../../connection-260e45a8.js';
1
+ import { C as ClientTransport } from '../../../client-9292552a.js';
2
+ import { c as TransportClientId } from '../../../message-57bb8187.js';
3
+ import { b as ProvidedClientTransportOptions } from '../../../context-69f37ac1.js';
4
+ import { W as WebSocketConnection } from '../../../connection-94dea547.js';
5
5
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
6
6
  import '@sinclair/typebox/value';
7
7
  import '@sinclair/typebox';
@@ -1,7 +1,7 @@
1
- import { C as ClientTransport } from '../../../client-22a47343.js';
2
- import { c as TransportClientId } from '../../../message-7d135e38.js';
3
- import { b as ProvidedClientTransportOptions } from '../../../context-b4aff18f.js';
4
- import { W as WebSocketConnection } from '../../../connection-260e45a8.js';
1
+ import { C as ClientTransport } from '../../../client-9292552a.js';
2
+ import { c as TransportClientId } from '../../../message-57bb8187.js';
3
+ import { b as ProvidedClientTransportOptions } from '../../../context-69f37ac1.js';
4
+ import { W as WebSocketConnection } from '../../../connection-94dea547.js';
5
5
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
6
6
  import '@sinclair/typebox/value';
7
7
  import '@sinclair/typebox';
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  ClientTransport
3
- } from "../../../chunk-4HT6P2ZG.js";
3
+ } from "../../../chunk-A4JKES5A.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/client.ts
14
14
  var WebSocketClientTransport = class extends ClientTransport {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../transport/impls/ws/client.ts"],"sourcesContent":["import { ClientTransport } from '../../client';\nimport { TransportClientId } from '../../message';\nimport { ProvidedClientTransportOptions } from '../../options';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\n\n/**\n * A transport implementation that uses a WebSocket connection with automatic reconnection.\n * @class\n * @extends Transport\n */\nexport class WebSocketClientTransport extends ClientTransport<WebSocketConnection> {\n /**\n * A function that returns a Promise that resolves to a websocket URL.\n */\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike;\n\n /**\n * Creates a new WebSocketClientTransport instance.\n * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.\n * @param clientId The ID of the client using the transport. This should be unique per session.\n * @param serverId The ID of the server this transport is connecting to.\n * @param providedOptions An optional object containing configuration options for the transport.\n */\n constructor(\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike,\n clientId: TransportClientId,\n providedOptions?: ProvidedClientTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wsGetter = wsGetter;\n }\n\n async createNewOutgoingConnection(to: string) {\n this.log?.info(`establishing a new websocket to ${to}`, {\n clientId: this.clientId,\n connectedTo: to,\n });\n\n const ws = await this.wsGetter(to);\n\n await new Promise<void>((resolve, reject) => {\n if (ws.readyState === ws.OPEN) {\n resolve();\n return;\n }\n\n if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {\n reject(new Error('ws is closing or closed'));\n return;\n }\n\n ws.onopen = () => {\n resolve();\n };\n\n ws.onclose = (evt) => {\n reject(new Error(evt.reason));\n };\n\n ws.onerror = (err) => {\n reject(new Error(err.message));\n };\n });\n\n const conn = new WebSocketConnection(ws);\n this.log?.info(`raw websocket to ${to} ok`, {\n clientId: this.clientId,\n connectedTo: to,\n ...conn.loggingMetadata,\n });\n\n return conn;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAWO,IAAM,2BAAN,cAAuC,gBAAqC;AAAA;AAAA;AAAA;AAAA,EAIjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YACE,UACA,UACA,iBACA;AACA,UAAM,UAAU,eAAe;AAC/B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,4BAA4B,IAAY;AAC5C,SAAK,KAAK,KAAK,mCAAmC,EAAE,IAAI;AAAA,MACtD,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,IACf,CAAC;AAED,UAAM,KAAK,MAAM,KAAK,SAAS,EAAE;AAEjC,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,GAAG,eAAe,GAAG,MAAM;AAC7B,gBAAQ;AACR;AAAA,MACF;AAEA,UAAI,GAAG,eAAe,GAAG,WAAW,GAAG,eAAe,GAAG,QAAQ;AAC/D,eAAO,IAAI,MAAM,yBAAyB,CAAC;AAC3C;AAAA,MACF;AAEA,SAAG,SAAS,MAAM;AAChB,gBAAQ;AAAA,MACV;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,MAC9B;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,OAAO,CAAC;AAAA,MAC/B;AAAA,IACF,CAAC;AAED,UAAM,OAAO,IAAI,oBAAoB,EAAE;AACvC,SAAK,KAAK,KAAK,oBAAoB,EAAE,OAAO;AAAA,MAC1C,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,MACb,GAAG,KAAK;AAAA,IACV,CAAC;AAED,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../transport/impls/ws/client.ts"],"sourcesContent":["import { ClientTransport } from '../../client';\nimport { TransportClientId } from '../../message';\nimport { ProvidedClientTransportOptions } from '../../options';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\n\n/**\n * A transport implementation that uses a WebSocket connection with automatic reconnection.\n * @class\n * @extends Transport\n */\nexport class WebSocketClientTransport extends ClientTransport<WebSocketConnection> {\n /**\n * A function that returns a Promise that resolves to a websocket URL.\n */\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike;\n\n /**\n * Creates a new WebSocketClientTransport instance.\n * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.\n * @param clientId The ID of the client using the transport. This should be unique per session.\n * @param serverId The ID of the server this transport is connecting to.\n * @param providedOptions An optional object containing configuration options for the transport.\n */\n constructor(\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike,\n clientId: TransportClientId,\n providedOptions?: ProvidedClientTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wsGetter = wsGetter;\n }\n\n async createNewOutgoingConnection(to: string) {\n this.log?.info(`establishing a new websocket to ${to}`, {\n clientId: this.clientId,\n connectedTo: to,\n });\n\n const ws = await this.wsGetter(to);\n\n await new Promise<void>((resolve, reject) => {\n if (ws.readyState === ws.OPEN) {\n resolve();\n\n return;\n }\n\n if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {\n reject(new Error('ws is closing or closed'));\n\n return;\n }\n\n ws.onopen = () => {\n resolve();\n };\n\n ws.onclose = (evt) => {\n reject(new Error(evt.reason));\n };\n\n ws.onerror = (err) => {\n reject(new Error(err.message));\n };\n });\n\n const conn = new WebSocketConnection(ws);\n this.log?.info(`raw websocket to ${to} ok`, {\n clientId: this.clientId,\n connectedTo: to,\n ...conn.loggingMetadata,\n });\n\n return conn;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAWO,IAAM,2BAAN,cAAuC,gBAAqC;AAAA;AAAA;AAAA;AAAA,EAIjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YACE,UACA,UACA,iBACA;AACA,UAAM,UAAU,eAAe;AAC/B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,4BAA4B,IAAY;AAC5C,SAAK,KAAK,KAAK,mCAAmC,EAAE,IAAI;AAAA,MACtD,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,IACf,CAAC;AAED,UAAM,KAAK,MAAM,KAAK,SAAS,EAAE;AAEjC,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,GAAG,eAAe,GAAG,MAAM;AAC7B,gBAAQ;AAER;AAAA,MACF;AAEA,UAAI,GAAG,eAAe,GAAG,WAAW,GAAG,eAAe,GAAG,QAAQ;AAC/D,eAAO,IAAI,MAAM,yBAAyB,CAAC;AAE3C;AAAA,MACF;AAEA,SAAG,SAAS,MAAM;AAChB,gBAAQ;AAAA,MACV;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,MAC9B;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,OAAO,CAAC;AAAA,MAC/B;AAAA,IACF,CAAC;AAED,UAAM,OAAO,IAAI,oBAAoB,EAAE;AACvC,SAAK,KAAK,KAAK,oBAAoB,EAAE,OAAO;AAAA,MAC1C,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,MACb,GAAG,KAAK;AAAA,IACV,CAAC;AAED,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -103,11 +103,21 @@ var Connection = class {
103
103
  };
104
104
 
105
105
  // transport/impls/ws/connection.ts
106
+ var WS_HEALTHY_CLOSE_CODE = 1e3;
106
107
  var WebSocketConnection = class extends Connection {
107
108
  ws;
108
- constructor(ws) {
109
+ extras;
110
+ get loggingMetadata() {
111
+ const metadata = super.loggingMetadata;
112
+ if (this.extras) {
113
+ metadata.extras = this.extras;
114
+ }
115
+ return metadata;
116
+ }
117
+ constructor(ws, extras) {
109
118
  super();
110
119
  this.ws = ws;
120
+ this.extras = extras;
111
121
  this.ws.binaryType = "arraybuffer";
112
122
  let didError = false;
113
123
  this.ws.onerror = () => {
@@ -140,7 +150,7 @@ var WebSocketConnection = class extends Connection {
140
150
  return true;
141
151
  }
142
152
  close() {
143
- this.ws.close();
153
+ this.ws.close(WS_HEALTHY_CLOSE_CODE);
144
154
  }
145
155
  };
146
156
 
@@ -175,6 +185,9 @@ var ControlMessageCloseSchema = import_typebox.Type.Object({
175
185
  });
176
186
  var currentProtocolVersion = "v2.0";
177
187
  var acceptedProtocolVersions = ["v1.1", currentProtocolVersion];
188
+ function isAcceptedProtocolVersion(version2) {
189
+ return acceptedProtocolVersions.includes(version2);
190
+ }
178
191
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
179
192
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
180
193
  protocolVersion: import_typebox.Type.String(),
@@ -187,10 +200,7 @@ var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
187
200
  expectedSessionState: import_typebox.Type.Object({
188
201
  // what the client expects the server to send next
189
202
  nextExpectedSeq: import_typebox.Type.Integer(),
190
- // TODO: remove optional once we know all servers
191
- // are nextSentSeq here
192
- // what the server expects the client to send next
193
- nextSentSeq: import_typebox.Type.Optional(import_typebox.Type.Integer())
203
+ nextSentSeq: import_typebox.Type.Integer()
194
204
  }),
195
205
  metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
196
206
  });
@@ -226,9 +236,7 @@ var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
226
236
  import_typebox.Type.Object({
227
237
  ok: import_typebox.Type.Literal(false),
228
238
  reason: import_typebox.Type.String(),
229
- // TODO: remove optional once we know all servers
230
- // are sending code here
231
- code: import_typebox.Type.Optional(HandshakeErrorResponseCodes)
239
+ code: HandshakeErrorResponseCodes
232
240
  })
233
241
  ])
234
242
  });
@@ -398,7 +406,8 @@ var createLogProxy = (log) => ({
398
406
  var ProtocolError = {
399
407
  RetriesExceeded: "conn_retry_exceeded",
400
408
  HandshakeFailed: "handshake_failed",
401
- MessageOrderingViolated: "message_ordering_violated"
409
+ MessageOrderingViolated: "message_ordering_violated",
410
+ InvalidMessage: "invalid_message"
402
411
  };
403
412
  var EventDispatcher = class {
404
413
  eventListeners = {};
@@ -676,7 +685,7 @@ var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
676
685
  var import_api = require("@opentelemetry/api");
677
686
 
678
687
  // package.json
679
- var version = "0.200.0-rc.9";
688
+ var version = "0.200.2";
680
689
 
681
690
  // tracing/index.ts
682
691
  function createSessionTelemetryInfo(sessionId, to, from, propagationCtx) {
@@ -829,13 +838,13 @@ var SessionConnected = class extends IdentifiedSession {
829
838
  this.conn.addCloseListener(this.listeners.onConnectionClosed);
830
839
  this.conn.addErrorListener(this.listeners.onConnectionErrored);
831
840
  if (this.sendBuffer.length > 0) {
832
- this.log?.debug(
833
- `sending ${this.sendBuffer.length} buffered messages`,
841
+ this.log?.info(
842
+ `sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
834
843
  this.loggingMetadata
835
844
  );
836
- }
837
- for (const msg of this.sendBuffer) {
838
- this.conn.send(this.options.codec.toBuffer(msg));
845
+ for (const msg of this.sendBuffer) {
846
+ this.conn.send(this.options.codec.toBuffer(msg));
847
+ }
839
848
  }
840
849
  this.isActivelyHeartbeating = false;
841
850
  this.heartbeatHandle = setInterval(() => {
@@ -877,6 +886,12 @@ var SessionConnected = class extends IdentifiedSession {
877
886
  }
878
887
  });
879
888
  }
889
+ closeConnection() {
890
+ this.conn.removeDataListener(this.onMessageData);
891
+ this.conn.removeCloseListener(this.listeners.onConnectionClosed);
892
+ this.conn.removeErrorListener(this.listeners.onConnectionErrored);
893
+ this.conn.close();
894
+ }
880
895
  onMessageData = (msg) => {
881
896
  const parsedMsg = this.parseMsg(msg);
882
897
  if (parsedMsg === null) {
@@ -893,8 +908,8 @@ var SessionConnected = class extends IdentifiedSession {
893
908
  }
894
909
  );
895
910
  } else {
896
- const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
897
- this.log?.error(reason, {
911
+ const reason = `received out-of-order msg, closing connection (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
912
+ this.log?.warn(reason, {
898
913
  ...this.loggingMetadata,
899
914
  transportMessage: parsedMsg,
900
915
  tags: ["invariant-violation"]
@@ -903,7 +918,7 @@ var SessionConnected = class extends IdentifiedSession {
903
918
  code: import_api2.SpanStatusCode.ERROR,
904
919
  message: reason
905
920
  });
906
- this.listeners.onInvalidMessage(reason);
921
+ this.closeConnection();
907
922
  }
908
923
  return;
909
924
  }
@@ -929,8 +944,10 @@ var SessionConnected = class extends IdentifiedSession {
929
944
  this.conn.removeDataListener(this.onMessageData);
930
945
  this.conn.removeCloseListener(this.listeners.onConnectionClosed);
931
946
  this.conn.removeErrorListener(this.listeners.onConnectionErrored);
932
- clearInterval(this.heartbeatHandle);
933
- this.heartbeatHandle = void 0;
947
+ if (this.heartbeatHandle) {
948
+ clearInterval(this.heartbeatHandle);
949
+ this.heartbeatHandle = void 0;
950
+ }
934
951
  }
935
952
  _handleClose() {
936
953
  super._handleClose();
@@ -1297,12 +1314,12 @@ var Transport = class {
1297
1314
  /**
1298
1315
  * Called when a message is received by this transport.
1299
1316
  * You generally shouldn't need to override this in downstream transport implementations.
1300
- * @param msg The received message.
1317
+ * @param message The received message.
1301
1318
  */
1302
- handleMsg(msg) {
1319
+ handleMsg(message) {
1303
1320
  if (this.getStatus() !== "open")
1304
1321
  return;
1305
- this.eventDispatcher.dispatchEvent("message", msg);
1322
+ this.eventDispatcher.dispatchEvent("message", message);
1306
1323
  }
1307
1324
  /**
1308
1325
  * Adds a listener to this transport.
@@ -1342,28 +1359,59 @@ var Transport = class {
1342
1359
  getStatus() {
1343
1360
  return this.status;
1344
1361
  }
1345
- updateSession(session) {
1362
+ // state transitions
1363
+ createSession(session) {
1346
1364
  const activeSession = this.sessions.get(session.to);
1347
- if (activeSession && activeSession.id !== session.id) {
1348
- const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1365
+ if (activeSession) {
1366
+ const msg = `attempt to create session for ${session.to} but active session (${activeSession.id}) already exists`;
1367
+ this.log?.error(msg, {
1368
+ ...session.loggingMetadata,
1369
+ tags: ["invariant-violation"]
1370
+ });
1349
1371
  throw new Error(msg);
1350
1372
  }
1351
1373
  this.sessions.set(session.to, session);
1374
+ this.eventDispatcher.dispatchEvent("sessionStatus", {
1375
+ status: "connect",
1376
+ session
1377
+ });
1378
+ this.eventDispatcher.dispatchEvent("sessionTransition", {
1379
+ state: session.state,
1380
+ session
1381
+ });
1382
+ }
1383
+ updateSession(session) {
1384
+ const activeSession = this.sessions.get(session.to);
1352
1385
  if (!activeSession) {
1353
- this.eventDispatcher.dispatchEvent("sessionStatus", {
1354
- status: "connect",
1355
- session
1386
+ const msg = `attempt to transition session for ${session.to} but no active session exists`;
1387
+ this.log?.error(msg, {
1388
+ ...session.loggingMetadata,
1389
+ tags: ["invariant-violation"]
1390
+ });
1391
+ throw new Error(msg);
1392
+ }
1393
+ if (activeSession.id !== session.id) {
1394
+ const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
1395
+ this.log?.error(msg, {
1396
+ ...session.loggingMetadata,
1397
+ tags: ["invariant-violation"]
1356
1398
  });
1399
+ throw new Error(msg);
1357
1400
  }
1401
+ this.sessions.set(session.to, session);
1358
1402
  this.eventDispatcher.dispatchEvent("sessionTransition", {
1359
1403
  state: session.state,
1360
1404
  session
1361
1405
  });
1362
- return session;
1363
1406
  }
1364
- // state transitions
1365
- deleteSession(session) {
1366
- session.log?.info(`closing session ${session.id}`, session.loggingMetadata);
1407
+ deleteSession(session, options) {
1408
+ if (session._isConsumed)
1409
+ return;
1410
+ const loggingMetadata = session.loggingMetadata;
1411
+ if (loggingMetadata.tags && options?.unhealthy) {
1412
+ loggingMetadata.tags.push("unhealthy-session");
1413
+ }
1414
+ session.log?.info(`closing session ${session.id}`, loggingMetadata);
1367
1415
  this.eventDispatcher.dispatchEvent("sessionStatus", {
1368
1416
  status: "disconnect",
1369
1417
  session
@@ -1386,7 +1434,8 @@ var Transport = class {
1386
1434
  this.onSessionGracePeriodElapsed(noConnectionSession);
1387
1435
  }
1388
1436
  });
1389
- return this.updateSession(noConnectionSession);
1437
+ this.updateSession(noConnectionSession);
1438
+ return noConnectionSession;
1390
1439
  }
1391
1440
  onConnClosed(session) {
1392
1441
  let noConnectionSession;
@@ -1403,7 +1452,36 @@ var Transport = class {
1403
1452
  }
1404
1453
  });
1405
1454
  }
1406
- return this.updateSession(noConnectionSession);
1455
+ this.updateSession(noConnectionSession);
1456
+ return noConnectionSession;
1457
+ }
1458
+ /**
1459
+ * Gets a send closure scoped to a specific session. Sending using the returned
1460
+ * closure after the session has transitioned to a different state will be a noop.
1461
+ *
1462
+ * Session objects themselves can become stale as they transition between
1463
+ * states. As stale sessions cannot be used again (and will throw), holding
1464
+ * onto a session object is not recommended.
1465
+ */
1466
+ getSessionBoundSendFn(to, sessionId) {
1467
+ if (this.getStatus() !== "open") {
1468
+ throw new Error("cannot get a bound send function on a closed transport");
1469
+ }
1470
+ return (msg) => {
1471
+ const session = this.sessions.get(to);
1472
+ if (!session) {
1473
+ throw new Error(
1474
+ `session scope for ${sessionId} has ended (close), can't send`
1475
+ );
1476
+ }
1477
+ const sameSession = session.id === sessionId;
1478
+ if (!sameSession) {
1479
+ throw new Error(
1480
+ `session scope for ${sessionId} has ended (transition), can't send`
1481
+ );
1482
+ }
1483
+ return session.send(msg);
1484
+ };
1407
1485
  }
1408
1486
  };
1409
1487
 
@@ -1447,35 +1525,13 @@ var ServerTransport = class extends Transport {
1447
1525
  extendHandshake(options) {
1448
1526
  this.handshakeExtensions = options;
1449
1527
  }
1450
- send(to, msg) {
1451
- if (this.getStatus() === "closed") {
1452
- const err = "transport is closed, cant send";
1453
- this.log?.error(err, {
1454
- clientId: this.clientId,
1455
- transportMessage: msg,
1456
- tags: ["invariant-violation"]
1457
- });
1458
- throw new Error(err);
1459
- }
1460
- const session = this.sessions.get(to);
1461
- if (!session) {
1462
- const err = `session to ${to} does not exist`;
1463
- this.log?.error(err, {
1464
- clientId: this.clientId,
1465
- transportMessage: msg,
1466
- tags: ["invariant-violation"]
1467
- });
1468
- throw new Error(err);
1469
- }
1470
- return session.send(msg);
1471
- }
1472
1528
  deletePendingSession(pendingSession) {
1473
1529
  pendingSession.close();
1474
1530
  this.pendingSessions.delete(pendingSession);
1475
1531
  }
1476
- deleteSession(session) {
1532
+ deleteSession(session, options) {
1477
1533
  this.sessionHandshakeMetadata.delete(session.to);
1478
- super.deleteSession(session);
1534
+ super.deleteSession(session, options);
1479
1535
  }
1480
1536
  handleConnection(conn) {
1481
1537
  if (this.getStatus() !== "open")
@@ -1588,7 +1644,7 @@ var ServerTransport = class extends Transport {
1588
1644
  return;
1589
1645
  }
1590
1646
  const gotVersion = msg.payload.protocolVersion;
1591
- if (!acceptedProtocolVersions.includes(gotVersion)) {
1647
+ if (!isAcceptedProtocolVersion(gotVersion)) {
1592
1648
  this.rejectHandshakeRequest(
1593
1649
  session,
1594
1650
  msg.from,
@@ -1602,7 +1658,6 @@ var ServerTransport = class extends Transport {
1602
1658
  );
1603
1659
  return;
1604
1660
  }
1605
- let oldSession = this.sessions.get(msg.from);
1606
1661
  let parsedMetadata = {};
1607
1662
  if (this.handshakeExtensions) {
1608
1663
  if (!import_value2.Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {
@@ -1624,7 +1679,9 @@ var ServerTransport = class extends Transport {
1624
1679
  );
1625
1680
  return;
1626
1681
  }
1627
- const previousParsedMetadata = oldSession ? this.sessionHandshakeMetadata.get(oldSession.to) : void 0;
1682
+ const previousParsedMetadata = this.sessionHandshakeMetadata.get(
1683
+ msg.from
1684
+ );
1628
1685
  const parsedMetadataOrFailureCode = await this.handshakeExtensions.validate(
1629
1686
  msg.payload.metadata,
1630
1687
  previousParsedMetadata
@@ -1653,7 +1710,8 @@ var ServerTransport = class extends Transport {
1653
1710
  }
1654
1711
  let connectCase = "new session";
1655
1712
  const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
1656
- const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
1713
+ const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq;
1714
+ let oldSession = this.sessions.get(msg.from);
1657
1715
  if (this.options.enableTransparentSessionReconnects && oldSession && oldSession.id === msg.payload.sessionId) {
1658
1716
  connectCase = "transparent reconnection";
1659
1717
  const ourNextSeq = oldSession.nextSeq();
@@ -1766,25 +1824,41 @@ var ServerTransport = class extends Transport {
1766
1824
  );
1767
1825
  this.onConnClosed(connectedSession);
1768
1826
  },
1769
- onMessage: (msg2) => this.handleMsg(msg2),
1827
+ onMessage: (msg2) => {
1828
+ this.handleMsg(msg2);
1829
+ },
1770
1830
  onInvalidMessage: (reason) => {
1771
1831
  this.protocolError({
1772
- type: ProtocolError.MessageOrderingViolated,
1832
+ type: ProtocolError.InvalidMessage,
1773
1833
  message: reason
1774
1834
  });
1775
- this.deleteSession(connectedSession);
1835
+ this.deleteSession(connectedSession, { unhealthy: true });
1776
1836
  }
1777
1837
  },
1778
1838
  gotVersion
1779
1839
  );
1780
1840
  this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
1781
- this.updateSession(connectedSession);
1841
+ if (oldSession) {
1842
+ this.updateSession(connectedSession);
1843
+ } else {
1844
+ this.createSession(connectedSession);
1845
+ }
1782
1846
  this.pendingSessions.delete(session);
1783
1847
  connectedSession.startActiveHeartbeat();
1784
1848
  }
1785
1849
  };
1786
1850
 
1787
1851
  // transport/impls/ws/server.ts
1852
+ function cleanHeaders(headers) {
1853
+ const cleanedHeaders = {};
1854
+ for (const [key, value] of Object.entries(headers)) {
1855
+ if (!key.startsWith("sec-") && value) {
1856
+ const cleanedValue = Array.isArray(value) ? value[0] : value;
1857
+ cleanedHeaders[key] = cleanedValue;
1858
+ }
1859
+ }
1860
+ return cleanedHeaders;
1861
+ }
1788
1862
  var WebSocketServerTransport = class extends ServerTransport {
1789
1863
  wss;
1790
1864
  constructor(wss, clientId, providedOptions) {
@@ -1792,8 +1866,10 @@ var WebSocketServerTransport = class extends ServerTransport {
1792
1866
  this.wss = wss;
1793
1867
  this.wss.on("connection", this.connectionHandler);
1794
1868
  }
1795
- connectionHandler = (ws) => {
1796
- const conn = new WebSocketConnection(ws);
1869
+ connectionHandler = (ws, req) => {
1870
+ const conn = new WebSocketConnection(ws, {
1871
+ headers: cleanHeaders(req.headersDistinct)
1872
+ });
1797
1873
  this.handleConnection(conn);
1798
1874
  };
1799
1875
  close() {