@replit/river 0.26.1 → 0.26.3

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 (52) hide show
  1. package/dist/{chunk-4W5LENT2.js → chunk-3JCZNGF7.js} +2 -2
  2. package/dist/{chunk-XRI2BXMM.js → chunk-BB2E5L4U.js} +25 -13
  3. package/dist/chunk-BB2E5L4U.js.map +1 -0
  4. package/dist/{chunk-6UVTCZ6K.js → chunk-JI6FFDY5.js} +5 -4
  5. package/dist/{chunk-6UVTCZ6K.js.map → chunk-JI6FFDY5.js.map} +1 -1
  6. package/dist/{chunk-UQOD22AN.js → chunk-MZELCWJK.js} +2 -2
  7. package/dist/{chunk-UQOD22AN.js.map → chunk-MZELCWJK.js.map} +1 -1
  8. package/dist/{chunk-M43R4RPL.js → chunk-OCL2FUTQ.js} +128 -45
  9. package/dist/chunk-OCL2FUTQ.js.map +1 -0
  10. package/dist/{chunk-IVNX5H6C.js → chunk-X35QRIA5.js} +54 -55
  11. package/dist/chunk-X35QRIA5.js.map +1 -0
  12. package/dist/{chunk-AYIMQWS7.js → chunk-ZY2HYJ5Y.js} +2 -2
  13. package/dist/{client-0f636b3a.d.ts → client-1894a9c9.d.ts} +2 -4
  14. package/dist/{connection-07e97a79.d.ts → connection-03ffb583.d.ts} +1 -1
  15. package/dist/{handshake-8752f79e.d.ts → handshake-154a0bb2.d.ts} +82 -39
  16. package/dist/logging/index.d.cts +1 -1
  17. package/dist/logging/index.d.ts +1 -1
  18. package/dist/{message-57296605.d.ts → message-ff78a233.d.ts} +1 -1
  19. package/dist/router/index.cjs +1 -1
  20. package/dist/router/index.cjs.map +1 -1
  21. package/dist/router/index.d.cts +9 -8
  22. package/dist/router/index.d.ts +9 -8
  23. package/dist/router/index.js +2 -2
  24. package/dist/{server-e304daec.d.ts → server-1f5eb427.d.ts} +27 -6
  25. package/dist/{services-fc99aae1.d.ts → services-491d8c32.d.ts} +3 -3
  26. package/dist/transport/impls/ws/client.cjs +153 -56
  27. package/dist/transport/impls/ws/client.cjs.map +1 -1
  28. package/dist/transport/impls/ws/client.d.cts +5 -4
  29. package/dist/transport/impls/ws/client.d.ts +5 -4
  30. package/dist/transport/impls/ws/client.js +8 -7
  31. package/dist/transport/impls/ws/client.js.map +1 -1
  32. package/dist/transport/impls/ws/server.cjs +179 -96
  33. package/dist/transport/impls/ws/server.cjs.map +1 -1
  34. package/dist/transport/impls/ws/server.d.cts +5 -4
  35. package/dist/transport/impls/ws/server.d.ts +5 -4
  36. package/dist/transport/impls/ws/server.js +5 -5
  37. package/dist/transport/index.cjs +200 -105
  38. package/dist/transport/index.cjs.map +1 -1
  39. package/dist/transport/index.d.cts +5 -4
  40. package/dist/transport/index.d.ts +5 -4
  41. package/dist/transport/index.js +5 -5
  42. package/dist/util/testHelpers.cjs +127 -44
  43. package/dist/util/testHelpers.cjs.map +1 -1
  44. package/dist/util/testHelpers.d.cts +5 -4
  45. package/dist/util/testHelpers.d.ts +5 -4
  46. package/dist/util/testHelpers.js +3 -3
  47. package/package.json +1 -1
  48. package/dist/chunk-IVNX5H6C.js.map +0 -1
  49. package/dist/chunk-M43R4RPL.js.map +0 -1
  50. package/dist/chunk-XRI2BXMM.js.map +0 -1
  51. /package/dist/{chunk-4W5LENT2.js.map → chunk-3JCZNGF7.js.map} +0 -0
  52. /package/dist/{chunk-AYIMQWS7.js.map → chunk-ZY2HYJ5Y.js.map} +0 -0
