@replit/river 0.207.1 → 0.207.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 (56) hide show
  1. package/dist/adapter-f2b6e211.d.ts +46 -0
  2. package/dist/{chunk-7LMZNSVC.js → chunk-B7REV3ZV.js} +6 -5
  3. package/dist/{chunk-7LMZNSVC.js.map → chunk-B7REV3ZV.js.map} +1 -1
  4. package/dist/{chunk-QMAVXV4Z.js → chunk-BO7MFCO6.js} +1136 -132
  5. package/dist/chunk-BO7MFCO6.js.map +1 -0
  6. package/dist/{chunk-BCCZA7SX.js → chunk-QGPYCXV4.js} +2 -2
  7. package/dist/{chunk-BCCZA7SX.js.map → chunk-QGPYCXV4.js.map} +1 -1
  8. package/dist/codec/index.cjs +157 -23
  9. package/dist/codec/index.cjs.map +1 -1
  10. package/dist/codec/index.d.cts +5 -1
  11. package/dist/codec/index.d.ts +5 -1
  12. package/dist/codec/index.js +6 -20
  13. package/dist/codec/index.js.map +1 -1
  14. package/dist/{connection-933c87b2.d.ts → connection-06d72f2e.d.ts} +3 -2
  15. package/dist/index-02554794.d.ts +37 -0
  16. package/dist/logging/index.d.cts +2 -1
  17. package/dist/logging/index.d.ts +2 -1
  18. package/dist/{message-ffacb98a.d.ts → message-01c3e85a.d.ts} +1 -35
  19. package/dist/router/index.cjs +1 -1
  20. package/dist/router/index.cjs.map +1 -1
  21. package/dist/router/index.d.cts +6 -5
  22. package/dist/router/index.d.ts +6 -5
  23. package/dist/router/index.js +1 -1
  24. package/dist/{services-4cd29829.d.ts → services-87887bc5.d.ts} +16 -11
  25. package/dist/testUtil/index.cjs +992 -829
  26. package/dist/testUtil/index.cjs.map +1 -1
  27. package/dist/testUtil/index.d.cts +4 -3
  28. package/dist/testUtil/index.d.ts +4 -3
  29. package/dist/testUtil/index.js +18 -13
  30. package/dist/testUtil/index.js.map +1 -1
  31. package/dist/transport/impls/ws/client.cjs +293 -193
  32. package/dist/transport/impls/ws/client.cjs.map +1 -1
  33. package/dist/transport/impls/ws/client.d.cts +5 -4
  34. package/dist/transport/impls/ws/client.d.ts +5 -4
  35. package/dist/transport/impls/ws/client.js +5 -7
  36. package/dist/transport/impls/ws/client.js.map +1 -1
  37. package/dist/transport/impls/ws/server.cjs +230 -117
  38. package/dist/transport/impls/ws/server.cjs.map +1 -1
  39. package/dist/transport/impls/ws/server.d.cts +5 -4
  40. package/dist/transport/impls/ws/server.d.ts +5 -4
  41. package/dist/transport/impls/ws/server.js +5 -7
  42. package/dist/transport/impls/ws/server.js.map +1 -1
  43. package/dist/transport/index.cjs +408 -259
  44. package/dist/transport/index.cjs.map +1 -1
  45. package/dist/transport/index.d.cts +7 -6
  46. package/dist/transport/index.d.ts +7 -6
  47. package/dist/transport/index.js +4 -9
  48. package/package.json +1 -1
  49. package/dist/chunk-AJGIY2UB.js +0 -56
  50. package/dist/chunk-AJGIY2UB.js.map +0 -1
  51. package/dist/chunk-CRD3HDVN.js +0 -438
  52. package/dist/chunk-CRD3HDVN.js.map +0 -1
  53. package/dist/chunk-I27WBSMZ.js +0 -377
  54. package/dist/chunk-I27WBSMZ.js.map +0 -1
  55. package/dist/chunk-QMAVXV4Z.js.map +0 -1
  56. package/dist/types-3e5768ec.d.ts +0 -20
@@ -1,10 +1,11 @@
1
- import { C as ClientTransport, P as ProvidedClientTransportOptions } from '../../../services-4cd29829.js';
2
- import { T as TransportClientId } from '../../../message-ffacb98a.js';
3
- import { W as WebSocketConnection } from '../../../connection-933c87b2.js';
1
+ import { C as ClientTransport, P as ProvidedClientTransportOptions } from '../../../services-87887bc5.js';
2
+ import { T as TransportClientId } from '../../../message-01c3e85a.js';
3
+ import { W as WebSocketConnection } from '../../../connection-06d72f2e.js';
4
4
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
5
5
  import '@sinclair/typebox';
6
6
  import '@opentelemetry/api';
