@replit/river 0.207.2 → 0.208.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 (65) hide show
  1. package/dist/adapter-ChksXKVN.d.ts +46 -0
  2. package/dist/adapter-Cuc4JtfV.d.cts +46 -0
  3. package/dist/chunk-2JNVDUMN.js +2238 -0
  4. package/dist/chunk-2JNVDUMN.js.map +1 -0
  5. package/dist/{chunk-4HE7UYRL.js → chunk-DKW3GC3M.js} +6 -5
  6. package/dist/{chunk-4HE7UYRL.js.map → chunk-DKW3GC3M.js.map} +1 -1
  7. package/dist/{chunk-46IVOKJU.js → chunk-ETZAHFGQ.js} +80 -61
  8. package/dist/chunk-ETZAHFGQ.js.map +1 -0
  9. package/dist/codec/index.cjs +157 -23
  10. package/dist/codec/index.cjs.map +1 -1
  11. package/dist/codec/index.d.cts +5 -1
  12. package/dist/codec/index.d.ts +5 -1
  13. package/dist/codec/index.js +6 -20
  14. package/dist/codec/index.js.map +1 -1
  15. package/dist/connection-BF4zg6Qv.d.cts +35 -0
  16. package/dist/{connection-a18e31d5.d.ts → connection-Donr3JRB.d.ts} +4 -3
  17. package/dist/index-C9tpZjBN.d.cts +37 -0
  18. package/dist/index-D8IOd3LG.d.ts +37 -0
  19. package/dist/logging/index.d.cts +2 -1
  20. package/dist/logging/index.d.ts +2 -1
  21. package/dist/{message-ffacb98a.d.ts → message-Di94OL80.d.cts} +1 -35
  22. package/dist/message-Di94OL80.d.ts +108 -0
  23. package/dist/router/index.cjs +62 -43
  24. package/dist/router/index.cjs.map +1 -1
  25. package/dist/router/index.d.cts +27 -7
  26. package/dist/router/index.d.ts +27 -7
  27. package/dist/router/index.js +1 -1
  28. package/dist/testUtil/index.cjs +828 -725
  29. package/dist/testUtil/index.cjs.map +1 -1
  30. package/dist/testUtil/index.d.cts +5 -4
  31. package/dist/testUtil/index.d.ts +5 -4
  32. package/dist/testUtil/index.js +23 -25
  33. package/dist/testUtil/index.js.map +1 -1
  34. package/dist/transport/impls/ws/client.cjs +293 -233
  35. package/dist/transport/impls/ws/client.cjs.map +1 -1
  36. package/dist/transport/impls/ws/client.d.cts +6 -5
  37. package/dist/transport/impls/ws/client.d.ts +6 -5
  38. package/dist/transport/impls/ws/client.js +5 -7
  39. package/dist/transport/impls/ws/client.js.map +1 -1
  40. package/dist/transport/impls/ws/server.cjs +269 -200
  41. package/dist/transport/impls/ws/server.cjs.map +1 -1
  42. package/dist/transport/impls/ws/server.d.cts +6 -5
  43. package/dist/transport/impls/ws/server.d.ts +6 -5
  44. package/dist/transport/impls/ws/server.js +5 -7
  45. package/dist/transport/impls/ws/server.js.map +1 -1
  46. package/dist/transport/index.cjs +438 -342
  47. package/dist/transport/index.cjs.map +1 -1
  48. package/dist/transport/index.d.cts +7 -6
  49. package/dist/transport/index.d.ts +7 -6
  50. package/dist/transport/index.js +5 -10
  51. package/dist/transport-CCaWx1Rb.d.cts +1566 -0
  52. package/dist/{services-43528f4b.d.ts → transport-CZb3vdB4.d.ts} +294 -293
  53. package/dist/{wslike-e0b32dd5.d.ts → wslike-Dng9H1C7.d.cts} +1 -1
  54. package/dist/wslike-Dng9H1C7.d.ts +40 -0
  55. package/package.json +3 -3
  56. package/dist/chunk-24EWYOGK.js +0 -1287
  57. package/dist/chunk-24EWYOGK.js.map +0 -1
  58. package/dist/chunk-46IVOKJU.js.map +0 -1
  59. package/dist/chunk-A7RGOVRV.js +0 -438
  60. package/dist/chunk-A7RGOVRV.js.map +0 -1
  61. package/dist/chunk-AJGIY2UB.js +0 -56
  62. package/dist/chunk-AJGIY2UB.js.map +0 -1
  63. package/dist/chunk-XV4RQ62N.js +0 -377
  64. package/dist/chunk-XV4RQ62N.js.map +0 -1
  65. package/dist/types-3e5768ec.d.ts +0 -20
@@ -186,23 +186,20 @@ var NaiveJsonCodec = {
186
186
  );
187
187
  },