@@ -1,11 +1,12 @@
1
- import { C as ClientTransport } from '../../../client-0f636b3a.js';
2
- import { c as TransportClientId } from '../../../message-57296605.js';
3
- import { b as ProvidedClientTransportOptions } from '../../../handshake-8752f79e.js';
4
- import { W as WebSocketConnection } from '../../../connection-07e97a79.js';
1
+ import { C as ClientTransport } from '../../../client-1894a9c9.js';
2
+ import { c as TransportClientId } from '../../../message-ff78a233.js';
3
+ import { b as ProvidedClientTransportOptions } from '../../../handshake-154a0bb2.js';
4
+ import { W as WebSocketConnection } from '../../../connection-03ffb583.js';
5
5
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
6
6
  import '@sinclair/typebox/value';
7
7
  import '@sinclair/typebox';
8
8
  import '@opentelemetry/api';
9
+ import '@sinclair/typebox/errors';
9
10
  import '../../../types-3e5768ec.js';
10
11
 
11
12
  /**
@@ -1,11 +1,12 @@
1
- import { C as ClientTransport } from '../../../client-0f636b3a.js';
2
- import { c as TransportClientId } from '../../../message-57296605.js';
3
- import { b as ProvidedClientTransportOptions } from '../../../handshake-8752f79e.js';
4
- import { W as WebSocketConnection } from '../../../connection-07e97a79.js';
1
+ import { C as ClientTransport } from '../../../client-1894a9c9.js';
2
+ import { c as TransportClientId } from '../../../message-ff78a233.js';
3
+ import { b as ProvidedClientTransportOptions } from '../../../handshake-154a0bb2.js';
4
+ import { W as WebSocketConnection } from '../../../connection-03ffb583.js';
5
5
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
6
6
  import '@sinclair/typebox/value';
7
7
  import '@sinclair/typebox';
8
8
  import '@opentelemetry/api';
9
+ import '@sinclair/typebox/errors';
9
10
  import '../../../types-3e5768ec.js';
10
11
 
11
12
  /**
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  ClientTransport
3
- } from "../../../chunk-XRI2BXMM.js";
3
+ } from "../../../chunk-BB2E5L4U.js";
4
4
  import {
5
5
  WebSocketConnection
6
- } from "../../../chunk-AYIMQWS7.js";
7
- import "../../../chunk-6UVTCZ6K.js";
6
+ } from "../../../chunk-ZY2HYJ5Y.js";
7
+ import "../../../chunk-JI6FFDY5.js";
8
8
  import "../../../chunk-TAH2GVTJ.js";
9
- import "../../../chunk-M43R4RPL.js";
10
- import "../../../chunk-UQOD22AN.js";
9
+ import "../../../chunk-OCL2FUTQ.js";
10
+ import "../../../chunk-MZELCWJK.js";
11
11
  import "../../../chunk-4PVU7J25.js";
12
12
 
13
13
  // transport/impls/ws/client.ts
@@ -53,9 +53,10 @@ var WebSocketClientTransport = class extends ClientTransport {
53
53
  };
54
54
  });
55
55
  const conn = new WebSocketConnection(ws);
56
- this.log?.info(`raw websocket to ${to} ok, starting handshake`, {
56
+ this.log?.info(`raw websocket to ${to} ok`, {
57
57
  clientId: this.clientId,
58
- connectedTo: to
58
+ connectedTo: to,
59
+ ...conn.loggingMetadata
59
60
  });
60
61
  return conn;
61
62
  }
@@ -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, starting handshake`, {\n clientId: this.clientId,\n connectedTo: to,\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,2BAA2B;AAAA,MAC9D,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,IACf,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 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":[]}
@@ -322,6 +322,7 @@ var defaultTransportOptions = {
322
322
  sessionDisconnectGraceMs: 5e3,
323
323
  connectionTimeoutMs: 2e3,
324
324
  handshakeTimeoutMs: 1e3,
325
+ enableTransparentSessionReconnects: true,
325
326
  codec: NaiveJsonCodec
326
327
  };
327
328
  var defaultConnectionRetryOptions = {
@@ -456,6 +457,7 @@ var StateMachineState = class {
456
457
  }
457
458
  if (prop === "_handleClose") {
458
459
  return () => {
460
+ target._isConsumed = true;
459
461
  target._handleStateExit();
460
462
  target._handleClose();
461
463
  };
@@ -536,15 +538,18 @@ var IdentifiedSession = class extends CommonSession {
536
538
  }
537
539
  get loggingMetadata() {
538
540
  const spanContext = this.telemetry.span.spanContext();
539
- return {
541
+ const metadata = {
540
542
  clientId: this.from,
541
543
  connectedTo: this.to,
542
- sessionId: this.id,
543
- telemetry: {
544
+ sessionId: this.id
545
+ };
546
+ if (this.telemetry.span.isRecording()) {
547
+ metadata.telemetry = {
544
548
  traceId: spanContext.traceId,
545
549
  spanId: spanContext.spanId
546
- }
547
- };
550
+ };
551
+ }
552
+ return metadata;
548
553
  }
549
554
  constructMsg(partialMsg) {
550
555
  const msg = {
@@ -573,9 +578,32 @@ var IdentifiedSession = class extends CommonSession {
573
578
  this.telemetry.span.end();
574
579
  }
575
580
  };
581
+ var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
582
+ graceExpiryTime;
583
+ gracePeriodTimeout;
584
+ listeners;
585
+ constructor(props) {
586
+ super(props);
587
+ this.listeners = props.listeners;
588
+ this.graceExpiryTime = props.graceExpiryTime;
589
+ this.gracePeriodTimeout = setTimeout(() => {
590
+ this.listeners.onSessionGracePeriodElapsed();
591
+ }, this.graceExpiryTime - Date.now());
592
+ }
593
+ _handleStateExit() {
594
+ super._handleStateExit();
595
+ if (this.gracePeriodTimeout) {
596
+ clearTimeout(this.gracePeriodTimeout);
597
+ this.gracePeriodTimeout = void 0;
598
+ }
599
+ }
600
+ _handleClose() {
601
+ super._handleClose();
602
+ }
603
+ };
576
604
 
577
605
  // transport/sessionStateMachine/SessionConnecting.ts
578
- var SessionConnecting = class extends IdentifiedSession {
606
+ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
579
607
  state = "Connecting" /* Connecting */;