7
- import '../../../types-3e5768ec.js';
7
+ import '../../../index-02554794.js';
8
+ import '../../../adapter-f2b6e211.js';
8
9
 
9
10
  /**
10
11
  * A transport implementation that uses a WebSocket connection with automatic reconnection.
@@ -1,10 +1,11 @@
1
- import { C as ClientTransport, P as ProvidedClientTransportOptions } from '../../../services-4cd29829.js';
2
- import { T as TransportClientId } from '../../../message-ffacb98a.js';
3
- import { W as WebSocketConnection } from '../../../connection-933c87b2.js';
1
+ import { C as ClientTransport, P as ProvidedClientTransportOptions } from '../../../services-87887bc5.js';
2
+ import { T as TransportClientId } from '../../../message-01c3e85a.js';
3
+ import { W as WebSocketConnection } from '../../../connection-06d72f2e.js';
4
4
  import { W as WsLike } from '../../../wslike-e0b32dd5.js';
5
5
  import '@sinclair/typebox';
6
6
  import '@opentelemetry/api';
7
- import '../../../types-3e5768ec.js';
7
+ import '../../../index-02554794.js';
8
+ import '../../../adapter-f2b6e211.js';
8
9
 
9
10
  /**
10
11
  * A transport implementation that uses a WebSocket connection with automatic reconnection.
@@ -1,13 +1,11 @@
1
- import {
2
- ClientTransport
3
- } from "../../../chunk-CRD3HDVN.js";
4
1
  import {
5
2
  WebSocketConnection
6
- } from "../../../chunk-7LMZNSVC.js";
7
- import "../../../chunk-QMAVXV4Z.js";
8
- import "../../../chunk-BCCZA7SX.js";
3
+ } from "../../../chunk-B7REV3ZV.js";
4
+ import {
5
+ ClientTransport
6
+ } from "../../../chunk-BO7MFCO6.js";
7
+ import "../../../chunk-QGPYCXV4.js";
9
8
  import "../../../chunk-CC7RN7GI.js";
10
- import "../../../chunk-AJGIY2UB.js";
11
9
 
12
10
  // transport/impls/ws/client.ts
13
11
  var WebSocketClientTransport = class extends ClientTransport {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../transport/impls/ws/client.ts"],"sourcesContent":["import { ClientTransport } from '../../client';\nimport { TransportClientId } from '../../message';\nimport { ProvidedClientTransportOptions } from '../../options';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\n\n/**\n * A transport implementation that uses a WebSocket connection with automatic reconnection.\n * @class\n * @extends Transport\n */\nexport class WebSocketClientTransport extends ClientTransport<WebSocketConnection> {\n /**\n * A function that returns a Promise that resolves to a websocket URL.\n */\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike;\n\n /**\n * Creates a new WebSocketClientTransport instance.\n * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.\n * @param clientId The ID of the client using the transport. This should be unique per session.\n * @param serverId The ID of the server this transport is connecting to.\n * @param providedOptions An optional object containing configuration options for the transport.\n */\n constructor(\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike,\n clientId: TransportClientId,\n providedOptions?: ProvidedClientTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wsGetter = wsGetter;\n }\n\n async createNewOutgoingConnection(to: string) {\n this.log?.info(`establishing a new websocket to ${to}`, {\n clientId: this.clientId,\n connectedTo: to,\n });\n\n const ws = await this.wsGetter(to);\n\n await new Promise<void>((resolve, reject) => {\n if (ws.readyState === ws.OPEN) {\n resolve();\n\n return;\n }\n\n if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {\n reject(new Error('ws is closing or closed'));\n\n return;\n }\n\n ws.onopen = () => {\n resolve();\n };\n\n ws.onclose = (evt) => {\n reject(new Error(evt.reason));\n };\n\n ws.onerror = (err) => {\n reject(new Error(err.message));\n };\n });\n\n const conn = new WebSocketConnection(ws);\n this.log?.info(`raw websocket to ${to} ok`, {\n clientId: this.clientId,\n connectedTo: to,\n ...conn.loggingMetadata,\n });\n\n return conn;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAWO,IAAM,2BAAN,cAAuC,gBAAqC;AAAA;AAAA;AAAA;AAAA,EAIjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YACE,UACA,UACA,iBACA;AACA,UAAM,UAAU,eAAe;AAC/B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,4BAA4B,IAAY;AAC5C,SAAK,KAAK,KAAK,mCAAmC,EAAE,IAAI;AAAA,MACtD,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,IACf,CAAC;AAED,UAAM,KAAK,MAAM,KAAK,SAAS,EAAE;AAEjC,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,GAAG,eAAe,GAAG,MAAM;AAC7B,gBAAQ;AAER;AAAA,MACF;AAEA,UAAI,GAAG,eAAe,GAAG,WAAW,GAAG,eAAe,GAAG,QAAQ;AAC/D,eAAO,IAAI,MAAM,yBAAyB,CAAC;AAE3C;AAAA,MACF;AAEA,SAAG,SAAS,MAAM;AAChB,gBAAQ;AAAA,MACV;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,MAC9B;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,OAAO,CAAC;AAAA,MAC/B;AAAA,IACF,CAAC;AAED,UAAM,OAAO,IAAI,oBAAoB,EAAE;AACvC,SAAK,KAAK,KAAK,oBAAoB,EAAE,OAAO;AAAA,MAC1C,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,MACb,GAAG,KAAK;AAAA,IACV,CAAC;AAED,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../transport/impls/ws/client.ts"],"sourcesContent":["import { ClientTransport } from '../../client';\nimport { TransportClientId } from '../../message';\nimport { ProvidedClientTransportOptions } from '../../options';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\n\n/**\n * A transport implementation that uses a WebSocket connection with automatic reconnection.\n * @class\n * @extends Transport\n */\nexport class WebSocketClientTransport extends ClientTransport<WebSocketConnection> {\n /**\n * A function that returns a Promise that resolves to a websocket URL.\n */\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike;\n\n /**\n * Creates a new WebSocketClientTransport instance.\n * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.\n * @param clientId The ID of the client using the transport. This should be unique per session.\n * @param serverId The ID of the server this transport is connecting to.\n * @param providedOptions An optional object containing configuration options for the transport.\n */\n constructor(\n wsGetter: (to: TransportClientId) => Promise<WsLike> | WsLike,\n clientId: TransportClientId,\n providedOptions?: ProvidedClientTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wsGetter = wsGetter;\n }\n\n async createNewOutgoingConnection(to: string) {\n this.log?.info(`establishing a new websocket to ${to}`, {\n clientId: this.clientId,\n connectedTo: to,\n });\n\n const ws = await this.wsGetter(to);\n\n await new Promise<void>((resolve, reject) => {\n if (ws.readyState === ws.OPEN) {\n resolve();\n\n return;\n }\n\n if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {\n reject(new Error('ws is closing or closed'));\n\n return;\n }\n\n ws.onopen = () => {\n resolve();\n };\n\n ws.onclose = (evt) => {\n reject(new Error(evt.reason));\n };\n\n ws.onerror = (err) => {\n reject(new Error(err.message));\n };\n });\n\n const conn = new WebSocketConnection(ws);\n this.log?.info(`raw websocket to ${to} ok`, {\n clientId: this.clientId,\n connectedTo: to,\n ...conn.loggingMetadata,\n });\n\n return conn;\n }\n}\n"],"mappings":";;;;;;;;;;AAWO,IAAM,2BAAN,cAAuC,gBAAqC;AAAA;AAAA;AAAA;AAAA,EAIjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YACE,UACA,UACA,iBACA;AACA,UAAM,UAAU,eAAe;AAC/B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,4BAA4B,IAAY;AAC5C,SAAK,KAAK,KAAK,mCAAmC,EAAE,IAAI;AAAA,MACtD,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,IACf,CAAC;AAED,UAAM,KAAK,MAAM,KAAK,SAAS,EAAE;AAEjC,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,GAAG,eAAe,GAAG,MAAM;AAC7B,gBAAQ;AAER;AAAA,MACF;AAEA,UAAI,GAAG,eAAe,GAAG,WAAW,GAAG,eAAe,GAAG,QAAQ;AAC/D,eAAO,IAAI,MAAM,yBAAyB,CAAC;AAE3C;AAAA,MACF;AAEA,SAAG,SAAS,MAAM;AAChB,gBAAQ;AAAA,MACV;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,MAC9B;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,eAAO,IAAI,MAAM,IAAI,OAAO,CAAC;AAAA,MAC/B;AAAA,IACF,CAAC;AAED,UAAM,OAAO,IAAI,oBAAoB,EAAE;AACvC,SAAK,KAAK,KAAK,oBAAoB,EAAE,OAAO;AAAA,MAC1C,UAAU,KAAK;AAAA,MACf,aAAa;AAAA,MACb,GAAG,KAAK;AAAA,IACV,CAAC;AAED,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -153,11 +153,12 @@ var WebSocketConnection = class extends Connection {
153
153
  };
154
154
  }
155
155
  send(payload) {
156
- if (this.ws.readyState !== this.ws.OPEN) {
156
+ try {
157
+ this.ws.send(payload);
158
+ return true;
159
+ } catch {
157
160
  return false;
158
161
  }
159
- this.ws.send(payload);
160
- return true;
161
162
  }
162
163
  close() {
163
164
  this.ws.close(WS_HEALTHY_CLOSE_CODE);
@@ -314,23 +315,20 @@ var NaiveJsonCodec = {
314
315
  );
315
316
  },
316
317
  fromBuffer: (buff) => {
317
- try {
318
- const parsed = JSON.parse(
319
- decoder.decode(buff),
320
- function reviver(_key, val) {
321
- if (val?.$t) {
322
- return base64ToUint8Array(val.$t);
323
- } else {
324
- return val;
325
- }
318
+ const parsed = JSON.parse(
319
+ decoder.decode(buff),
320
+ function reviver(_key, val) {
321
+ if (val?.$t) {
322
+ return base64ToUint8Array(val.$t);
323
+ } else {
324
+ return val;
326
325
  }
327
- );
328
- if (typeof parsed === "object")
329
- return parsed;
330
- return null;
331
- } catch {
332
- return null;
326
+ }
327
+ );
328
+ if (typeof parsed !== "object" || parsed === null) {
329
+ throw new Error("unpacked msg is not an object");
333
330
  }
331
+ return parsed;
334
332
  }
335
333
  };
336
334
 
@@ -427,7 +425,8 @@ var ProtocolError = {
427
425
  RetriesExceeded: "conn_retry_exceeded",
428
426
  HandshakeFailed: "handshake_failed",
429
427
  MessageOrderingViolated: "message_ordering_violated",
430
- InvalidMessage: "invalid_message"
428
+ InvalidMessage: "invalid_message",
429
+ MessageSendFailure: "message_send_failure"
431
430
  };
432
431
  var EventDispatcher = class {
433
432
  eventListeners = {};
@@ -461,7 +460,6 @@ var EventDispatcher = class {
461
460
  };
462
461
 
463
462
  // transport/sessionStateMachine/common.ts
464
- var import_value = require("@sinclair/typebox/value");
465
463
  var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
466
464
  var StateMachineState = class {
467
465
  /*
@@ -521,34 +519,16 @@ var StateMachineState = class {
521
519
  var CommonSession = class extends StateMachineState {
522
520
  from;
523
521
  options;
522
+ codec;
524
523
  tracer;
525
524
  log;
526
- constructor({ from, options, log, tracer }) {
525
+ constructor({ from, options, log, tracer, codec }) {
527
526
  super();
528
527
  this.from = from;
529
528
  this.options = options;
530
529
  this.log = log;
531
530
  this.tracer = tracer;
532
- }
533
- parseMsg(msg) {
534
- const parsedMsg = this.options.codec.fromBuffer(msg);
535
- if (parsedMsg === null) {
536
- this.log?.error(
537
- `received malformed msg: ${Buffer.from(msg).toString("base64")}`,
538
- this.loggingMetadata
539
- );
540
- return null;
541
- }
542
- if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
543
- this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
544
- ...this.loggingMetadata,
545
- validationErrors: [
546
- ...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
547
- ]
548
- });
549
- return null;
550
- }
551
- return parsedMsg;
531
+ this.codec = codec;
552
532
  }
553
533
  };
554
534
  var IdentifiedSession = class extends CommonSession {
@@ -608,9 +588,6 @@ var IdentifiedSession = class extends CommonSession {
608
588
  return metadata;
609
589
  }
610
590
  constructMsg(partialMsg) {
611
- if (this._isConsumed) {
612
- throw new Error(ERR_CONSUMED);
613
- }
614
591
  const msg = {
615
592
  ...partialMsg,
616
593
  id: generateId(),
@@ -628,7 +605,10 @@ var IdentifiedSession = class extends CommonSession {
628
605
  send(msg) {
629
606
  const constructedMsg = this.constructMsg(msg);
630
607
  this.sendBuffer.push(constructedMsg);
631
- return constructedMsg.id;
608
+ return {
609
+ ok: true,
610
+ value: constructedMsg.id
611
+ };
632
612
  }
633
613
  _handleStateExit() {
634
614
  }
@@ -660,6 +640,23 @@ var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
660
640
  super._handleClose();
661
641
  }
662
642
  };
643
+ function sendMessage(conn, codec, msg) {
644
+ const buff = codec.toBuffer(msg);
645
+ if (!buff.ok) {
646
+ return buff;
647
+ }
648
+ const sent = conn.send(buff.value);
649
+ if (!sent) {
650
+ return {
651
+ ok: false,
652
+ reason: "failed to send message"
653
+ };
654
+ }
655
+ return {
656
+ ok: true,
657
+ value: msg.id
658
+ };
659
+ }
663
660
 
664
661
  // transport/sessionStateMachine/SessionConnecting.ts
665
662
  var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
@@ -712,8 +709,8 @@ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
712
709
  }
713
710
  }
714
711
  _handleClose() {
715
- this.bestEffortClose();
716
712
  super._handleClose();
713
+ this.bestEffortClose();
717
714
  }
718
715
  };
719
716
 
@@ -740,7 +737,7 @@ function coerceErrorString(err) {
740
737
  }
741
738
 
742
739
  // package.json
743
- var version = "0.207.1";
740
+ var version = "0.207.3";
744
741
 
745
742
  // tracing/index.ts
746
743
  function createSessionTelemetryInfo(tracer, sessionId, to, from, propagationCtx) {
@@ -804,18 +801,18 @@ var SessionWaitingForHandshake = class extends CommonSession {
804
801
  };
805
802
  }
806
803
  onHandshakeData = (msg) => {
807
- const parsedMsg = this.parseMsg(msg);
808
- if (parsedMsg === null) {
804
+ const parsedMsgRes = this.codec.fromBuffer(msg);
805
+ if (!parsedMsgRes.ok) {
809
806
  this.listeners.onInvalidHandshake(
810
- "could not parse message",
807
+ `could not parse handshake message: ${parsedMsgRes.reason}`,
811
808
  "MALFORMED_HANDSHAKE"
812
809
  );
813
810
  return;
814
811
  }
815
- this.listeners.onHandshake(parsedMsg);
812
+ this.listeners.onHandshake(parsedMsgRes.value);
816
813
  };
817
814
  sendHandshake(msg) {
818
- return this.conn.send(this.options.codec.toBuffer(msg));
815
+ return sendMessage(this.conn, this.codec, msg);
819
816
  }
820
817
  _handleStateExit() {
821
818
  this.conn.removeDataListener(this.onHandshakeData);
@@ -853,18 +850,18 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
853
850
  };
854
851
  }
855
852
  onHandshakeData = (msg) => {
856
- const parsedMsg = this.parseMsg(msg);
857
- if (parsedMsg === null) {
853
+ const parsedMsgRes = this.codec.fromBuffer(msg);
854
+ if (!parsedMsgRes.ok) {
858
855
  this.listeners.onInvalidHandshake(
859
- "could not parse message",
856
+ `could not parse handshake message: ${parsedMsgRes.reason}`,
860
857
  "MALFORMED_HANDSHAKE"
861
858
  );
862
859
  return;
863
860
  }
864
- this.listeners.onHandshake(parsedMsg);
861
+ this.listeners.onHandshake(parsedMsgRes.value);
865
862
  };
866
863
  sendHandshake(msg) {
867
- return this.conn.send(this.options.codec.toBuffer(msg));
864
+ return sendMessage(this.conn, this.codec, msg);
868
865
  }
869
866
  _handleStateExit() {
870
867
  super._handleStateExit();
@@ -889,12 +886,15 @@ var SessionConnected = class extends IdentifiedSession {
889
886
  conn;
890
887
  listeners;
891
888
  heartbeatHandle;
892
- heartbeatMisses = 0;
893
- isActivelyHeartbeating;
889
+ heartbeatMissTimeout;
890
+ isActivelyHeartbeating = false;
894
891
  updateBookkeeping(ack, seq) {
895
892
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
896
893
  this.ack = seq + 1;
897
- this.heartbeatMisses = 0;
894
+ if (this.heartbeatMissTimeout) {
895
+ clearTimeout(this.heartbeatMissTimeout);
896
+ }
897
+ this.startMissingHeartbeatTimeout();
898
898
  }
899
899
  assertSendOrdering(constructedMsg) {
900
900
  if (constructedMsg.seq > this.seqSent + 1) {
@@ -911,9 +911,13 @@ var SessionConnected = class extends IdentifiedSession {
911
911
  const constructedMsg = this.constructMsg(msg);
912
912
  this.assertSendOrdering(constructedMsg);
913
913
  this.sendBuffer.push(constructedMsg);
914
- this.conn.send(this.options.codec.toBuffer(constructedMsg));
914
+ const res = sendMessage(this.conn, this.codec, constructedMsg);
915
+ if (!res.ok) {
916
+ this.listeners.onMessageSendFailure(constructedMsg, res.reason);
917
+ return res;
918
+ }
915
919
  this.seqSent = constructedMsg.seq;
916
- return constructedMsg.id;
920
+ return res;
917
921
  }
918
922
  constructor(props) {
919
923
  super(props);
@@ -922,6 +926,8 @@ var SessionConnected = class extends IdentifiedSession {
922
926
  this.conn.addDataListener(this.onMessageData);
923
927
  this.conn.addCloseListener(this.listeners.onConnectionClosed);
924
928
  this.conn.addErrorListener(this.listeners.onConnectionErrored);
929
+ }
930
+ sendBufferedMessages() {
925
931
  if (this.sendBuffer.length > 0) {
926
932
  this.log?.info(
927
933
  `sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
@@ -929,30 +935,15 @@ var SessionConnected = class extends IdentifiedSession {
929
935
  );
930
936
  for (const msg of this.sendBuffer) {
931
937
  this.assertSendOrdering(msg);
932
- this.conn.send(this.options.codec.toBuffer(msg));
938
+ const res = sendMessage(this.conn, this.codec, msg);
939
+ if (!res.ok) {
940
+ this.listeners.onMessageSendFailure(msg, res.reason);
941
+ return res;
942
+ }
933
943
  this.seqSent = msg.seq;
934
944
  }
935
945
  }
936
- this.isActivelyHeartbeating = false;
937
- this.heartbeatHandle = setInterval(() => {
938
- const misses = this.heartbeatMisses;
939
- const missDuration = misses * this.options.heartbeatIntervalMs;
940
- if (misses >= this.options.heartbeatsUntilDead) {
941
- this.log?.info(
942
- `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
943
- this.loggingMetadata
944
- );
945
- this.telemetry.span.addEvent("closing connection due to inactivity");
946
- this.conn.close();
947
- clearInterval(this.heartbeatHandle);
948
- this.heartbeatHandle = void 0;
949
- return;
950
- }
951
- if (this.isActivelyHeartbeating) {
952
- this.sendHeartbeat();
953
- }
954
- this.heartbeatMisses++;
955
- }, this.options.heartbeatIntervalMs);
946
+ return { ok: true, value: void 0 };
956
947
  }
957
948
  get loggingMetadata() {
958
949
  return {
@@ -960,31 +951,46 @@ var SessionConnected = class extends IdentifiedSession {
960
951
  ...this.conn.loggingMetadata
961
952
  };
962
953
  }
954
+ startMissingHeartbeatTimeout() {
955
+ const maxMisses = this.options.heartbeatsUntilDead;
956
+ const missDuration = maxMisses * this.options.heartbeatIntervalMs;
957
+ this.heartbeatMissTimeout = setTimeout(() => {
958
+ this.log?.info(
959
+ `closing connection to ${this.to} due to inactivity (missed ${maxMisses} heartbeats which is ${missDuration}ms)`,
960
+ this.loggingMetadata
961
+ );
962
+ this.telemetry.span.addEvent(
963
+ "closing connection due to missing heartbeat"
964
+ );
965
+ this.conn.close();
966
+ }, missDuration);
967
+ }
963
968
  startActiveHeartbeat() {
964
969
  this.isActivelyHeartbeating = true;
970
+ this.heartbeatHandle = setInterval(() => {
971
+ this.sendHeartbeat();
972
+ }, this.options.heartbeatIntervalMs);
965
973
  }
966
974
  sendHeartbeat() {
967
975
  this.log?.debug("sending heartbeat", this.loggingMetadata);
968
- this.send({
976
+ const heartbeat = {
969
977
  streamId: "heartbeat",
970
978
  controlFlags: 1 /* AckBit */,
971
979
  payload: {
972
980
  type: "ACK"
973
981
  }
974
- });
975
- }
976
- closeConnection() {
977
- this.conn.removeDataListener(this.onMessageData);
978
- this.conn.removeCloseListener(this.listeners.onConnectionClosed);
979
- this.conn.removeErrorListener(this.listeners.onConnectionErrored);
980
- this.conn.close();
982
+ };
983
+ this.send(heartbeat);
981
984
  }
982
985
  onMessageData = (msg) => {
983
- const parsedMsg = this.parseMsg(msg);
984
- if (parsedMsg === null) {
985
- this.listeners.onInvalidMessage("could not parse message");
986
+ const parsedMsgRes = this.codec.fromBuffer(msg);
987
+ if (!parsedMsgRes.ok) {
988
+ this.listeners.onInvalidMessage(
989
+ `could not parse message: ${parsedMsgRes.reason}`
990
+ );
986
991
  return;
987
992
  }
993
+ const parsedMsg = parsedMsgRes.value;
988
994
  if (parsedMsg.seq !== this.ack) {
989
995
  if (parsedMsg.seq < this.ack) {
990
996
  this.log?.debug(
@@ -1005,7 +1011,7 @@ var SessionConnected = class extends IdentifiedSession {
1005
1011
  code: import_api3.SpanStatusCode.ERROR,
1006
1012
  message: reason
1007
1013
  });
1008
- this.closeConnection();
1014
+ this.conn.close();
1009
1015
  }
1010
1016
  return;
1011
1017
  }
@@ -1023,9 +1029,7 @@ var SessionConnected = class extends IdentifiedSession {
1023
1029
  transportMessage: parsedMsg
1024
1030
  });
1025
1031
  if (!this.isActivelyHeartbeating) {
1026
- void Promise.resolve().then(() => {
1027
- this.sendHeartbeat();
1028
- });
1032
+ this.sendHeartbeat();
1029
1033
  }
1030
1034
  };
1031
1035
  _handleStateExit() {
@@ -1037,6 +1041,10 @@ var SessionConnected = class extends IdentifiedSession {
1037
1041
  clearInterval(this.heartbeatHandle);
1038
1042
  this.heartbeatHandle = void 0;
1039
1043
  }
1044
+ if (this.heartbeatMissTimeout) {
1045
+ clearTimeout(this.heartbeatMissTimeout);
1046
+ this.heartbeatMissTimeout = void 0;
1047
+ }
1040
1048
  }
1041
1049
  _handleClose() {
1042
1050
  super._handleClose();
@@ -1068,6 +1076,47 @@ var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
1068
1076
  }
1069
1077
  };
