@replit/river 0.25.1 → 0.26.0

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 (54) hide show
  1. package/dist/{chunk-D5O3ERJU.js → chunk-5FDAIAQ5.js} +3 -3
  2. package/dist/chunk-5FDAIAQ5.js.map +1 -0
  3. package/dist/{chunk-5CNNIOAO.js → chunk-5S64PXTU.js} +102 -95
  4. package/dist/chunk-5S64PXTU.js.map +1 -0
  5. package/dist/{chunk-PCBPPTXH.js → chunk-7ETNUCOL.js} +54 -62
  6. package/dist/chunk-7ETNUCOL.js.map +1 -0
  7. package/dist/{chunk-SGSRNAWJ.js → chunk-BNNELZM4.js} +2 -2
  8. package/dist/{chunk-SGSRNAWJ.js.map → chunk-BNNELZM4.js.map} +1 -1
  9. package/dist/{chunk-SZ5NBBX7.js → chunk-CCUYKR5C.js} +14 -4
  10. package/dist/chunk-CCUYKR5C.js.map +1 -0
  11. package/dist/{chunk-YM5Y4NAT.js → chunk-JSU2KACV.js} +199 -117
  12. package/dist/chunk-JSU2KACV.js.map +1 -0
  13. package/dist/{chunk-MBMEJIPU.js → chunk-KP4UB5NW.js} +2 -2
  14. package/dist/{client-1321630c.d.ts → client-162c509c.d.ts} +4 -2
  15. package/dist/{connection-bd907ca6.d.ts → connection-6a404bb8.d.ts} +1 -1
  16. package/dist/{handshake-3772d7ca.d.ts → handshake-3342bb94.d.ts} +132 -84
  17. package/dist/logging/index.d.cts +1 -1
  18. package/dist/logging/index.d.ts +1 -1
  19. package/dist/{message-e6c560fd.d.ts → message-1a434848.d.ts} +2 -1
  20. package/dist/router/index.cjs +12 -3
  21. package/dist/router/index.cjs.map +1 -1
  22. package/dist/router/index.d.cts +8 -8
  23. package/dist/router/index.d.ts +8 -8
  24. package/dist/router/index.js +2 -2
  25. package/dist/{server-f0fd2b98.d.ts → server-1b695374.d.ts} +9 -4
  26. package/dist/{services-8d14ae16.d.ts → services-c17f7eff.d.ts} +3 -3
  27. package/dist/transport/impls/ws/client.cjs +302 -207
  28. package/dist/transport/impls/ws/client.cjs.map +1 -1
  29. package/dist/transport/impls/ws/client.d.cts +4 -4
  30. package/dist/transport/impls/ws/client.d.ts +4 -4
  31. package/dist/transport/impls/ws/client.js +5 -5
  32. package/dist/transport/impls/ws/server.cjs +253 -174
  33. package/dist/transport/impls/ws/server.cjs.map +1 -1
  34. package/dist/transport/impls/ws/server.d.cts +4 -4
  35. package/dist/transport/impls/ws/server.d.ts +4 -4
  36. package/dist/transport/impls/ws/server.js +5 -5
  37. package/dist/transport/index.cjs +351 -264
  38. package/dist/transport/index.cjs.map +1 -1
  39. package/dist/transport/index.d.cts +4 -4
  40. package/dist/transport/index.d.ts +4 -4
  41. package/dist/transport/index.js +5 -5
  42. package/dist/util/testHelpers.cjs +208 -117
  43. package/dist/util/testHelpers.cjs.map +1 -1
  44. package/dist/util/testHelpers.d.cts +6 -5
  45. package/dist/util/testHelpers.d.ts +6 -5
  46. package/dist/util/testHelpers.js +6 -3
  47. package/dist/util/testHelpers.js.map +1 -1
  48. package/package.json +14 -13
  49. package/dist/chunk-5CNNIOAO.js.map +0 -1
  50. package/dist/chunk-D5O3ERJU.js.map +0 -1
  51. package/dist/chunk-PCBPPTXH.js.map +0 -1
  52. package/dist/chunk-SZ5NBBX7.js.map +0 -1
  53. package/dist/chunk-YM5Y4NAT.js.map +0 -1
  54. /package/dist/{chunk-MBMEJIPU.js.map → chunk-KP4UB5NW.js.map} +0 -0
@@ -85,11 +85,20 @@ var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
85
85
  var HandshakeErrorRetriableResponseCodes = import_typebox.Type.Union([
86
86
  import_typebox.Type.Literal("SESSION_STATE_MISMATCH")
87
87
  ]);
88
+ var HandshakeErrorCustomHandlerFatalResponseCodes = import_typebox.Type.Union([
89
+ // The custom validation handler rejected the handler because the client is unsupported.
90
+ import_typebox.Type.Literal("REJECTED_UNSUPPORTED_CLIENT"),
91
+ // The custom validation handler rejected the handshake.
92
+ import_typebox.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
93
+ ]);
88
94
  var HandshakeErrorFatalResponseCodes = import_typebox.Type.Union([
95
+ HandshakeErrorCustomHandlerFatalResponseCodes,
96
+ // The ciient sent a handshake that doesn't comply with the extended handshake metadata.
89
97
  import_typebox.Type.Literal("MALFORMED_HANDSHAKE_META"),
98
+ // The ciient sent a handshake that doesn't comply with ControlMessageHandshakeRequestSchema.
90
99
  import_typebox.Type.Literal("MALFORMED_HANDSHAKE"),
91
- import_typebox.Type.Literal("PROTOCOL_VERSION_MISMATCH"),
92
- import_typebox.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
100
+ // The client's protocol version does not match the server's.
101
+ import_typebox.Type.Literal("PROTOCOL_VERSION_MISMATCH")
93
102
  ]);