188
188
  fromBuffer: (buff) => {
189
- try {
190
- const parsed = JSON.parse(
191
- decoder.decode(buff),
192
- function reviver(_key, val) {
193
- if (val?.$t) {
194
- return base64ToUint8Array(val.$t);
195
- } else {
196
- return val;
197
- }
189
+ const parsed = JSON.parse(
190
+ decoder.decode(buff),
191
+ function reviver(_key, val) {
192
+ if (val?.$t) {
193
+ return base64ToUint8Array(val.$t);
194
+ } else {
195
+ return val;
198
196
  }
199
- );
200
- if (typeof parsed === "object")
201
- return parsed;
202
- return null;
203
- } catch {
204
- return null;
197
+ }
198
+ );
199
+ if (typeof parsed !== "object" || parsed === null) {
200
+ throw new Error("unpacked msg is not an object");
205
201
  }
202
+ return parsed;
206
203
  }
207
204
  };
208
205
 
@@ -366,7 +363,8 @@ var ProtocolError = {
366
363
  RetriesExceeded: "conn_retry_exceeded",
367
364
  HandshakeFailed: "handshake_failed",
368
365
  MessageOrderingViolated: "message_ordering_violated",
369
- InvalidMessage: "invalid_message"
366
+ InvalidMessage: "invalid_message",
367
+ MessageSendFailure: "message_send_failure"
370
368
  };
371
369
  var EventDispatcher = class {
372
370
  eventListeners = {};
@@ -400,7 +398,6 @@ var EventDispatcher = class {
400
398
  };
401
399
 
402
400
  // transport/sessionStateMachine/common.ts
403
- var import_value = require("@sinclair/typebox/value");
404
401
  var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
405
402
  var StateMachineState = class {
406
403
  /*
@@ -460,34 +457,16 @@ var StateMachineState = class {
460
457
  var CommonSession = class extends StateMachineState {
461
458
  from;
462
459
  options;
460
+ codec;
463
461
  tracer;
464
462
  log;
465
- constructor({ from, options, log, tracer }) {
463
+ constructor({ from, options, log, tracer, codec }) {
466
464
  super();
467
465
  this.from = from;
468
466
  this.options = options;
469
467
  this.log = log;
470
468
  this.tracer = tracer;
471
- }
472
- parseMsg(msg) {
473
- const parsedMsg = this.options.codec.fromBuffer(msg);
474
- if (parsedMsg === null) {
475
- this.log?.error(
476
- `received malformed msg: ${Buffer.from(msg).toString("base64")}`,
477
- this.loggingMetadata
478
- );
479
- return null;
480
- }
481
- if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
482
- this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
483
- ...this.loggingMetadata,
484
- validationErrors: [
485
- ...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
486
- ]
487
- });
488
- return null;
489
- }
490
- return parsedMsg;
469
+ this.codec = codec;
491
470
  }
492
471
  };
493
472
  var IdentifiedSession = class extends CommonSession {
@@ -547,9 +526,6 @@ var IdentifiedSession = class extends CommonSession {
547
526
  return metadata;
548
527
  }
549
528
  constructMsg(partialMsg) {
550
- if (this._isConsumed) {
551
- throw new Error(ERR_CONSUMED);
552
- }
553
529
  const msg = {
554
530
  ...partialMsg,
555
531
  id: generateId(),
@@ -567,7 +543,10 @@ var IdentifiedSession = class extends CommonSession {
567
543
  send(msg) {
568
544
  const constructedMsg = this.constructMsg(msg);
569
545
  this.sendBuffer.push(constructedMsg);
570
- return constructedMsg.id;
546
+ return {
547
+ ok: true,
548
+ value: constructedMsg.id
549
+ };
571
550
  }
572
551
  _handleStateExit() {
573
552
  }
@@ -599,6 +578,23 @@ var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
599
578
  super._handleClose();
600
579
  }
601
580
  };
581
+ function sendMessage(conn, codec, msg) {
582
+ const buff = codec.toBuffer(msg);
583
+ if (!buff.ok) {
584
+ return buff;
585
+ }
586
+ const sent = conn.send(buff.value);
587
+ if (!sent) {
588
+ return {
589
+ ok: false,
590
+ reason: "failed to send message"
591
+ };
592
+ }
593
+ return {
594
+ ok: true,
595
+ value: msg.id
596
+ };
597
+ }
602
598
 
603
599
  // transport/sessionStateMachine/SessionConnecting.ts
604
600
  var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
@@ -612,13 +608,11 @@ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
612
608
  this.listeners = props.listeners;
613
609
  this.connPromise.then(
614
610
  (conn) => {
615
- if (this._isConsumed)
616
- return;
611
+ if (this._isConsumed) return;
617
612
  this.listeners.onConnectionEstablished(conn);
618
613
  },
619
614
  (err) => {
620
- if (this._isConsumed)
621
- return;
615
+ if (this._isConsumed) return;
622
616
  this.listeners.onConnectionFailed(err);
623
617
  }
624
618
  );
@@ -651,8 +645,8 @@ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
651
645
  }
652
646
  }
653
647
  _handleClose() {
654
- this.bestEffortClose();
655
648
  super._handleClose();
649
+ this.bestEffortClose();
656
650
  }
657
651
  };
658
652
 
@@ -679,7 +673,7 @@ function coerceErrorString(err) {
679
673
  }
680
674
 
681
675
  // package.json
682
- var version = "0.207.2";
676
+ var version = "0.208.0";
683
677
 
684
678
  // tracing/index.ts
685
679
  function getPropagationContext(ctx) {
@@ -693,7 +687,7 @@ function getPropagationContext(ctx) {
693
687
  function createSessionTelemetryInfo(tracer, sessionId, to, from, propagationCtx) {
694
688
  const parentCtx = propagationCtx ? import_api2.propagation.extract(import_api2.context.active(), propagationCtx) : import_api2.context.active();
695
689
  const span = tracer.startSpan(
696
- `river.session.${sessionId}`,
690
+ `river.session`,
697
691
  {
698
692
  attributes: {
699
693
  component: "river",
@@ -709,7 +703,7 @@ function createSessionTelemetryInfo(tracer, sessionId, to, from, propagationCtx)
709
703
  }
710
704
  function createConnectionTelemetryInfo(tracer, connection, info) {
711
705
  const span = tracer.startSpan(
712
- `connection ${connection.id}`,
706
+ `river.connection`,
713
707
  {
714
708
  attributes: {
715
709
  component: "river",
@@ -739,9 +733,9 @@ var SessionWaitingForHandshake = class extends CommonSession {
739
733
  this.handshakeTimeout = setTimeout(() => {
740
734
  this.listeners.onHandshakeTimeout();
741
735
  }, this.options.handshakeTimeoutMs);
742
- this.conn.addDataListener(this.onHandshakeData);
743
- this.conn.addErrorListener(this.listeners.onConnectionErrored);
744
- this.conn.addCloseListener(this.listeners.onConnectionClosed);
736
+ this.conn.setDataListener(this.onHandshakeData);
737
+ this.conn.setErrorListener(this.listeners.onConnectionErrored);
738
+ this.conn.setCloseListener(this.listeners.onConnectionClosed);
745
739
  }
746
740
  get loggingMetadata() {
747
741
  return {
@@ -751,23 +745,23 @@ var SessionWaitingForHandshake = class extends CommonSession {
751
745
  };
752
746
  }
753
747
  onHandshakeData = (msg) => {
754
- const parsedMsg = this.parseMsg(msg);
755
- if (parsedMsg === null) {
748
+ const parsedMsgRes = this.codec.fromBuffer(msg);
749
+ if (!parsedMsgRes.ok) {
756
750
  this.listeners.onInvalidHandshake(
757
- "could not parse message",
751
+ `could not parse handshake message: ${parsedMsgRes.reason}`,
758
752
  "MALFORMED_HANDSHAKE"
759
753
  );
760
754
  return;
761
755
  }
762
- this.listeners.onHandshake(parsedMsg);
756
+ this.listeners.onHandshake(parsedMsgRes.value);
763
757
  };
764
758
  sendHandshake(msg) {
765
- return this.conn.send(this.options.codec.toBuffer(msg));
759
+ return sendMessage(this.conn, this.codec, msg);
766
760
  }
767
761
  _handleStateExit() {
768
- this.conn.removeDataListener(this.onHandshakeData);
769
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
770
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
762
+ this.conn.removeDataListener();
763
+ this.conn.removeErrorListener();
764
+ this.conn.removeCloseListener();
771
765
  clearTimeout(this.handshakeTimeout);
772
766
  this.handshakeTimeout = void 0;
773
767
  }
@@ -789,9 +783,9 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
789
783
  this.handshakeTimeout = setTimeout(() => {
790
784
  this.listeners.onHandshakeTimeout();
791
785
  }, this.options.handshakeTimeoutMs);
792
- this.conn.addDataListener(this.onHandshakeData);
793
- this.conn.addErrorListener(this.listeners.onConnectionErrored);
794
- this.conn.addCloseListener(this.listeners.onConnectionClosed);
786
+ this.conn.setDataListener(this.onHandshakeData);
787
+ this.conn.setErrorListener(this.listeners.onConnectionErrored);
788
+ this.conn.setCloseListener(this.listeners.onConnectionClosed);
795
789
  }
796
790
  get loggingMetadata() {
797
791
  return {
@@ -800,24 +794,24 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
800
794
  };
801
795
  }
802
796
  onHandshakeData = (msg) => {
803
- const parsedMsg = this.parseMsg(msg);
804
- if (parsedMsg === null) {
797
+ const parsedMsgRes = this.codec.fromBuffer(msg);
798
+ if (!parsedMsgRes.ok) {
805
799
  this.listeners.onInvalidHandshake(
806
- "could not parse message",
800
+ `could not parse handshake message: ${parsedMsgRes.reason}`,
807
801
  "MALFORMED_HANDSHAKE"
808
802
  );
809
803
  return;
810
804
  }
811
- this.listeners.onHandshake(parsedMsg);
805
+ this.listeners.onHandshake(parsedMsgRes.value);
812
806
  };
813
807
  sendHandshake(msg) {
814
- return this.conn.send(this.options.codec.toBuffer(msg));
808
+ return sendMessage(this.conn, this.codec, msg);
815
809
  }
816
810
  _handleStateExit() {
817
811
  super._handleStateExit();
818
- this.conn.removeDataListener(this.onHandshakeData);
819
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
820
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
812
+ this.conn.removeDataListener();
813
+ this.conn.removeErrorListener();
814
+ this.conn.removeCloseListener();
821
815
  if (this.handshakeTimeout) {
822
816
  clearTimeout(this.handshakeTimeout);
823
817
  this.handshakeTimeout = void 0;
@@ -836,25 +830,15 @@ var SessionConnected = class extends IdentifiedSession {
836
830
  conn;
837
831
  listeners;
838
832
  heartbeatHandle;
839
- heartbeatMisses = 0;
840
- isActivelyHeartbeating;
841
- lastConstructedMsgs = [];
842
- pushLastConstructedMsgs = (msg) => {
843
- const trackedMsg = {
844
- id: msg.id,
845
- seq: msg.seq,
846
- streamId: msg.streamId,
847
- stack: new Error().stack
848
- };
849
- this.lastConstructedMsgs.push(trackedMsg);
850
- if (this.lastConstructedMsgs.length > 10) {
851
- this.lastConstructedMsgs.shift();
852
- }
853
- };
833
+ heartbeatMissTimeout;
834
+ isActivelyHeartbeating = false;
854
835
  updateBookkeeping(ack, seq) {
855
836
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
856
837
  this.ack = seq + 1;
857
- this.heartbeatMisses = 0;
838
+ if (this.heartbeatMissTimeout) {
839
+ clearTimeout(this.heartbeatMissTimeout);
840
+ }
841
+ this.startMissingHeartbeatTimeout();
858
842
  }
859
843
  assertSendOrdering(constructedMsg) {
860
844
  if (constructedMsg.seq > this.seqSent + 1) {
@@ -862,30 +846,32 @@ var SessionConnected = class extends IdentifiedSession {
862
846
  this.log?.error(msg, {
863
847
  ...this.loggingMetadata,
864
848
  transportMessage: constructedMsg,
865
- tags: ["invariant-violation"],
866
- extras: {
867
- lastConstructedMsgs: this.lastConstructedMsgs
868
- }
849
+ tags: ["invariant-violation"]
869
850
  });
870
851
  throw new Error(msg);
871
852
  }
872
853
  }
873
854
  send(msg) {
874
855
  const constructedMsg = this.constructMsg(msg);
875
- this.pushLastConstructedMsgs(constructedMsg);
876
856
  this.assertSendOrdering(constructedMsg);
877
857
  this.sendBuffer.push(constructedMsg);
878
- this.conn.send(this.options.codec.toBuffer(constructedMsg));
858
+ const res = sendMessage(this.conn, this.codec, constructedMsg);
859
+ if (!res.ok) {
860
+ this.listeners.onMessageSendFailure(constructedMsg, res.reason);
861
+ return res;
862
+ }
879
863
  this.seqSent = constructedMsg.seq;
880
- return constructedMsg.id;
864
+ return res;
881
865
  }
882
866
  constructor(props) {
883
867
  super(props);
884
868
  this.conn = props.conn;
885
869
  this.listeners = props.listeners;
886
- this.conn.addDataListener(this.onMessageData);
887
- this.conn.addCloseListener(this.listeners.onConnectionClosed);
888
- this.conn.addErrorListener(this.listeners.onConnectionErrored);
870
+ this.conn.setDataListener(this.onMessageData);
871
+ this.conn.setCloseListener(this.listeners.onConnectionClosed);
872
+ this.conn.setErrorListener(this.listeners.onConnectionErrored);
873
+ }
874
+ sendBufferedMessages() {
889
875
  if (this.sendBuffer.length > 0) {
890
876
  this.log?.info(
891
877
  `sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
@@ -893,30 +879,15 @@ var SessionConnected = class extends IdentifiedSession {
893
879
  );
894
880
  for (const msg of this.sendBuffer) {
895
881
  this.assertSendOrdering(msg);
896
- this.conn.send(this.options.codec.toBuffer(msg));
882
+ const res = sendMessage(this.conn, this.codec, msg);
883
+ if (!res.ok) {
884
+ this.listeners.onMessageSendFailure(msg, res.reason);
885
+ return res;
886
+ }
897
887
  this.seqSent = msg.seq;
898
888
  }
899
889
  }
900
- this.isActivelyHeartbeating = false;
901
- this.heartbeatHandle = setInterval(() => {
902
- const misses = this.heartbeatMisses;
903
- const missDuration = misses * this.options.heartbeatIntervalMs;
904
- if (misses >= this.options.heartbeatsUntilDead) {
905
- this.log?.info(
906
- `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
907
- this.loggingMetadata
908
- );
909
- this.telemetry.span.addEvent("closing connection due to inactivity");
910
- this.conn.close();
911
- clearInterval(this.heartbeatHandle);
912
- this.heartbeatHandle = void 0;
913
- return;
914
- }
915
- if (this.isActivelyHeartbeating) {
916
- this.sendHeartbeat();
917
- }
918
- this.heartbeatMisses++;
919
- }, this.options.heartbeatIntervalMs);
890
+ return { ok: true, value: void 0 };
920
891
  }
921
892
  get loggingMetadata() {
922
893
  return {
@@ -924,25 +895,46 @@ var SessionConnected = class extends IdentifiedSession {
924
895
  ...this.conn.loggingMetadata
925
896
  };
926
897
  }
898
+ startMissingHeartbeatTimeout() {
899
+ const maxMisses = this.options.heartbeatsUntilDead;
900
+ const missDuration = maxMisses * this.options.heartbeatIntervalMs;
901
+ this.heartbeatMissTimeout = setTimeout(() => {
902
+ this.log?.info(
903
+ `closing connection to ${this.to} due to inactivity (missed ${maxMisses} heartbeats which is ${missDuration}ms)`,
904
+ this.loggingMetadata
905
+ );
906
+ this.telemetry.span.addEvent(
907
+ "closing connection due to missing heartbeat"
908
+ );
909
+ this.conn.close();
910
+ }, missDuration);
911
+ }
927
912
  startActiveHeartbeat() {
928
913
  this.isActivelyHeartbeating = true;
914
+ this.heartbeatHandle = setInterval(() => {
915
+ this.sendHeartbeat();
916
+ }, this.options.heartbeatIntervalMs);
929
917
  }
930
918
  sendHeartbeat() {
931
919
  this.log?.debug("sending heartbeat", this.loggingMetadata);
932
- this.send({
920
+ const heartbeat = {
933
921
  streamId: "heartbeat",
934
922
  controlFlags: 1 /* AckBit */,
935
923
  payload: {
936
924
  type: "ACK"
937
925
  }
938
- });
926
+ };
927
+ this.send(heartbeat);
939
928
  }