1070
1078
 
1079
+ // codec/adapter.ts
1080
+ var import_value = require("@sinclair/typebox/value");
1081
+ var CodecMessageAdapter = class {
1082
+ constructor(codec) {
1083
+ this.codec = codec;
1084
+ }
1085
+ toBuffer(msg) {
1086
+ try {
1087
+ return {
1088
+ ok: true,
1089
+ value: this.codec.toBuffer(msg)
1090
+ };
1091
+ } catch (e) {
1092
+ return {
1093
+ ok: false,
1094
+ reason: coerceErrorString(e)
1095
+ };
1096
+ }
1097
+ }
1098
+ fromBuffer(buf) {
1099
+ try {
1100
+ const parsedMsg = this.codec.fromBuffer(buf);
1101
+ if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
1102
+ return {
1103
+ ok: false,
1104
+ reason: "transport message schema mismatch"
1105
+ };
1106
+ }
1107
+ return {
1108
+ ok: true,
1109
+ value: parsedMsg
1110
+ };
1111
+ } catch (e) {
1112
+ return {
1113
+ ok: false,
1114
+ reason: coerceErrorString(e)
1115
+ };
1116
+ }
1117
+ }
1118
+ };
1119
+
1071
1120
  // transport/sessionStateMachine/transitions.ts