94
103
  var HandshakeErrorResponseCodes = import_typebox.Type.Union([
95
104
  HandshakeErrorRetriableResponseCodes,
@@ -212,7 +221,7 @@ var defaultTransportOptions = {
212
221
  codec: NaiveJsonCodec
213
222
  };
214
223
  var defaultConnectionRetryOptions = {
215
- baseIntervalMs: 250,
224
+ baseIntervalMs: 150,
216
225
  maxJitterMs: 200,
217
226
  maxBackoffMs: 32e3,
218
227
  attemptBudgetCapacity: 5,
@@ -229,17 +238,17 @@ var defaultServerTransportOptions = {
229
238
  // transport/rateLimit.ts
230
239
  var LeakyBucketRateLimit = class {
231
240
  budgetConsumed;
232
- intervalHandles;
241
+ intervalHandle;
233
242
  options;
234
243
  constructor(options) {
235
244
  this.options = options;
236
- this.budgetConsumed = /* @__PURE__ */ new Map();
237
- this.intervalHandles = /* @__PURE__ */ new Map();
245
+ this.budgetConsumed = 0;
238
246
  }
239
- getBackoffMs(user) {
240
- if (!this.budgetConsumed.has(user))
247
+ getBackoffMs() {
248
+ if (this.getBudgetConsumed() === 0) {
241
249
  return 0;
242
- const exponent = Math.max(0, this.getBudgetConsumed(user) - 1);
250
+ }
251
+ const exponent = Math.max(0, this.getBudgetConsumed() - 1);
243
252
  const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
244
253
  const backoffMs = Math.min(
245
254
  this.options.baseIntervalMs * 2 ** exponent,
@@ -250,50 +259,46 @@ var LeakyBucketRateLimit = class {
250
259
  get totalBudgetRestoreTime() {
251
260
  return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
252
261
  }
253
- consumeBudget(user) {
254
- this.stopLeak(user);
255
- this.budgetConsumed.set(user, this.getBudgetConsumed(user) + 1);
262
+ consumeBudget() {
263
+ this.stopLeak();
264
+ this.budgetConsumed = this.getBudgetConsumed() + 1;
256
265
  }
257
- getBudgetConsumed(user) {
258
- return this.budgetConsumed.get(user) ?? 0;
266
+ getBudgetConsumed() {
267
+ return this.budgetConsumed;
259
268
  }
260
- hasBudget(user) {
261
- return this.getBudgetConsumed(user) < this.options.attemptBudgetCapacity;
269
+ hasBudget() {
270
+ return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
262
271
  }
263
- startRestoringBudget(user) {
264
- if (this.intervalHandles.has(user)) {
272
+ startRestoringBudget() {
273
+ if (this.intervalHandle) {
265
274
  return;
266
275
  }
267
276
  const restoreBudgetForUser = () => {
268
- const currentBudget = this.budgetConsumed.get(user);
277
+ const currentBudget = this.budgetConsumed;
269
278
  if (!currentBudget) {
270
- this.stopLeak(user);
279
+ this.stopLeak();
271
280
  return;
272
281
  }
273
282
  const newBudget = currentBudget - 1;
274
283
  if (newBudget === 0) {
275
- this.budgetConsumed.delete(user);
276
284
  return;
277
285
  }
278
- this.budgetConsumed.set(user, newBudget);
286
+ this.budgetConsumed = newBudget;
279
287
  };
280
- const intervalHandle = setInterval(
288
+ this.intervalHandle = setInterval(
281
289
  restoreBudgetForUser,
282
290
  this.options.budgetRestoreIntervalMs
283
291
  );
284
- this.intervalHandles.set(user, intervalHandle);
285
292
  }
286
- stopLeak(user) {
287
- if (!this.intervalHandles.has(user)) {
293
+ stopLeak() {
294
+ if (!this.intervalHandle) {
288
295
  return;
289
296
  }
290
- clearInterval(this.intervalHandles.get(user));
291
- this.intervalHandles.delete(user);
297
+ clearInterval(this.intervalHandle);
298
+ this.intervalHandle = void 0;
292
299
  }
293
300
  close() {
294
- for (const user of this.intervalHandles.keys()) {
295
- this.stopLeak(user);
296
- }
301
+ this.stopLeak();
297
302
  }
298
303
  };
299
304
 
@@ -440,7 +445,7 @@ var CommonSession = class extends StateMachineState {
440
445
  from;
441
446
  options;
442
447
  log;
443
- constructor(from, options, log) {
448
+ constructor({ from, options, log }) {
444
449
  super();
445
450
  this.from = from;
446
451
  this.options = options;
@@ -481,8 +486,9 @@ var IdentifiedSession = class extends CommonSession {
481
486
  */
482
487
  ack;
483
488
  sendBuffer;
484
- constructor(id, from, to, seq, ack, sendBuffer, telemetry, options, log) {
485
- super(from, options, log);
489
+ constructor(props) {
490
+ const { id, to, seq, ack, sendBuffer, telemetry, log } = props;
491
+ super(props);
486
492
  this.id = id;
487
493
  this.to = to;
488
494
  this.seq = seq;
@@ -537,23 +543,23 @@ var SessionConnecting = class extends IdentifiedSession {
537
543
  connPromise;
538
544
  listeners;
539
545
  connectionTimeout;
540
- constructor(connPromise, listeners, ...args) {
541
- super(...args);
542
- this.connPromise = connPromise;
543
- this.listeners = listeners;
546
+ constructor(props) {
547
+ super(props);
548
+ this.connPromise = props.connPromise;
549
+ this.listeners = props.listeners;
544
550
  this.connectionTimeout = setTimeout(() => {
545
- listeners.onConnectionTimeout();
551
+ this.listeners.onConnectionTimeout();
546
552
  }, this.options.connectionTimeoutMs);
547
- connPromise.then(
553
+ this.connPromise.then(
548
554
  (conn) => {
549
555
  if (this._isConsumed)
550
556
  return;
551
- listeners.onConnectionEstablished(conn);
557
+ this.listeners.onConnectionEstablished(conn);
552
558
  },
553
559
  (err) => {
554
560
  if (this._isConsumed)
555
561
  return;
556
- listeners.onConnectionFailed(err);
562
+ this.listeners.onConnectionFailed(err);
557
563
  }
558
564
  );
559
565
  }
@@ -579,9 +585,9 @@ var SessionNoConnection = class extends IdentifiedSession {
579
585
  state = "NoConnection" /* NoConnection */;
580
586
  listeners;
581
587
  gracePeriodTimeout;
582
- constructor(listeners, ...args) {
583
- super(...args);
584
- this.listeners = listeners;
588
+ constructor(props) {
589
+ super(props);
590
+ this.listeners = props.listeners;
585
591
  this.gracePeriodTimeout = setTimeout(() => {
586
592
  this.listeners.onSessionGracePeriodElapsed();
587
593
  }, this.options.sessionDisconnectGraceMs);
@@ -602,7 +608,7 @@ var SessionNoConnection = class extends IdentifiedSession {
602
608
  var import_api = require("@opentelemetry/api");
603
609
 
604
610
  // package.json
605
- var version = "0.25.1";
611
+ var version = "0.26.0";
606
612
 
607
613
  // tracing/index.ts
608
614
  function getPropagationContext(ctx) {
@@ -639,16 +645,16 @@ var SessionWaitingForHandshake = class extends CommonSession {
639
645
  conn;
640
646
  listeners;
641
647
  handshakeTimeout;
642
- constructor(conn, listeners, ...args) {
643
- super(...args);
644
- this.conn = conn;
645
- this.listeners = listeners;
648
+ constructor(props) {
649
+ super(props);
650
+ this.conn = props.conn;
651
+ this.listeners = props.listeners;
646
652
  this.handshakeTimeout = setTimeout(() => {
647
- listeners.onHandshakeTimeout();
653
+ this.listeners.onHandshakeTimeout();
648
654
  }, this.options.handshakeTimeoutMs);
649
655
  this.conn.addDataListener(this.onHandshakeData);
650
- this.conn.addErrorListener(listeners.onConnectionErrored);
651
- this.conn.addCloseListener(listeners.onConnectionClosed);
656
+ this.conn.addErrorListener(this.listeners.onConnectionErrored);
657
+ this.conn.addCloseListener(this.listeners.onConnectionClosed);
652
658
  }
653
659
  onHandshakeData = (msg) => {
654
660
  const parsedMsg = this.parseMsg(msg);
@@ -685,16 +691,16 @@ var SessionHandshaking = class extends IdentifiedSession {
685
691
  conn;
686
692
  listeners;
687
693
  handshakeTimeout;
688
- constructor(conn, listeners, ...args) {
689
- super(...args);
690
- this.conn = conn;
691
- this.listeners = listeners;
694
+ constructor(props) {
695
+ super(props);
696
+ this.conn = props.conn;
697
+ this.listeners = props.listeners;
692
698
  this.handshakeTimeout = setTimeout(() => {
693
- listeners.onHandshakeTimeout();
699
+ this.listeners.onHandshakeTimeout();
694
700
  }, this.options.handshakeTimeoutMs);
695
701
  this.conn.addDataListener(this.onHandshakeData);
696
- this.conn.addErrorListener(listeners.onConnectionErrored);
697
- this.conn.addCloseListener(listeners.onConnectionClosed);
702
+ this.conn.addErrorListener(this.listeners.onConnectionErrored);
703
+ this.conn.addCloseListener(this.listeners.onConnectionClosed);
698
704
  }
699
705
  onHandshakeData = (msg) => {
700
706
  const parsedMsg = this.parseMsg(msg);
@@ -726,16 +732,13 @@ var SessionConnected = class extends IdentifiedSession {
726
732
  state = "Connected" /* Connected */;
727
733
  conn;
728
734
  listeners;
729
- activeHeartbeatHandle;
730
- activeHeartbeatMisses = 0;
731
- passiveHeartbeatHandle;
732
- get isActivelyHeartbeating() {
733
- return this.activeHeartbeatHandle !== void 0;
734
- }
735
+ heartbeatHandle;
736
+ heartbeatMisses = 0;
737
+ isActivelyHeartbeating;
735
738
  updateBookkeeping(ack, seq) {
736
739
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
737
740
  this.ack = seq + 1;
738
- this.activeHeartbeatMisses = 0;
741
+ this.heartbeatMisses = 0;
739
742
  }
740
743
  send(msg) {
741
744
  const constructedMsg = this.constructMsg(msg);
@@ -743,13 +746,13 @@ var SessionConnected = class extends IdentifiedSession {
743
746
  this.conn.send(this.options.codec.toBuffer(constructedMsg));
744
747
  return constructedMsg.id;
745
748
  }
746
- constructor(conn, listeners, ...args) {
747
- super(...args);
748
- this.conn = conn;
749
- this.listeners = listeners;
749
+ constructor(props) {
750
+ super(props);
751
+ this.conn = props.conn;
752
+ this.listeners = props.listeners;
750
753
  this.conn.addDataListener(this.onMessageData);
751
- this.conn.addCloseListener(listeners.onConnectionClosed);
752
- this.conn.addErrorListener(listeners.onConnectionErrored);
754
+ this.conn.addCloseListener(this.listeners.onConnectionClosed);
755
+ this.conn.addErrorListener(this.listeners.onConnectionErrored);
753
756
  if (this.sendBuffer.length > 0) {
754
757
  this.log?.debug(
755
758
  `sending ${this.sendBuffer.length} buffered messages`,
@@ -757,12 +760,11 @@ var SessionConnected = class extends IdentifiedSession {
757
760
  );
758
761
  }
759
762
  for (const msg of this.sendBuffer) {
760
- conn.send(this.options.codec.toBuffer(msg));
763
+ this.conn.send(this.options.codec.toBuffer(msg));
761
764
  }
762
- }
763
- startActiveHeartbeat() {
764
- this.activeHeartbeatHandle = setInterval(() => {
765
- const misses = this.activeHeartbeatMisses;
765
+ this.isActivelyHeartbeating = false;
766
+ this.heartbeatHandle = setInterval(() => {
767
+ const misses = this.heartbeatMisses;
766
768
  const missDuration = misses * this.options.heartbeatIntervalMs;
767
769
  if (misses >= this.options.heartbeatsUntilDead) {
768
770
  this.log?.info(
@@ -771,29 +773,18 @@ var SessionConnected = class extends IdentifiedSession {
771
773
  );
772
774
  this.telemetry.span.addEvent("closing connection due to inactivity");
773
775
  this.conn.close();
774
- clearInterval(this.activeHeartbeatHandle);
775
- this.activeHeartbeatHandle = void 0;
776
+ clearInterval(this.heartbeatHandle);
777
+ this.heartbeatHandle = void 0;
776
778
  return;
777
779
  }
778
- this.sendHeartbeat();
779
- this.activeHeartbeatMisses++;
780
+ if (this.isActivelyHeartbeating) {
781
+ this.sendHeartbeat();
782
+ }
783
+ this.heartbeatMisses++;
780
784
  }, this.options.heartbeatIntervalMs);
781
785
  }
782
- waitForNextHeartbeat() {
783
- const duration = this.options.heartbeatsUntilDead * this.options.heartbeatIntervalMs;
784
- if (this.passiveHeartbeatHandle) {
785
- clearTimeout(this.passiveHeartbeatHandle);
786
- this.passiveHeartbeatHandle = void 0;
787
- }
788
- this.passiveHeartbeatHandle = setTimeout(() => {
789
- this.log?.info(
790
- `closing connection to ${this.to} due to not receiving a heartbeat in the last ${duration}ms`,
791
- this.loggingMetadata
792
- );
793
- this.telemetry.span.addEvent("closing connection due to inactivity");
794
- this.conn.close();
795
- this.passiveHeartbeatHandle = void 0;
796
- }, duration);
786
+ startActiveHeartbeat() {
787
+ this.isActivelyHeartbeating = true;
797
788
  }
798
789
  sendHeartbeat() {
799
790
  this.log?.debug("sending heartbeat", this.loggingMetadata);
@@ -848,7 +839,6 @@ var SessionConnected = class extends IdentifiedSession {
848
839
  });
849
840
  if (!this.isActivelyHeartbeating) {
850
841
  this.sendHeartbeat();
851
- this.waitForNextHeartbeat();
852
842
  }
853
843
  };
854
844
  _handleStateExit() {
@@ -856,10 +846,8 @@ var SessionConnected = class extends IdentifiedSession {
856
846
  this.conn.removeDataListener(this.onMessageData);
857
847
  this.conn.removeCloseListener(this.listeners.onConnectionClosed);
858
848
  this.conn.removeErrorListener(this.listeners.onConnectionErrored);
859
- clearInterval(this.activeHeartbeatHandle);
860
- clearTimeout(this.passiveHeartbeatHandle);
861
- this.activeHeartbeatHandle = void 0;
862
- this.passiveHeartbeatHandle = void 0;
849
+ clearInterval(this.heartbeatHandle);
850
+ this.heartbeatHandle = void 0;
863
851
  }
864
852
  _handleClose() {
865
853
  super._handleClose();
@@ -867,52 +855,76 @@ var SessionConnected = class extends IdentifiedSession {
867
855
  }
868
856
  };
869
857
 
858
+ // transport/sessionStateMachine/SessionBackingOff.ts
859
+ var SessionBackingOff = class extends IdentifiedSession {
860
+ state = "BackingOff" /* BackingOff */;
861
+ listeners;
862
+ backoffTimeout;
863
+ constructor(props) {
864
+ super(props);
865
+ this.listeners = props.listeners;
866
+ this.backoffTimeout = setTimeout(() => {
867
+ this.listeners.onBackoffFinished();
868
+ }, props.backoffMs);
869
+ }
870
+ _handleClose() {
871
+ super._handleClose();
872
+ }
873
+ _handleStateExit() {
874
+ super._handleStateExit();
875
+ if (this.backoffTimeout) {
876
+ clearTimeout(this.backoffTimeout);
877
+ this.backoffTimeout = void 0;
878
+ }
879
+ }
880
+ };
881
+
870
882
  // transport/sessionStateMachine/transitions.ts
871
883
  function inheritSharedSession(session) {
872
- return [
873
- session.id,
874
- session.from,
875
- session.to,
876
- session.seq,
877
- session.ack,
878
- session.sendBuffer,
879
- session.telemetry,
880
- session.options,
881
- session.log
882
- ];
884
+ return {
885
+ id: session.id,
886
+ from: session.from,
887
+ to: session.to,
888
+ seq: session.seq,
889
+ ack: session.ack,
890
+ sendBuffer: session.sendBuffer,
891
+ telemetry: session.telemetry,
892
+ options: session.options,
893
+ log: session.log
894
+ };
883
895
  }
884
896
  var SessionStateGraph = {
885
897
  entrypoints: {
886
- NoConnection(to, from, listeners, options, log) {
898
+ NoConnection: (to, from, listeners, options, log) => {
887
899
  const id = `session-${generateId()}`;
888
900
  const telemetry = createSessionTelemetryInfo(id, to, from);
889
901
  const sendBuffer = [];
890
- const session = new SessionNoConnection(
902
+ const session = new SessionNoConnection({
891
903
  listeners,
892
904
  id,
893
905
  from,
894
906
  to,
895
- 0,
896
- 0,
907
+ seq: 0,
908
+ ack: 0,
897
909
  sendBuffer,
898
910
  telemetry,
899
911
  options,
900
912
  log
901
- );
913
+ });
902
914
  session.log?.info(`session ${session.id} created in NoConnection state`, {
903
915
  ...session.loggingMetadata,
904
916
  tags: ["state-transition"]
905
917
  });
906
918
  return session;
907
919
  },
908
- WaitingForHandshake(from, conn, listeners, options, log) {
909
- const session = new SessionWaitingForHandshake(
920
+ WaitingForHandshake: (from, conn, listeners, options, log) => {
921
+ const session = new SessionWaitingForHandshake({
910
922
  conn,
911
923
  listeners,
912
924
  from,
913
925
  options,
914
926
  log
915
- );
927
+ });
916
928
  session.log?.info(`session created in WaitingForHandshake state`, {
917
929
  ...session.loggingMetadata,
918
930
  tags: ["state-transition"]
@@ -924,16 +936,33 @@ var SessionStateGraph = {
924
936
  // After a session is transitioned, any usage of the old session will throw.
925
937
  transition: {
926
938
  // happy path transitions
927
- NoConnectionToConnecting(oldSession, connPromise, listeners) {
939
+ NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
928
940
  const carriedState = inheritSharedSession(oldSession);
929
941
  oldSession._handleStateExit();
930
- const session = new SessionConnecting(
931
- connPromise,
942
+ const session = new SessionBackingOff({
943
+ backoffMs,
932
944
  listeners,
933
945
  ...carriedState
946
+ });
947
+ session.log?.info(
948
+ `session ${session.id} transition from NoConnection to BackingOff`,
949
+ {
950
+ ...session.loggingMetadata,
951
+ tags: ["state-transition"]
952
+ }
934
953
  );
954
+ return session;
955
+ },
956
+ BackingOffToConnecting: (oldSession, connPromise, listeners) => {
957
+ const carriedState = inheritSharedSession(oldSession);
958
+ oldSession._handleStateExit();
959
+ const session = new SessionConnecting({
960
+ connPromise,
961
+ listeners,
962
+ ...carriedState
963
+ });
935
964
  session.log?.info(
936
- `session ${session.id} transition from NoConnection to Connecting`,
965
+ `session ${session.id} transition from BackingOff to Connecting`,
937
966
  {
938
967
  ...session.loggingMetadata,
939
968
  tags: ["state-transition"]
@@ -941,10 +970,14 @@ var SessionStateGraph = {
941
970
  );
942
971
  return session;
943
972
  },
944
- ConnectingToHandshaking(oldSession, conn, listeners) {
973
+ ConnectingToHandshaking: (oldSession, conn, listeners) => {
945
974
  const carriedState = inheritSharedSession(oldSession);
946
975
  oldSession._handleStateExit();
947
- const session = new SessionHandshaking(conn, listeners, ...carriedState);
976
+ const session = new SessionHandshaking({
977
+ conn,
978
+ listeners,
979
+ ...carriedState
980
+ });
948
981
  session.log?.info(
949
982
  `session ${session.id} transition from Connecting to Handshaking`,
950
983
  {
@@ -954,11 +987,15 @@ var SessionStateGraph = {
954
987
  );
955
988
  return session;
956
989
  },
957
- HandshakingToConnected(oldSession, listeners) {
990
+ HandshakingToConnected: (oldSession, listeners) => {
958
991
  const carriedState = inheritSharedSession(oldSession);
959
992
  const conn = oldSession.conn;
960
993
  oldSession._handleStateExit();
961
- const session = new SessionConnected(conn, listeners, ...carriedState);
994
+ const session = new SessionConnected({
995
+ conn,
996
+ listeners,
997
+ ...carriedState
998
+ });
962
999
  session.log?.info(
963
1000
  `session ${session.id} transition from Handshaking to Connected`,
964
1001
  {
@@ -968,7 +1005,7 @@ var SessionStateGraph = {
968
1005
  );
969
1006
  return session;
970
1007
  },
971
- WaitingForHandshakeToConnected(pendingSession, oldSession, sessionId, to, propagationCtx, listeners) {
1008
+ WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners) => {
972
1009
  const conn = pendingSession.conn;
973
1010
  const { from, options } = pendingSession;
974
1011
  const carriedState = oldSession ? (
@@ -976,21 +1013,30 @@ var SessionStateGraph = {
976
1013
  inheritSharedSession(oldSession)
977
1014
  ) : (
978
1015
  // old session does not exist, create new state
979
- [
980
- sessionId,
1016
+ {
1017
+ id: sessionId,
981
1018
  from,
982
1019
  to,
983
- 0,
984
- 0,
985
- [],
986
- createSessionTelemetryInfo(sessionId, to, from, propagationCtx),
1020
+ seq: 0,
1021
+ ack: 0,
1022
+ sendBuffer: [],
1023
+ telemetry: createSessionTelemetryInfo(
1024
+ sessionId,
1025
+ to,
1026
+ from,
1027
+ propagationCtx
1028
+ ),
987
1029
  options,
988
- pendingSession.log
989
- ]
1030
+ log: pendingSession.log
1031
+ }
990
1032
  );
991
1033
  pendingSession._handleStateExit();
992
1034
  oldSession?._handleStateExit();
993
- const session = new SessionConnected(conn, listeners, ...carriedState);
1035
+ const session = new SessionConnected({
1036
+ conn,
1037
+ listeners,
1038
+ ...carriedState
1039
+ });
994
1040
  session.log?.info(
995
1041
  `session ${session.id} transition from WaitingForHandshake to Connected`,
996
1042
  {
@@ -1001,11 +1047,24 @@ var SessionStateGraph = {
1001
1047
  return session;
1002
1048
  },
1003
1049
  // disconnect paths
1004
- ConnectingToNoConnection(oldSession, listeners) {
1050
+ BackingOffToNoConnection: (oldSession, listeners) => {
1051
+ const carriedState = inheritSharedSession(oldSession);
1052
+ oldSession._handleStateExit();
1053
+ const session = new SessionNoConnection({ listeners, ...carriedState });
1054
+ session.log?.info(
1055
+ `session ${session.id} transition from BackingOff to NoConnection`,
1056
+ {
1057
+ ...session.loggingMetadata,
1058
+ tags: ["state-transition"]
1059
+ }
1060
+ );
1061
+ return session;
1062
+ },
1063
+ ConnectingToNoConnection: (oldSession, listeners) => {
1005
1064
  const carriedState = inheritSharedSession(oldSession);
1006
1065
  oldSession.bestEffortClose();
1007
1066
  oldSession._handleStateExit();
1008
- const session = new SessionNoConnection(listeners, ...carriedState);
1067
+ const session = new SessionNoConnection({ listeners, ...carriedState });
1009
1068
  session.log?.info(
1010
1069
  `session ${session.id} transition from Connecting to NoConnection`,
1011
1070
  {
@@ -1015,11 +1074,11 @@ var SessionStateGraph = {
1015
1074
  );
1016
1075
  return session;
1017
1076
  },
1018
- HandshakingToNoConnection(oldSession, listeners) {
1077
+ HandshakingToNoConnection: (oldSession, listeners) => {
1019
1078
  const carriedState = inheritSharedSession(oldSession);
1020
1079
  oldSession.conn.close();
1021
1080
  oldSession._handleStateExit();
1022
- const session = new SessionNoConnection(listeners, ...carriedState);
1081
+ const session = new SessionNoConnection({ listeners, ...carriedState });
1023
1082
  session.log?.info(
1024
1083
  `session ${session.id} transition from Handshaking to NoConnection`,
1025
1084
  {
@@ -1029,11 +1088,11 @@ var SessionStateGraph = {
1029
1088
  );
1030
1089
  return session;
1031
1090
  },
1032
- ConnectedToNoConnection(oldSession, listeners) {
1091
+ ConnectedToNoConnection: (oldSession, listeners) => {
1033
1092
  const carriedState = inheritSharedSession(oldSession);
1034
1093
  oldSession.conn.close();
1035
1094
  oldSession._handleStateExit();
1036
- const session = new SessionNoConnection(listeners, ...carriedState);
1095
+ const session = new SessionNoConnection({ listeners, ...carriedState });
1037
1096
  session.log?.info(
1038
1097
  `session ${session.id} transition from Connected to NoConnection`,
1039
1098
  {
@@ -1045,6 +1104,31 @@ var SessionStateGraph = {
1045
1104
  }
1046
1105
  }
1047
1106
  };
1107
+ var transitions = SessionStateGraph.transition;
1108
+ var ClientSessionStateGraph = {
1109
+ entrypoint: SessionStateGraph.entrypoints.NoConnection,
1110
+ transition: {
1111
+ // happy paths
1112
+ NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
1113
+ BackingOffToConnecting: transitions.BackingOffToConnecting,
1114
+ ConnectingToHandshaking: transitions.ConnectingToHandshaking,
1115
+ HandshakingToConnected: transitions.HandshakingToConnected,
1116
+ // disconnect paths
1117
+ BackingOffToNoConnection: transitions.BackingOffToNoConnection,
1118
+ ConnectingToNoConnection: transitions.ConnectingToNoConnection,
1119
+ HandshakingToNoConnection: transitions.HandshakingToNoConnection,
1120
+ ConnectedToNoConnection: transitions.ConnectedToNoConnection
1121
+ }
1122
+ };
1123
+ var ServerSessionStateGraph = {
1124
+ entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
1125
+ transition: {
1126
+ // happy paths
1127
+ WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
1128
+ // disconnect paths
1129
+ ConnectedToNoConnection: transitions.ConnectedToNoConnection
1130
+ }
1131
+ };
1048
1132
 
1049
1133
  // transport/transport.ts
1050
1134
  var Transport = class {
@@ -1224,8 +1308,10 @@ var ClientTransport = class extends Transport {
1224
1308
  * Optional handshake options for this client.
1225
1309
  */
1226
1310
  handshakeExtensions;
1311
+ sessions;
1227
1312
  constructor(clientId, providedOptions) {
1228
1313
  super(clientId, providedOptions);
1314
+ this.sessions = /* @__PURE__ */ new Map();
1229
1315
  this.options = {
1230
1316
  ...defaultClientTransportOptions,
1231
1317
  ...providedOptions
@@ -1257,7 +1343,7 @@ var ClientTransport = class extends Transport {
1257
1343
  return session.send(msg);
1258
1344
  }
1259
1345
  createUnconnectedSession(to) {
1260
- const session = SessionStateGraph.entrypoints.NoConnection(
1346
+ const session = ClientSessionStateGraph.entrypoint(
1261
1347
  to,
1262
1348
  this.clientId,
1263
1349
  {
@@ -1283,40 +1369,44 @@ var ClientTransport = class extends Transport {
1283
1369
  return noConnectionSession;
1284
1370
  }
1285
1371
  onConnectionEstablished(session, conn) {
1286
- const handshakingSession = SessionStateGraph.transition.ConnectingToHandshaking(session, conn, {
1287
- onConnectionErrored: (err) => {
1288
- const errStr = coerceErrorString(err);
1289
- this.log?.error(
1290
- `connection to ${handshakingSession.to} errored during handshake: ${errStr}`,
1291
- handshakingSession.loggingMetadata
1292
- );
1293
- },
1294
- onConnectionClosed: () => {
1295
- this.log?.warn(
1296
- `connection to ${handshakingSession.to} closed during handshake`,
1297
- handshakingSession.loggingMetadata
1298
- );
1299
- this.onConnClosed(handshakingSession);
1300
- },
1301
- onHandshake: (msg) => {
1302
- this.onHandshakeResponse(handshakingSession, msg);
1303
- },
1304
- onInvalidHandshake: (reason) => {
1305
- this.log?.error(
1306
- `invalid handshake: ${reason}`,
1307
- handshakingSession.loggingMetadata
1308
- );
1309
- this.deleteSession(session);
1310
- this.protocolError(ProtocolError.HandshakeFailed, reason);
1311
- },
1312
- onHandshakeTimeout: () => {
1313
- this.log?.error(
1314
- `connection to ${handshakingSession.to} timed out during handshake`,
1315
- handshakingSession.loggingMetadata
1316
- );
1317
- this.onConnClosed(handshakingSession);
1372
+ const handshakingSession = ClientSessionStateGraph.transition.ConnectingToHandshaking(
1373
+ session,
1374
+ conn,
1375
+ {
1376
+ onConnectionErrored: (err) => {
1377
+ const errStr = coerceErrorString(err);
1378
+ this.log?.error(
1379
+ `connection to ${handshakingSession.to} errored during handshake: ${errStr}`,
1380
+ handshakingSession.loggingMetadata
1381
+ );
1382
+ },
1383
+ onConnectionClosed: () => {
1384
+ this.log?.warn(
1385
+ `connection to ${handshakingSession.to} closed during handshake`,
1386
+ handshakingSession.loggingMetadata
1387
+ );
1388
+ this.onConnClosed(handshakingSession);
1389
+ },
1390
+ onHandshake: (msg) => {
1391
+ this.onHandshakeResponse(handshakingSession, msg);
1392
+ },
1393
+ onInvalidHandshake: (reason) => {
1394
+ this.log?.error(
1395
+ `invalid handshake: ${reason}`,
1396
+ handshakingSession.loggingMetadata
1397
+ );
1398
+ this.deleteSession(session);
1399
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
1400
+ },
1401
+ onHandshakeTimeout: () => {
1402
+ this.log?.error(
1403
+ `connection to ${handshakingSession.to} timed out during handshake`,
1404
+ handshakingSession.loggingMetadata
1405
+ );
1406
+ this.onConnClosed(handshakingSession);
1407
+ }
1318
1408
  }
1319
- });
1409
+ );
1320
1410
  this.updateSession(handshakingSession);
1321
1411
  void this.sendHandshake(handshakingSession);
1322
1412
  return handshakingSession;
@@ -1371,7 +1461,7 @@ var ClientTransport = class extends Transport {
1371
1461
  ...session.loggingMetadata,
1372
1462
  transportMessage: msg
1373
1463
  });
1374
- const connectedSession = SessionStateGraph.transition.HandshakingToConnected(session, {
1464
+ const connectedSession = ClientSessionStateGraph.transition.HandshakingToConnected(session, {
1375
1465
  onConnectionErrored: (err) => {
1376
1466
  const errStr = coerceErrorString(err);
1377
1467
  this.log?.warn(
@@ -1393,7 +1483,7 @@ var ClientTransport = class extends Transport {
1393
1483
  }
1394
1484
  });
1395
1485
  this.updateSession(connectedSession);
1396
- this.retryBudget.startRestoringBudget(connectedSession.to);
1486
+ this.retryBudget.startRestoringBudget();
1397
1487
  }
1398
1488
  /**
1399
1489
  * Manually attempts to connect to a client.
@@ -1416,44 +1506,49 @@ var ClientTransport = class extends Transport {
1416
1506
  );
1417
1507
  return;
1418
1508
  }
1419
- if (!this.retryBudget.hasBudget(to)) {
1420
- const budgetConsumed = this.retryBudget.getBudgetConsumed(to);
1509
+ if (!this.retryBudget.hasBudget()) {
1510
+ const budgetConsumed = this.retryBudget.getBudgetConsumed();
1421
1511
  const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
1422
1512
  this.log?.error(errMsg, session.loggingMetadata);
1423
1513
  this.protocolError(ProtocolError.RetriesExceeded, errMsg);
1424
1514
  return;
1425
1515
  }
1426
- let sleep = Promise.resolve();
1427
- const backoffMs = this.retryBudget.getBackoffMs(to);
1428
- if (backoffMs > 0) {
1429
- sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
1430
- }
1516
+ const backoffMs = this.retryBudget.getBackoffMs();
1431
1517
  this.log?.info(
1432
1518
  `attempting connection to ${to} (${backoffMs}ms backoff)`,
1433
1519
  session.loggingMetadata
1434
1520
  );
1435
- this.retryBudget.consumeBudget(to);
1436
- const reconnectPromise = tracing_default.startActiveSpan("connect", async (span) => {
1437
- try {
1438
- span.addEvent("backoff", { backoffMs });
1439
- await sleep;
1440
- if (this.getStatus() !== "open") {
1441
- throw new Error("transport state is no longer open");
1521
+ this.retryBudget.consumeBudget();
1522
+ const backingOffSession = ClientSessionStateGraph.transition.NoConnectionToBackingOff(
1523
+ session,
1524
+ backoffMs,
1525
+ {
1526
+ onBackoffFinished: () => {
1527
+ const reconnectPromise = tracing_default.startActiveSpan(
1528
+ "connect",
1529
+ async (span) => {
1530
+ try {
1531
+ return await this.createNewOutgoingConnection(to);
1532
+ } catch (err) {
1533
+ const errStr = coerceErrorString(err);
1534
+ span.recordException(errStr);
1535
+ span.setStatus({ code: import_api3.SpanStatusCode.ERROR });
1536
+ throw err;
1537
+ } finally {
1538
+ span.end();
1539
+ }
1540
+ }
1541
+ );
1542
+ this.onBackoffFinished(backingOffSession, reconnectPromise);
1442
1543
  }
1443
- span.addEvent("connecting");
1444
- return await this.createNewOutgoingConnection(to);
1445
- } catch (err) {
1446
- const errStr = coerceErrorString(err);
1447
- span.recordException(errStr);
1448
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR });
1449
- throw err;
1450
- } finally {
1451
- span.end();
1452
1544
  }
1453
- });
1454
- const connectingSession = SessionStateGraph.transition.NoConnectionToConnecting(
1545
+ );
1546
+ this.updateSession(backingOffSession);
1547
+ }
1548
+ onBackoffFinished(session, connPromise) {
1549
+ const connectingSession = ClientSessionStateGraph.transition.BackingOffToConnecting(
1455
1550
  session,
1456
- reconnectPromise,
1551
+ connPromise,
1457
1552
  {
1458
1553
  onConnectionEstablished: (conn) => {
1459
1554
  this.log?.debug(