580
608
  connPromise;
581
609
  listeners;
@@ -603,13 +631,24 @@ var SessionConnecting = class extends IdentifiedSession {
603
631
  // close a pending connection if it resolves, ignore errors if the promise
604
632
  // ends up rejected anyways
605
633
  bestEffortClose() {
606
- void this.connPromise.then((conn) => conn.close()).catch(() => {
634
+ void this.connPromise.then((conn) => {
635
+ conn.close();
636
+ this.log?.info(
637
+ "connection eventually resolved but session has transitioned, closed connection",
638
+ {
639
+ ...this.loggingMetadata,
640
+ ...conn.loggingMetadata
641
+ }
642
+ );
643
+ }).catch(() => {
607
644
  });
608
645
  }
609
646
  _handleStateExit() {
610
647
  super._handleStateExit();
611
- clearTimeout(this.connectionTimeout);
612
- this.connectionTimeout = void 0;
648
+ if (this.connectionTimeout) {
649
+ clearTimeout(this.connectionTimeout);
650
+ this.connectionTimeout = void 0;
651
+ }
613
652
  }
614
653
  _handleClose() {
615
654
  this.bestEffortClose();
@@ -618,26 +657,13 @@ var SessionConnecting = class extends IdentifiedSession {
618
657
  };
619
658
 
620
659
  // transport/sessionStateMachine/SessionNoConnection.ts
621
- var SessionNoConnection = class extends IdentifiedSession {
660
+ var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
622
661
  state = "NoConnection" /* NoConnection */;
623
- listeners;
624
- gracePeriodTimeout;
625
- constructor(props) {
626
- super(props);
627
- this.listeners = props.listeners;
628
- this.gracePeriodTimeout = setTimeout(() => {
629
- this.listeners.onSessionGracePeriodElapsed();
630
- }, this.options.sessionDisconnectGraceMs);
631
- }
632
662
  _handleClose() {
633
663
  super._handleClose();
634
664
  }
635
665
  _handleStateExit() {
636
666
  super._handleStateExit();
637
- if (this.gracePeriodTimeout) {
638
- clearTimeout(this.gracePeriodTimeout);
639
- this.gracePeriodTimeout = void 0;
640
- }
641
667
  }
642
668
  };
643
669
 
@@ -645,7 +671,7 @@ var SessionNoConnection = class extends IdentifiedSession {
645
671
  var import_api = require("@opentelemetry/api");
646
672
 
647
673
  // package.json
648
- var version = "0.26.1";
674
+ var version = "0.26.3";
649
675
 
650
676
  // tracing/index.ts
651
677
  function createSessionTelemetryInfo(sessionId, to, from, propagationCtx) {
@@ -684,6 +710,13 @@ var SessionWaitingForHandshake = class extends CommonSession {
684
710
  this.conn.addErrorListener(this.listeners.onConnectionErrored);
685
711
  this.conn.addCloseListener(this.listeners.onConnectionClosed);
686
712
  }
713
+ get loggingMetadata() {
714
+ return {
715
+ clientId: this.from,
716
+ connId: this.conn.id,
717
+ ...this.conn.loggingMetadata
718
+ };
719
+ }
687
720
  onHandshakeData = (msg) => {
688
721
  const parsedMsg = this.parseMsg(msg);
689
722
  if (parsedMsg === null) {
@@ -695,12 +728,6 @@ var SessionWaitingForHandshake = class extends CommonSession {
695
728
  }
696
729
  this.listeners.onHandshake(parsedMsg);
697
730
  };
698
- get loggingMetadata() {
699
- return {
700
- clientId: this.from,
701
- connId: this.conn.id
702
- };
703
- }
704
731
  sendHandshake(msg) {
705
732
  return this.conn.send(this.options.codec.toBuffer(msg));
706
733
  }
@@ -717,7 +744,7 @@ var SessionWaitingForHandshake = class extends CommonSession {
717
744
  };
718
745
 
719
746
  // transport/sessionStateMachine/SessionHandshaking.ts
720
- var SessionHandshaking = class extends IdentifiedSession {
747
+ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
721
748
  state = "Handshaking" /* Handshaking */;
722
749
  conn;
723
750
  listeners;
@@ -733,6 +760,12 @@ var SessionHandshaking = class extends IdentifiedSession {
733
760
  this.conn.addErrorListener(this.listeners.onConnectionErrored);
734
761
  this.conn.addCloseListener(this.listeners.onConnectionClosed);
735
762
  }
763
+ get loggingMetadata() {
764
+ return {
765
+ ...super.loggingMetadata,
766
+ ...this.conn.loggingMetadata
767
+ };
768
+ }
736
769
  onHandshakeData = (msg) => {
737
770
  const parsedMsg = this.parseMsg(msg);
738
771
  if (parsedMsg === null) {
@@ -752,7 +785,10 @@ var SessionHandshaking = class extends IdentifiedSession {
752
785
  this.conn.removeDataListener(this.onHandshakeData);
753
786
  this.conn.removeErrorListener(this.listeners.onConnectionErrored);
754
787
  this.conn.removeCloseListener(this.listeners.onConnectionClosed);
755
- clearTimeout(this.handshakeTimeout);
788
+ if (this.handshakeTimeout) {
789
+ clearTimeout(this.handshakeTimeout);
790
+ this.handshakeTimeout = void 0;
791
+ }
756
792
  }
757
793
  _handleClose() {
758
794
  super._handleClose();
@@ -817,6 +853,12 @@ var SessionConnected = class extends IdentifiedSession {
817
853
  this.heartbeatMisses++;
818
854
  }, this.options.heartbeatIntervalMs);
819
855
  }
856
+ get loggingMetadata() {
857
+ return {
858
+ ...super.loggingMetadata,
859
+ ...this.conn.loggingMetadata
860
+ };
861
+ }
820
862
  startActiveHeartbeat() {
821
863
  this.isActivelyHeartbeating = true;
822
864
  }
@@ -832,8 +874,10 @@ var SessionConnected = class extends IdentifiedSession {
832
874
  }
833
875
  onMessageData = (msg) => {
834
876
  const parsedMsg = this.parseMsg(msg);
835
- if (parsedMsg === null)
877
+ if (parsedMsg === null) {
878
+ this.listeners.onInvalidMessage("could not parse message");
836
879
  return;
880
+ }
837
881
  if (parsedMsg.seq !== this.ack) {
838
882
  if (parsedMsg.seq < this.ack) {
839
883
  this.log?.debug(
@@ -890,7 +934,7 @@ var SessionConnected = class extends IdentifiedSession {
890
934
  };
891
935
 
892
936
  // transport/sessionStateMachine/SessionBackingOff.ts
893
- var SessionBackingOff = class extends IdentifiedSession {
937
+ var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
894
938
  state = "BackingOff" /* BackingOff */;
895
939
  listeners;
896
940
  backoffTimeout;
@@ -927,6 +971,12 @@ function inheritSharedSession(session) {
927
971
  log: session.log
928
972
  };
929
973
  }
974
+ function inheritSharedSessionWithGrace(session) {
975
+ return {
976
+ ...inheritSharedSession(session),
977
+ graceExpiryTime: session.graceExpiryTime
978
+ };
979
+ }
930
980
  var SessionStateGraph = {
931
981
  entrypoints: {
932
982
  NoConnection: (to, from, listeners, options, log) => {
@@ -940,6 +990,7 @@ var SessionStateGraph = {
940
990
  to,
941
991
  seq: 0,
942
992
  ack: 0,
993
+ graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
943
994
  sendBuffer,
944
995
  telemetry,
945
996
  options,
@@ -971,7 +1022,7 @@ var SessionStateGraph = {
971
1022
  transition: {
972
1023
  // happy path transitions
973
1024
  NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
974
- const carriedState = inheritSharedSession(oldSession);
1025
+ const carriedState = inheritSharedSessionWithGrace(oldSession);
975
1026
  oldSession._handleStateExit();
976
1027
  const session = new SessionBackingOff({
977
1028
  backoffMs,
@@ -988,7 +1039,7 @@ var SessionStateGraph = {
988
1039
  return session;
989
1040
  },
990
1041
  BackingOffToConnecting: (oldSession, connPromise, listeners) => {
991
- const carriedState = inheritSharedSession(oldSession);
1042
+ const carriedState = inheritSharedSessionWithGrace(oldSession);
992
1043
  oldSession._handleStateExit();
993
1044
  const session = new SessionConnecting({
994
1045
  connPromise,
@@ -1005,7 +1056,7 @@ var SessionStateGraph = {
1005
1056
  return session;
1006
1057
  },
1007
1058
  ConnectingToHandshaking: (oldSession, conn, listeners) => {
1008
- const carriedState = inheritSharedSession(oldSession);
1059
+ const carriedState = inheritSharedSessionWithGrace(oldSession);
1009
1060
  oldSession._handleStateExit();
1010
1061
  const session = new SessionHandshaking({
1011
1062
  conn,
@@ -1082,9 +1133,12 @@ var SessionStateGraph = {
1082
1133
  },
1083
1134
  // disconnect paths
1084
1135
  BackingOffToNoConnection: (oldSession, listeners) => {
1085
- const carriedState = inheritSharedSession(oldSession);
1136
+ const carriedState = inheritSharedSessionWithGrace(oldSession);
1086
1137
  oldSession._handleStateExit();
1087
- const session = new SessionNoConnection({ listeners, ...carriedState });
1138
+ const session = new SessionNoConnection({
1139
+ listeners,
1140
+ ...carriedState
1141
+ });
1088
1142
  session.log?.info(
1089
1143
  `session ${session.id} transition from BackingOff to NoConnection`,
1090
1144
  {
@@ -1095,10 +1149,13 @@ var SessionStateGraph = {
1095
1149
  return session;
1096
1150
  },
1097
1151
  ConnectingToNoConnection: (oldSession, listeners) => {
1098
- const carriedState = inheritSharedSession(oldSession);
1152
+ const carriedState = inheritSharedSessionWithGrace(oldSession);
1099
1153
  oldSession.bestEffortClose();
1100
1154
  oldSession._handleStateExit();
1101
- const session = new SessionNoConnection({ listeners, ...carriedState });
1155
+ const session = new SessionNoConnection({
1156
+ listeners,
1157
+ ...carriedState
1158
+ });
1102
1159
  session.log?.info(
1103
1160
  `session ${session.id} transition from Connecting to NoConnection`,
1104
1161
  {
@@ -1109,10 +1166,13 @@ var SessionStateGraph = {
1109
1166
  return session;
1110
1167
  },
1111
1168
  HandshakingToNoConnection: (oldSession, listeners) => {
1112
- const carriedState = inheritSharedSession(oldSession);
1169
+ const carriedState = inheritSharedSessionWithGrace(oldSession);
1113
1170
  oldSession.conn.close();
1114
1171
  oldSession._handleStateExit();
1115
- const session = new SessionNoConnection({ listeners, ...carriedState });
1172
+ const session = new SessionNoConnection({
1173
+ listeners,
1174
+ ...carriedState
1175
+ });
1116
1176
  session.log?.info(
1117
1177
  `session ${session.id} transition from Handshaking to NoConnection`,
1118
1178
  {
@@ -1124,9 +1184,14 @@ var SessionStateGraph = {
1124
1184
  },
1125
1185
  ConnectedToNoConnection: (oldSession, listeners) => {
1126
1186
  const carriedState = inheritSharedSession(oldSession);
1187
+ const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
1127
1188
  oldSession.conn.close();
1128
1189
  oldSession._handleStateExit();
1129
- const session = new SessionNoConnection({ listeners, ...carriedState });
1190
+ const session = new SessionNoConnection({
1191
+ listeners,
1192
+ graceExpiryTime,
1193
+ ...carriedState
1194
+ });
1130
1195
  session.log?.info(
1131
1196
  `session ${session.id} transition from Connected to NoConnection`,
1132
1197
  {
@@ -1143,24 +1208,42 @@ var ClientSessionStateGraph = {
1143
1208
  entrypoint: SessionStateGraph.entrypoints.NoConnection,
1144
1209
  transition: {
1145
1210
  // happy paths
1211
+ // NoConnection -> BackingOff: attempt to connect
1146
1212
  NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
1213
+ // BackingOff -> Connecting: backoff period elapsed, start connection
1147
1214
  BackingOffToConnecting: transitions.BackingOffToConnecting,
1215
+ // Connecting -> Handshaking: connection established, start handshake
1148
1216
  ConnectingToHandshaking: transitions.ConnectingToHandshaking,
1217
+ // Handshaking -> Connected: handshake complete, session ready
1149
1218
  HandshakingToConnected: transitions.HandshakingToConnected,
1150
1219
  // disconnect paths
1220
+ // BackingOff -> NoConnection: unused
1151
1221
  BackingOffToNoConnection: transitions.BackingOffToNoConnection,
1222
+ // Connecting -> NoConnection: connection failed or connection timeout
1152
1223
  ConnectingToNoConnection: transitions.ConnectingToNoConnection,
1224
+ // Handshaking -> NoConnection: connection closed or handshake timeout
1153
1225
  HandshakingToNoConnection: transitions.HandshakingToNoConnection,
1226
+ // Connected -> NoConnection: connection closed
1154
1227
  ConnectedToNoConnection: transitions.ConnectedToNoConnection
1228
+ // destroy/close paths
1229
+ // NoConnection -> x: grace period elapsed
1230
+ // BackingOff -> x: grace period elapsed
1231
+ // Connecting -> x: grace period elapsed
1232
+ // Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
1233
+ // Connected -> x: grace period elapsed or invalid message
1155
1234
  }
1156
1235
  };
1157
1236
  var ServerSessionStateGraph = {
1158
1237
  entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
1159
1238
  transition: {
1160
1239
  // happy paths
1240
+ // WaitingForHandshake -> Connected: handshake complete, session ready
1161
1241
  WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
1162
1242
  // disconnect paths
1243
+ // Connected -> NoConnection: connection closed
1163
1244
  ConnectedToNoConnection: transitions.ConnectedToNoConnection
1245
+ // destroy/close paths
1246
+ // WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
1164
1247
  }
1165
1248
  };
1166
1249
 
@@ -1277,8 +1360,9 @@ var Transport = class {
1277
1360
  status: "disconnect",
1278
1361
  session
1279
1362
  });
1363
+ const to = session.to;
1280
1364
  session.close();
1281
- this.sessions.delete(session.to);
1365
+ this.sessions.delete(to);
1282
1366
  }
1283
1367
  // common listeners
1284
1368
  onSessionGracePeriodElapsed(session) {
@@ -1511,19 +1595,58 @@ var ServerTransport = class extends Transport {
1511
1595
  return;
1512
1596
  }
1513
1597
  let oldSession = this.sessions.get(msg.from);
1514
- const parsedMetadata = await this.validateHandshakeMetadata(
1515
- session,
1516
- oldSession,
1517
- msg.payload.metadata,
1518
- msg.from
1519
- );
1520
- if (parsedMetadata === false) {
1521
- return;
1598
+ let parsedMetadata = {};
1599
+ if (this.handshakeExtensions) {
1600
+ if (!import_value2.Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {
1601
+ this.rejectHandshakeRequest(
1602
+ session,
1603
+ msg.from,
1604
+ "received malformed handshake metadata",
1605
+ "MALFORMED_HANDSHAKE_META",
1606
+ {
1607
+ ...session.loggingMetadata,
1608
+ connectedTo: msg.from,
1609
+ validationErrors: [
1610
+ ...import_value2.Value.Errors(
1611
+ this.handshakeExtensions.schema,
1612
+ msg.payload.metadata
1613
+ )
1614
+ ]
1615
+ }
1616
+ );
1617
+ return;
1618
+ }
1619
+ const previousParsedMetadata = oldSession ? this.sessionHandshakeMetadata.get(oldSession.to) : void 0;
1620
+ const parsedMetadataOrFailureCode = await this.handshakeExtensions.validate(
1621
+ msg.payload.metadata,
1622
+ previousParsedMetadata
1623
+ );
1624
+ if (session._isConsumed) {
1625
+ return;
1626
+ }
1627
+ if (import_value2.Value.Check(
1628
+ HandshakeErrorCustomHandlerFatalResponseCodes,
1629
+ parsedMetadataOrFailureCode
1630
+ )) {
1631
+ this.rejectHandshakeRequest(
1632
+ session,
1633
+ msg.from,
1634
+ "rejected by handshake handler",
1635
+ parsedMetadataOrFailureCode,
1636
+ {
1637
+ ...session.loggingMetadata,
1638
+ connectedTo: msg.from,
1639
+ clientId: this.clientId
1640
+ }
1641
+ );
1642
+ return;
1643
+ }
1644
+ parsedMetadata = parsedMetadataOrFailureCode;
1522
1645
  }
1523
1646
  let connectCase = "new session";
1524
1647
  const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
1525
1648
  const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
1526
- if (oldSession && oldSession.id === msg.payload.sessionId) {
1649
+ if (this.options.enableTransparentSessionReconnects && oldSession && oldSession.id === msg.payload.sessionId) {
1527
1650
  connectCase = "transparent reconnection";
1528
1651
  const ourNextSeq = oldSession.nextSeq();
1529
1652
  const ourAck = oldSession.ack;
@@ -1582,10 +1705,11 @@ var ServerTransport = class extends Transport {
1582
1705
  }
1583
1706
  if (!oldSession && (clientNextSentSeq > 0 || clientNextExpectedSeq > 0)) {
1584
1707
  connectCase = "unknown session";
1708
+ const rejectionMessage = this.options.enableTransparentSessionReconnects ? `client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}` : `client is attempting a transparent reconnect to a session but the server does not support it: ${msg.payload.sessionId}`;
1585
1709
  this.rejectHandshakeRequest(
1586
1710
  session,
1587
1711
  msg.from,
1588
- `client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}`,
1712
+ rejectionMessage,
1589
1713
  "SESSION_STATE_MISMATCH",
1590
1714
  {
1591
1715
  ...session.loggingMetadata,
@@ -1649,47 +1773,6 @@ var ServerTransport = class extends Transport {
1649
1773
  this.pendingSessions.delete(session);
1650
1774
  connectedSession.startActiveHeartbeat();
1651
1775
  }
1652
- async validateHandshakeMetadata(handshakingSession, existingSession, rawMetadata, from) {
1653
- if (!this.handshakeExtensions) {
1654
- return {};
1655
- }
1656
- if (!import_value2.Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
1657
- this.rejectHandshakeRequest(
1658
- handshakingSession,
1659
- from,
1660
- "received malformed handshake metadata",
1661
- "MALFORMED_HANDSHAKE_META",
1662
- {
1663
- ...handshakingSession.loggingMetadata,
1664
- connectedTo: from,
1665
- validationErrors: [
1666
- ...import_value2.Value.Errors(this.handshakeExtensions.schema, rawMetadata)
1667
- ]
1668
- }
1669
- );
1670
- return false;
1671
- }
1672
- const previousParsedMetadata = existingSession ? this.sessionHandshakeMetadata.get(existingSession.to) : void 0;
1673
- const parsedMetadata = await this.handshakeExtensions.validate(
1674
- rawMetadata,
1675
- previousParsedMetadata
1676
- );
1677
- if (import_value2.Value.Check(HandshakeErrorCustomHandlerFatalResponseCodes, parsedMetadata)) {
1678
- this.rejectHandshakeRequest(
1679
- handshakingSession,
1680
- from,
1681
- "rejected by handshake handler",
1682
- parsedMetadata,
1683
- {
1684
- ...handshakingSession.loggingMetadata,
1685
- connectedTo: from,
1686
- clientId: this.clientId
1687
- }
1688
- );
1689
- return false;
1690
- }
1691
- return parsedMetadata;
1692
- }
1693
1776
  };
1694
1777
 
1695
1778
  // transport/impls/ws/server.ts