1072
1121
  function inheritSharedSession(session) {
1073
1122
  return {
@@ -1082,7 +1131,8 @@ function inheritSharedSession(session) {
1082
1131
  options: session.options,
1083
1132
  log: session.log,
1084
1133
  tracer: session.tracer,
1085
- protocolVersion: session.protocolVersion
1134
+ protocolVersion: session.protocolVersion,
1135
+ codec: session.codec
1086
1136
  };
1087
1137
  }
1088
1138
  function inheritSharedSessionWithGrace(session) {
@@ -1111,7 +1161,8 @@ var SessionStateGraph = {
1111
1161
  options,
1112
1162
  protocolVersion,
1113
1163
  tracer,
1114
- log
1164
+ log,
1165
+ codec: new CodecMessageAdapter(options.codec)
1115
1166
  });
1116
1167
  session.log?.info(`session ${session.id} created in NoConnection state`, {
1117
1168
  ...session.loggingMetadata,
@@ -1126,7 +1177,8 @@ var SessionStateGraph = {
1126
1177
  from,
1127
1178
  options,
1128
1179
  tracer,
1129
- log
1180
+ log,
1181
+ codec: new CodecMessageAdapter(options.codec)
1130
1182
  });
1131
1183
  session.log?.info(`session created in WaitingForHandshake state`, {
1132
1184
  ...session.loggingMetadata,
@@ -1204,6 +1256,7 @@ var SessionStateGraph = {
1204
1256
  listeners,
1205
1257
  ...carriedState
1206
1258
  });
1259
+ session.startMissingHeartbeatTimeout();
1207
1260
  session.log?.info(
1208
1261
  `session ${session.id} transition from Handshaking to Connected`,
1209
1262
  {
@@ -1239,7 +1292,8 @@ var SessionStateGraph = {
1239
1292
  options,
1240
1293
  tracer: pendingSession.tracer,
1241
1294
  log: pendingSession.log,
1242
- protocolVersion
1295
+ protocolVersion,
1296
+ codec: new CodecMessageAdapter(options.codec)
1243
1297
  }
1244
1298
  );
1245
1299
  pendingSession._handleStateExit();
@@ -1249,6 +1303,7 @@ var SessionStateGraph = {
1249
1303
  listeners,
1250
1304
  ...carriedState
1251
1305
  });
1306
+ session.startMissingHeartbeatTimeout();
1252
1307
  conn.telemetry = createConnectionTelemetryInfo(
1253
1308
  session.tracer,
1254
1309
  conn,
@@ -1589,12 +1644,16 @@ var Transport = class {
1589
1644
  );
1590
1645
  }
1591
1646
  const sameSession = session.id === sessionId;
1592
- if (!sameSession) {
1647
+ if (!sameSession || session._isConsumed) {
1593
1648
  throw new Error(
1594
1649
  `session scope for ${sessionId} has ended (transition), can't send`
1595
1650
  );
1596
1651
  }
1597
- return session.send(msg);
1652
+ const res = session.send(msg);
1653
+ if (!res.ok) {
1654
+ throw new Error(res.reason);
1655
+ }
1656
+ return res.value;
1598
1657
  };
1599
1658
  }
1600
1659
  };
@@ -1714,17 +1773,28 @@ var ServerTransport = class extends Transport {
1714
1773
  message: reason
1715
1774
  });