940
929
  onMessageData = (msg) => {
941
- const parsedMsg = this.parseMsg(msg);
942
- if (parsedMsg === null) {
943
- this.listeners.onInvalidMessage("could not parse message");
930
+ const parsedMsgRes = this.codec.fromBuffer(msg);
931
+ if (!parsedMsgRes.ok) {
932
+ this.listeners.onInvalidMessage(
933
+ `could not parse message: ${parsedMsgRes.reason}`
934
+ );
944
935
  return;
945
936
  }
937
+ const parsedMsg = parsedMsgRes.value;
946
938
  if (parsedMsg.seq !== this.ack) {
947
939
  if (parsedMsg.seq < this.ack) {
948
940
  this.log?.debug(
@@ -981,20 +973,22 @@ var SessionConnected = class extends IdentifiedSession {
981
973
  transportMessage: parsedMsg
982
974
  });
983
975
  if (!this.isActivelyHeartbeating) {
984
- void Promise.resolve().then(() => {
985
- this.sendHeartbeat();
986
- });
976
+ this.sendHeartbeat();
987
977
  }
988
978
  };
989
979
  _handleStateExit() {
990
980
  super._handleStateExit();
991
- this.conn.removeDataListener(this.onMessageData);
992
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
993
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
981
+ this.conn.removeDataListener();
982
+ this.conn.removeCloseListener();
983
+ this.conn.removeErrorListener();
994
984
  if (this.heartbeatHandle) {
995
985
  clearInterval(this.heartbeatHandle);
996
986
  this.heartbeatHandle = void 0;
997
987
  }
988
+ if (this.heartbeatMissTimeout) {
989
+ clearTimeout(this.heartbeatMissTimeout);
990
+ this.heartbeatMissTimeout = void 0;
991
+ }
998
992
  }
999
993
  _handleClose() {
1000
994
  super._handleClose();
@@ -1026,6 +1020,120 @@ var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
1026
1020
  }
1027
1021
  };
1028
1022
 
1023
+ // codec/adapter.ts
1024
+ var import_value = require("@sinclair/typebox/value");
1025
+
1026
+ // transport/connection.ts
1027
+ var Connection = class {
1028
+ id;
1029
+ telemetry;
1030
+ constructor() {
1031
+ this.id = `conn-${generateId()}`;
1032
+ }
1033
+ get loggingMetadata() {
1034
+ const metadata = { connId: this.id };
1035
+ if (this.telemetry?.span.isRecording()) {
1036
+ const spanContext = this.telemetry.span.spanContext();
1037
+ metadata.telemetry = {
1038
+ traceId: spanContext.traceId,
1039
+ spanId: spanContext.spanId
1040
+ };
1041
+ }
1042
+ return metadata;
1043
+ }
1044
+ dataListener;
1045
+ closeListener;
1046
+ errorListener;
1047
+ onData(msg) {
1048
+ this.dataListener?.(msg);
1049
+ }
1050
+ onError(err) {
1051
+ this.errorListener?.(err);
1052
+ }
1053
+ onClose() {
1054
+ this.closeListener?.();
1055
+ this.telemetry?.span.end();
1056
+ }
1057
+ /**
1058
+ * Set the callback for when a message is received.
1059
+ * @param cb The message handler callback.
1060
+ */
1061
+ setDataListener(cb) {
1062
+ this.dataListener = cb;
1063
+ }
1064
+ removeDataListener() {
1065
+ this.dataListener = void 0;
1066
+ }
1067
+ /**
1068
+ * Set the callback for when the connection is closed.
1069
+ * This should also be called if an error happens and after notifying the error listener.
1070
+ * @param cb The callback to call when the connection is closed.
1071
+ */
1072
+ setCloseListener(cb) {
1073
+ this.closeListener = cb;
1074
+ }
1075
+ removeCloseListener() {
1076
+ this.closeListener = void 0;
1077
+ }
1078
+ /**
1079
+ * Set the callback for when an error is received.
1080
+ * This should only be used for logging errors, all cleanup
1081
+ * should be delegated to setCloseListener.
1082
+ *
1083
+ * The implementer should take care such that the implemented
1084
+ * connection will call both the close and error callbacks
1085
+ * on an error.
1086
+ *
1087
+ * @param cb The callback to call when an error is received.
1088
+ */
1089
+ setErrorListener(cb) {
1090
+ this.errorListener = cb;
1091
+ }
1092
+ removeErrorListener() {
1093
+ this.errorListener = void 0;
1094
+ }
1095
+ };
1096
+
1097
+ // codec/adapter.ts
1098
+ var CodecMessageAdapter = class {
1099
+ constructor(codec) {
1100
+ this.codec = codec;
1101
+ }
1102
+ toBuffer(msg) {
1103
+ try {
1104
+ return {
1105
+ ok: true,
1106
+ value: this.codec.toBuffer(msg)
1107
+ };
1108
+ } catch (e) {
1109
+ return {
1110
+ ok: false,
1111
+ reason: coerceErrorString(e)
1112
+ };
1113
+ }
1114
+ }
1115
+ fromBuffer(buf) {
1116
+ try {
1117
+ const parsedMsg = this.codec.fromBuffer(buf);
1118
+ if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
1119
+ return {
1120
+ ok: false,
1121
+ reason: "transport message schema mismatch"
1122
+ };
1123
+ }
1124
+ return {
1125
+ ok: true,
1126
+ value: parsedMsg
1127
+ };
1128
+ } catch (e) {
1129
+ return {
1130
+ ok: false,
1131
+ reason: coerceErrorString(e)
1132
+ };
1133
+ }
1134
+ }
1135
+ };
1136
+
1029
1137
  // transport/sessionStateMachine/transitions.ts
1030
1138
  function inheritSharedSession(session) {
1031
1139
  return {
@@ -1040,7 +1148,8 @@ function inheritSharedSession(session) {
1040
1148
  options: session.options,
1041
1149
  log: session.log,
1042
1150
  tracer: session.tracer,
1043
- protocolVersion: session.protocolVersion
1151
+ protocolVersion: session.protocolVersion,
1152
+ codec: session.codec
1044
1153
  };
1045
1154
  }
1046
1155
  function inheritSharedSessionWithGrace(session) {
@@ -1069,7 +1178,8 @@ var SessionStateGraph = {
1069
1178
  options,
1070
1179
  protocolVersion,
1071
1180
  tracer,
1072
- log
1181
+ log,
1182
+ codec: new CodecMessageAdapter(options.codec)
1073
1183
  });
1074
1184
  session.log?.info(`session ${session.id} created in NoConnection state`, {
1075
1185
  ...session.loggingMetadata,
@@ -1084,7 +1194,8 @@ var SessionStateGraph = {
1084
1194
  from,
1085
1195
  options,
1086
1196
  tracer,
1087
- log
1197
+ log,
1198
+ codec: new CodecMessageAdapter(options.codec)
1088
1199
  });
1089
1200
  session.log?.info(`session created in WaitingForHandshake state`, {
1090
1201
  ...session.loggingMetadata,
@@ -1162,6 +1273,7 @@ var SessionStateGraph = {
1162
1273
  listeners,
1163
1274
  ...carriedState
1164
1275
  });
1276
+ session.startMissingHeartbeatTimeout();
1165
1277
  session.log?.info(
1166
1278
  `session ${session.id} transition from Handshaking to Connected`,
1167
1279
  {
@@ -1197,7 +1309,8 @@ var SessionStateGraph = {
1197
1309
  options,
1198
1310
  tracer: pendingSession.tracer,
1199
1311
  log: pendingSession.log,
1200
- protocolVersion
1312
+ protocolVersion,
1313
+ codec: new CodecMessageAdapter(options.codec)
1201
1314
  }
1202
1315
  );
1203
1316
  pendingSession._handleStateExit();
@@ -1207,6 +1320,7 @@ var SessionStateGraph = {
1207
1320
  listeners,
1208
1321
  ...carriedState
1209
1322
  });
1323
+ session.startMissingHeartbeatTimeout();
1210
1324
  conn.telemetry = createConnectionTelemetryInfo(
1211
1325
  session.tracer,
1212
1326
  conn,
@@ -1384,8 +1498,7 @@ var Transport = class {
1384
1498
  * @param message The received message.
1385
1499
  */
1386
1500
  handleMsg(message) {
1387
- if (this.getStatus() !== "open")
1388
- return;
1501
+ if (this.getStatus() !== "open") return;
1389
1502
  this.eventDispatcher.dispatchEvent("message", message);
1390
1503
  }
1391
1504
  /**
@@ -1473,8 +1586,7 @@ var Transport = class {
1473
1586
  });
1474
1587
  }
1475
1588
  deleteSession(session, options) {
1476
- if (session._isConsumed)
1477
- return;
1589
+ if (session._isConsumed) return;
1478
1590
  const loggingMetadata = session.loggingMetadata;
1479
1591
  if (loggingMetadata.tags && options?.unhealthy) {
1480
1592
  loggingMetadata.tags.push("unhealthy-session");
@@ -1494,7 +1606,7 @@ var Transport = class {
1494
1606
  }
1495
1607
  // common listeners
1496
1608
  onSessionGracePeriodElapsed(session) {
1497
- this.log?.warn(
1609
+ this.log?.info(
1498
1610
  `session to ${session.to} grace period elapsed, closing`,
1499
1611
  session.loggingMetadata
1500
1612
  );
@@ -1547,12 +1659,16 @@ var Transport = class {
1547
1659
  );
1548
1660
  }
1549
1661
  const sameSession = session.id === sessionId;
1550
- if (!sameSession) {
1662
+ if (!sameSession || session._isConsumed) {
1551
1663
  throw new Error(
1552
1664
  `session scope for ${sessionId} has ended (transition), can't send`
1553
1665
  );
1554
1666
  }
1555
- return session.send(msg);
1667
+ const res = session.send(msg);
1668
+ if (!res.ok) {
1669
+ throw new Error(res.reason);
1670
+ }
1671
+ return res.value;
1556
1672
  };
1557
1673
  }
1558
1674
  };
@@ -1753,13 +1869,32 @@ var ClientTransport = class extends Transport {
1753
1869
  this.handleMsg(msg2);
1754
1870
  },
1755
1871
  onInvalidMessage: (reason) => {
1756
- this.deleteSession(connectedSession, { unhealthy: true });
1872
+ this.log?.error(`invalid message: ${reason}`, {
1873
+ ...connectedSession.loggingMetadata,
1874
+ transportMessage: msg
1875
+ });
1757
1876
  this.protocolError({
1758
1877
  type: ProtocolError.InvalidMessage,
1759
1878
  message: reason
1760
1879
  });
1880
+ this.deleteSession(connectedSession, { unhealthy: true });
1881
+ },
1882
+ onMessageSendFailure: (msg2, reason) => {
1883
+ this.log?.error(`failed to send message: ${reason}`, {
1884
+ ...connectedSession.loggingMetadata,
1885
+ transportMessage: msg2
1886
+ });
1887
+ this.protocolError({
1888
+ type: ProtocolError.MessageSendFailure,
1889
+ message: reason
1890
+ });
1891
+ this.deleteSession(connectedSession, { unhealthy: true });
1761
1892
  }
1762
1893
  });
1894
+ const res = connectedSession.sendBufferedMessages();
1895
+ if (!res.ok) {
1896
+ return;
1897
+ }
1763
1898
  this.updateSession(connectedSession);
1764
1899
  this.retryBudget.startRestoringBudget();
1765
1900
  }
@@ -1898,7 +2033,18 @@ var ClientTransport = class extends Transport {
1898
2033
  ...session.loggingMetadata,
1899
2034
  transportMessage: requestMsg
1900
2035
  });
1901
- session.sendHandshake(requestMsg);
2036
+ const res = session.sendHandshake(requestMsg);
2037
+ if (!res.ok) {
2038
+ this.log?.error(`failed to send handshake request: ${res.reason}`, {
2039
+ ...session.loggingMetadata,
2040
+ transportMessage: requestMsg
2041
+ });
2042
+ this.protocolError({
2043
+ type: ProtocolError.MessageSendFailure,
2044
+ message: res.reason
2045
+ });
2046
+ this.deleteSession(session, { unhealthy: true });
2047
+ }
1902
2048
  }
1903
2049
  close() {
1904
2050
  this.retryBudget.close();
@@ -1906,93 +2052,6 @@ var ClientTransport = class extends Transport {
1906
2052
  }
1907
2053
  };
1908
2054
 
1909
- // transport/connection.ts
1910
- var Connection = class {
1911
- id;
1912
- telemetry;
1913
- constructor() {
1914
- this.id = `conn-${generateId()}`;
1915
- }
1916
- get loggingMetadata() {
1917
- const metadata = { connId: this.id };
1918
- if (this.telemetry?.span.isRecording()) {
1919
- const spanContext = this.telemetry.span.spanContext();
1920
- metadata.telemetry = {
1921
- traceId: spanContext.traceId,
1922
- spanId: spanContext.spanId
1923
- };
1924
- }
1925
- return metadata;
1926
- }
1927
- // can't use event emitter because we need this to work in both node + browser
1928
- _dataListeners = /* @__PURE__ */ new Set();
1929
- _closeListeners = /* @__PURE__ */ new Set();
1930
- _errorListeners = /* @__PURE__ */ new Set();
1931
- get dataListeners() {
1932
- return [...this._dataListeners];
1933
- }
1934
- get closeListeners() {
1935
- return [...this._closeListeners];
1936
- }
1937
- get errorListeners() {
1938
- return [...this._errorListeners];
1939
- }
1940
- onData(msg) {
1941
- for (const cb of this.dataListeners) {
1942
- cb(msg);
1943
- }
1944
- }
1945
- onError(err) {
1946
- for (const cb of this.errorListeners) {
1947
- cb(err);
1948
- }
1949
- }
1950
- onClose() {
1951
- for (const cb of this.closeListeners) {
1952
- cb();
1953
- }
1954
- this.telemetry?.span.end();
1955
- }
1956
- /**
1957
- * Handle adding a callback for when a message is received.
1958
- * @param msg The message that was received.
1959
- */
1960
- addDataListener(cb) {
1961
- this._dataListeners.add(cb);
1962
- }
1963
- removeDataListener(cb) {
1964
- this._dataListeners.delete(cb);
1965
- }
1966
- /**
1967
- * Handle adding a callback for when the connection is closed.
1968
- * This should also be called if an error happens and after notifying all the error listeners.
1969
- * @param cb The callback to call when the connection is closed.
1970
- */
1971
- addCloseListener(cb) {
1972
- this._closeListeners.add(cb);
1973
- }
1974
- removeCloseListener(cb) {
1975
- this._closeListeners.delete(cb);
1976
- }
1977
- /**
1978
- * Handle adding a callback for when an error is received.
1979
- * This should only be used for this.logging errors, all cleanup
1980
- * should be delegated to addCloseListener.
1981
- *
1982
- * The implementer should take care such that the implemented
1983
- * connection will call both the close and error callbacks
1984
- * on an error.
1985
- *
1986
- * @param cb The callback to call when an error is received.
1987
- */
1988
- addErrorListener(cb) {
1989
- this._errorListeners.add(cb);
1990
- }
1991
- removeErrorListener(cb) {
1992
- this._errorListeners.delete(cb);
1993
- }
1994
- };
1995
-
1996
2055
  // transport/impls/ws/connection.ts
1997
2056
  var WS_HEALTHY_CLOSE_CODE = 1e3;
1998
2057
  var WebSocketConnection = class extends Connection {
@@ -2028,11 +2087,12 @@ var WebSocketConnection = class extends Connection {
2028
2087
  };
2029
2088
  }
2030
2089
  send(payload) {
2031
- if (this.ws.readyState !== this.ws.OPEN) {
2090
+ try {
2091
+ this.ws.send(payload);
2092
+ return true;
2093
+ } catch {
2032
2094
  return false;
2033
2095
  }
2034
- this.ws.send(payload);
2035
- return true;
2036
2096
  }
2037
2097
  close() {
2038
2098
  this.ws.close(WS_HEALTHY_CLOSE_CODE);