1716
1775
  this.log?.warn(reason, metadata);
1717
- session.sendHandshake(
1718
- handshakeResponseMessage({
1719
- from: this.clientId,
1720
- to,
1721
- status: {
1722
- ok: false,
1723
- code,
1724
- reason
1725
- }
1726
- })
1727
- );
1776
+ const responseMsg = handshakeResponseMessage({
1777
+ from: this.clientId,
1778
+ to,
1779
+ status: {
1780
+ ok: false,
1781
+ code,
1782
+ reason
1783
+ }
1784
+ });
1785
+ const res = session.sendHandshake(responseMsg);
1786
+ if (!res.ok) {
1787
+ this.log?.error(`failed to send handshake response: ${res.reason}`, {
1788
+ ...session.loggingMetadata,
1789
+ transportMessage: responseMsg
1790
+ });
1791
+ this.protocolError({
1792
+ type: ProtocolError.MessageSendFailure,
1793
+ message: res.reason
1794
+ });
1795
+ this.deletePendingSession(session);
1796
+ return;
1797
+ }
1728
1798
  this.protocolError({
1729
1799
  type: ProtocolError.HandshakeFailed,
1730
1800
  code,
@@ -1908,7 +1978,20 @@ var ServerTransport = class extends Transport {
1908
1978
  sessionId
1909
1979
  }
1910
1980
  });
1911
- session.sendHandshake(responseMsg);
1981
+ const res = session.sendHandshake(responseMsg);
1982
+ if (!res.ok) {
1983
+ this.log?.error(`failed to send handshake response: ${res.reason}`, {
1984
+ ...session.loggingMetadata,
1985
+ transportMessage: responseMsg
1986
+ });
1987
+ this.protocolError({
1988
+ type: ProtocolError.MessageSendFailure,
1989
+ message: res.reason
1990
+ });
1991
+ this.deletePendingSession(session);
1992
+ return;
1993
+ }
1994
+ this.pendingSessions.delete(session);
1912
1995
  const connectedSession = ServerSessionStateGraph.transition.WaitingForHandshakeToConnected(
1913
1996
  session,
1914
1997
  // by this point oldSession is either no connection or we dont have an old session
@@ -1935,22 +2018,52 @@ var ServerTransport = class extends Transport {
1935
2018
  this.handleMsg(msg2);
1936
2019
  },
1937
2020
  onInvalidMessage: (reason) => {
2021
+ this.log?.error(`invalid message: ${reason}`, {
2022
+ ...connectedSession.loggingMetadata,
2023
+ transportMessage: msg
2024
+ });
1938
2025
  this.protocolError({
1939
2026
  type: ProtocolError.InvalidMessage,
1940
2027
  message: reason
1941
2028
  });
1942
2029
  this.deleteSession(connectedSession, { unhealthy: true });
2030
+ },
2031
+ onMessageSendFailure: (msg2, reason) => {
2032
+ this.log?.error(`failed to send message: ${reason}`, {
2033
+ ...connectedSession.loggingMetadata,
2034
+ transportMessage: msg2
2035
+ });
2036
+ this.protocolError({
2037
+ type: ProtocolError.MessageSendFailure,
2038
+ message: reason
2039
+ });
2040
+ this.deleteSession(connectedSession, { unhealthy: true });
1943
2041
  }
1944
2042
  },
1945
2043
  gotVersion
1946
2044
  );
2045
+ const bufferSendRes = connectedSession.sendBufferedMessages();
2046
+ if (!bufferSendRes.ok) {
2047
+ this.log?.error(
2048
+ `failed to send buffered messages: ${bufferSendRes.reason}`,
2049
+ {
2050
+ ...connectedSession.loggingMetadata,
2051
+ transportMessage: msg
2052
+ }
2053
+ );
2054
+ this.protocolError({
2055
+ type: ProtocolError.MessageSendFailure,
2056
+ message: bufferSendRes.reason
2057
+ });
2058
+ this.deleteSession(connectedSession, { unhealthy: true });
2059
+ return;
2060
+ }
1947
2061
  this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
1948
2062
  if (oldSession) {
1949
2063
  this.updateSession(connectedSession);
1950
2064
  } else {
1951
2065
  this.createSession(connectedSession);
1952
2066
  }
1953
- this.pendingSessions.delete(session);
1954
2067
  connectedSession.startActiveHeartbeat();
1955
2068
  }
1956
2069
  };