@replit/river 0.12.0 → 0.12.1

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 (46) hide show
  1. package/dist/{chunk-24O3BKZA.js → chunk-55XUAPC6.js} +1 -1
  2. package/dist/{chunk-IUDKWAOK.js → chunk-M6LY25P2.js} +1 -1
  3. package/dist/{chunk-ANGOKBE5.js → chunk-QEYN2Z6O.js} +63 -45
  4. package/dist/{chunk-4HOR4NUO.js → chunk-RDTTKCGV.js} +1 -1
  5. package/dist/{chunk-XOTIAXAH.js → chunk-TKINU53F.js} +1 -1
  6. package/dist/{chunk-WTOIOXB7.js → chunk-XFFS4UOD.js} +5 -3
  7. package/dist/{connection-2956a1c5.d.ts → connection-bf7811aa.d.ts} +1 -1
  8. package/dist/{connection-cd963ed5.d.ts → connection-d880aa4a.d.ts} +1 -1
  9. package/dist/{connection-aaea7c88.d.ts → connection-eb10d250.d.ts} +1 -1
  10. package/dist/{index-d91775d9.d.ts → index-0c0a69f6.d.ts} +9 -11
  11. package/dist/router/index.cjs +2 -1
  12. package/dist/router/index.d.cts +1 -1
  13. package/dist/router/index.d.ts +1 -1
  14. package/dist/router/index.js +2 -2
  15. package/dist/transport/impls/stdio/client.cjs +53 -35
  16. package/dist/transport/impls/stdio/client.d.cts +2 -2
  17. package/dist/transport/impls/stdio/client.d.ts +2 -2
  18. package/dist/transport/impls/stdio/client.js +3 -3
  19. package/dist/transport/impls/stdio/server.cjs +51 -29
  20. package/dist/transport/impls/stdio/server.d.cts +2 -2
  21. package/dist/transport/impls/stdio/server.d.ts +2 -2
  22. package/dist/transport/impls/stdio/server.js +3 -3
  23. package/dist/transport/impls/uds/client.cjs +53 -35
  24. package/dist/transport/impls/uds/client.d.cts +2 -2
  25. package/dist/transport/impls/uds/client.d.ts +2 -2
  26. package/dist/transport/impls/uds/client.js +3 -3
  27. package/dist/transport/impls/uds/server.cjs +51 -29
  28. package/dist/transport/impls/uds/server.d.cts +2 -2
  29. package/dist/transport/impls/uds/server.d.ts +2 -2
  30. package/dist/transport/impls/uds/server.js +3 -3
  31. package/dist/transport/impls/ws/client.cjs +59 -35
  32. package/dist/transport/impls/ws/client.d.cts +2 -2
  33. package/dist/transport/impls/ws/client.d.ts +2 -2
  34. package/dist/transport/impls/ws/client.js +9 -3
  35. package/dist/transport/impls/ws/server.cjs +51 -29
  36. package/dist/transport/impls/ws/server.d.cts +2 -2
  37. package/dist/transport/impls/ws/server.d.ts +2 -2
  38. package/dist/transport/impls/ws/server.js +3 -3
  39. package/dist/transport/index.cjs +67 -47
  40. package/dist/transport/index.d.cts +1 -1
  41. package/dist/transport/index.d.ts +1 -1
  42. package/dist/transport/index.js +2 -2
  43. package/dist/util/testHelpers.d.cts +1 -1
  44. package/dist/util/testHelpers.d.ts +1 -1
  45. package/dist/util/testHelpers.js +2 -2
  46. package/package.json +1 -1
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  StreamConnection
3
- } from "../../../chunk-IUDKWAOK.js";
3
+ } from "../../../chunk-M6LY25P2.js";
4
4
  import "../../../chunk-5IZ2UHWV.js";
5
5
  import "../../../chunk-IIBVKYDB.js";
6
6
  import {
7
7
  ClientTransport
8
- } from "../../../chunk-ANGOKBE5.js";
8
+ } from "../../../chunk-QEYN2Z6O.js";
9
9
  import "../../../chunk-GZ7HCLLM.js";
10
- import "../../../chunk-WTOIOXB7.js";
10
+ import "../../../chunk-XFFS4UOD.js";
11
11
  import {
12
12
  log
13
13
  } from "../../../chunk-H4BYJELI.js";
@@ -51,7 +51,8 @@ var ControlMessageCloseSchema = import_typebox.Type.Object({
51
51
  var PROTOCOL_VERSION = "v1";
52
52
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
53
53
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
54
- protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION)
54
+ protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION),
55
+ instanceId: import_typebox.Type.String()
55
56
  });
56
57
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
57
58
  type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
@@ -144,9 +145,9 @@ var Connection = class {
144
145
  this.debugId = `conn-${unsafeId()}`;
145
146
  }
146
147
  };
147
- var HEARTBEAT_INTERVAL_MS = 250;
148
- var HEARTBEATS_TILL_DEAD = 4;
149
- var SESSION_DISCONNECT_GRACE_MS = 3e3;
148
+ var HEARTBEAT_INTERVAL_MS = 1e3;
149
+ var HEARTBEATS_TILL_DEAD = 2;
150
+ var SESSION_DISCONNECT_GRACE_MS = 5e3;
150
151
  var Session = class {
151
152
  codec;
152
153
  /**
@@ -229,11 +230,13 @@ var Session = class {
229
230
  return fullMsg.id;
230
231
  }
231
232
  sendHeartbeat() {
232
- if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD && this.connection) {
233
- log?.info(
234
- `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
235
- );
236
- this.halfCloseConnection();
233
+ if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD) {
234
+ if (this.connection) {
235
+ log?.info(
236
+ `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
237
+ );
238
+ this.halfCloseConnection();
239
+ }
237
240
  return;
238
241
  }
239
242
  this.send(
@@ -270,7 +273,6 @@ var Session = class {
270
273
  }
271
274
  }
272
275
  updateBookkeeping(ack, seq) {
273
- this.heartbeatMisses = 0;
274
276
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
275
277
  this.ack = seq + 1;
276
278
  }
@@ -302,6 +304,7 @@ var Session = class {
302
304
  }, SESSION_DISCONNECT_GRACE_MS);
303
305
  }
304
306
  cancelGrace() {
307
+ this.heartbeatMisses = 0;
305
308
  clearTimeout(this.disconnectionGrace);
306
309
  }
307
310
  get connected() {
@@ -409,6 +412,13 @@ var defaultTransportOptions = {
409
412
  codec: NaiveJsonCodec
410
413
  };
411
414
  var Transport = class {
415
+ /**
416
+ * Unique per instance of the transport.
417
+ * This allows us to distinguish reconnects to different
418
+ * transports.
419
+ */
420
+ instanceId = (0, import_nanoid3.nanoid)();
421
+ connectedInstanceIds = /* @__PURE__ */ new Map();
412
422
  /**
413
423
  * A flag indicating whether the transport has been destroyed.
414
424
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -470,12 +480,23 @@ var Transport = class {
470
480
  * and we know the identity of the connected client.
471
481
  * @param conn The connection object.
472
482
  */
473
- onConnect(conn, connectedTo) {
483
+ onConnect(conn, connectedTo, instanceId) {
474
484
  this.eventDispatcher.dispatchEvent("connectionStatus", {
475
485
  status: "connect",
476
486
  conn
477
487
  });
478
- const session = this.sessions.get(connectedTo);
488
+ let session = this.sessions.get(connectedTo);
489
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
490
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
491
+ log?.debug(
492
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
493
+ );
494
+ session.resetBufferedMessages();
495
+ session.closeStaleConnection();
496
+ this.deleteSession(session);
497
+ session = void 0;
498
+ }
499
+ this.connectedInstanceIds.set(connectedTo, instanceId);
479
500
  if (session === void 0) {
480
501
  const newSession = this.createSession(connectedTo, conn);
481
502
  log?.info(
@@ -541,11 +562,13 @@ var Transport = class {
541
562
  const parsedMsg = this.codec.fromBuffer(msg);
542
563
  if (parsedMsg === null) {
543
564
  const decodedBuffer = new TextDecoder().decode(msg);
544
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
565
+ log?.error(
566
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
567
+ );
545
568
  return null;
546
569
  }
547
570
  if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
548
- log?.warn(
571
+ log?.error(
549
572
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
550
573
  parsedMsg
551
574
  )}`
@@ -564,9 +587,6 @@ var Transport = class {
564
587
  * @param msg The received message.
565
588
  */
566
589
  handleMsg(msg) {
567
- if (!msg) {
568
- return;
569
- }
570
590
  const session = this.sessionByClientId(msg.from);
571
591
  session.cancelGrace();
572
592
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -663,14 +683,6 @@ var Transport = class {
663
683
  }
664
684
  };
665
685
  var ServerTransport = class extends Transport {
666
- /**
667
- * Unique per instance of server transport.
668
- * This allows us to distinguish reconnects to different
669
- * server transports at the same reachable address and signal
670
- * the appropriate session disconnect back to the client at the
671
- * boot stage.
672
- */
673
- instanceId = (0, import_nanoid3.nanoid)();
674
686
  constructor(clientId, providedOptions) {
675
687
  super(clientId, providedOptions);
676
688
  log?.info(
@@ -685,7 +697,14 @@ var ServerTransport = class extends Transport {
685
697
  (establishedSession) => {
686
698
  session = establishedSession;
687
699
  conn.removeDataListener(bootHandler);
688
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
700
+ conn.addDataListener((data) => {
701
+ const parsed = this.parseMsg(data);
702
+ if (!parsed) {
703
+ conn.close();
704
+ return;
705
+ }
706
+ this.handleMsg(parsed);
707
+ });
689
708
  }
690
709
  );
691
710
  conn.addDataListener(bootHandler);
@@ -708,8 +727,10 @@ var ServerTransport = class extends Transport {
708
727
  receiveWithBootSequence(conn, sessionCb) {
709
728
  const bootHandler = (data) => {
710
729
  const parsed = this.parseMsg(data);
711
- if (!parsed)
730
+ if (!parsed) {
731
+ conn.close();
712
732
  return;
733
+ }
713
734
  if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
714
735
  const responseMsg2 = bootResponseMessage(
715
736
  this.clientId,
@@ -725,8 +746,9 @@ var ServerTransport = class extends Transport {
725
746
  );
726
747
  return;
727
748
  }
749
+ const instanceId = parsed.payload.instanceId;
728
750
  log?.debug(
729
- `${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
751
+ `${this.clientId} -- handshake from ${parsed.from} ok (instance id: ${instanceId}), responding with handshake success`
730
752
  );
731
753
  const responseMsg = bootResponseMessage(
732
754
  this.clientId,
@@ -735,7 +757,7 @@ var ServerTransport = class extends Transport {
735
757
  true
736
758
  );
737
759
  conn.send(this.codec.toBuffer(responseMsg));
738
- sessionCb(this.onConnect(conn, parsed.from));
760
+ sessionCb(this.onConnect(conn, parsed.from, instanceId));
739
761
  };
740
762
  return bootHandler;
741
763
  }
@@ -1,5 +1,5 @@
1
- import { S as ServerTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
2
- import { S as StreamConnection } from '../../../connection-2956a1c5.js';
1
+ import { S as ServerTransport, b as TransportClientId, c as TransportOptions } from '../../../index-0c0a69f6.js';
2
+ import { S as StreamConnection } from '../../../connection-bf7811aa.js';
3
3
  import '../../../types-3e5768ec.js';
4
4
  import '@sinclair/typebox';
5
5
  import '../../../messageFraming-b200ef25.js';
@@ -1,5 +1,5 @@
1
- import { S as ServerTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
2
- import { S as StreamConnection } from '../../../connection-2956a1c5.js';
1
+ import { S as ServerTransport, b as TransportClientId, c as TransportOptions } from '../../../index-0c0a69f6.js';
2
+ import { S as StreamConnection } from '../../../connection-bf7811aa.js';
3
3
  import '../../../types-3e5768ec.js';
4
4
  import '@sinclair/typebox';
5
5
  import '../../../messageFraming-b200ef25.js';
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  StreamConnection
3
- } from "../../../chunk-IUDKWAOK.js";
3
+ } from "../../../chunk-M6LY25P2.js";
4
4
  import "../../../chunk-5IZ2UHWV.js";
5
5
  import "../../../chunk-IIBVKYDB.js";
6
6
  import {
7
7
  ServerTransport
8
- } from "../../../chunk-ANGOKBE5.js";
8
+ } from "../../../chunk-QEYN2Z6O.js";
9
9
  import "../../../chunk-GZ7HCLLM.js";
10
- import "../../../chunk-WTOIOXB7.js";
10
+ import "../../../chunk-XFFS4UOD.js";
11
11
  import "../../../chunk-H4BYJELI.js";
12
12
 
13
13
  // transport/impls/stdio/server.ts
@@ -55,7 +55,8 @@ var ControlMessageCloseSchema = import_typebox.Type.Object({
55
55
  var PROTOCOL_VERSION = "v1";
56
56
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
57
57
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
58
- protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION)
58
+ protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION),
59
+ instanceId: import_typebox.Type.String()
59
60
  });
60
61
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
61
62
  type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
@@ -79,7 +80,7 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
79
80
  var OpaqueTransportMessageSchema = TransportMessageSchema(
80
81
  import_typebox.Type.Unknown()
81
82
  );
82
- function bootRequestMessage(from, to) {
83
+ function bootRequestMessage(from, to, instanceId) {
83
84
  return {
84
85
  id: (0, import_nanoid.nanoid)(),
85
86
  from,
@@ -90,7 +91,8 @@ function bootRequestMessage(from, to) {
90
91
  controlFlags: 0,
91
92
  payload: {
92
93
  type: "HANDSHAKE_REQ",
93
- protocolVersion: PROTOCOL_VERSION
94
+ protocolVersion: PROTOCOL_VERSION,
95
+ instanceId
94
96
  }
95
97
  };
96
98
  }
@@ -107,9 +109,9 @@ var Connection = class {
107
109
  this.debugId = `conn-${unsafeId()}`;
108
110
  }
109
111
  };
110
- var HEARTBEAT_INTERVAL_MS = 250;
111
- var HEARTBEATS_TILL_DEAD = 4;
112
- var SESSION_DISCONNECT_GRACE_MS = 3e3;
112
+ var HEARTBEAT_INTERVAL_MS = 1e3;
113
+ var HEARTBEATS_TILL_DEAD = 2;
114
+ var SESSION_DISCONNECT_GRACE_MS = 5e3;
113
115
  var Session = class {
114
116
  codec;
115
117
  /**
@@ -192,11 +194,13 @@ var Session = class {
192
194
  return fullMsg.id;
193
195
  }
194
196
  sendHeartbeat() {
195
- if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD && this.connection) {
196
- log?.info(
197
- `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
198
- );
199
- this.halfCloseConnection();
197
+ if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD) {
198
+ if (this.connection) {
199
+ log?.info(
200
+ `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
201
+ );
202
+ this.halfCloseConnection();
203
+ }
200
204
  return;
201
205
  }
202
206
  this.send(
@@ -233,7 +237,6 @@ var Session = class {
233
237
  }
234
238
  }
235
239
  updateBookkeeping(ack, seq) {
236
- this.heartbeatMisses = 0;
237
240
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
238
241
  this.ack = seq + 1;
239
242
  }
@@ -265,6 +268,7 @@ var Session = class {
265
268
  }, SESSION_DISCONNECT_GRACE_MS);
266
269
  }
267
270
  cancelGrace() {
271
+ this.heartbeatMisses = 0;
268
272
  clearTimeout(this.disconnectionGrace);
269
273
  }
270
274
  get connected() {
@@ -496,6 +500,13 @@ var defaultTransportOptions = {
496
500
  codec: NaiveJsonCodec
497
501
  };
498
502
  var Transport = class {
503
+ /**
504
+ * Unique per instance of the transport.
505
+ * This allows us to distinguish reconnects to different
506
+ * transports.
507
+ */
508
+ instanceId = (0, import_nanoid3.nanoid)();
509
+ connectedInstanceIds = /* @__PURE__ */ new Map();
499
510
  /**
500
511
  * A flag indicating whether the transport has been destroyed.
501
512
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -557,12 +568,23 @@ var Transport = class {
557
568
  * and we know the identity of the connected client.
558
569
  * @param conn The connection object.
559
570
  */
560
- onConnect(conn, connectedTo) {
571
+ onConnect(conn, connectedTo, instanceId) {
561
572
  this.eventDispatcher.dispatchEvent("connectionStatus", {
562
573
  status: "connect",
563
574
  conn
564
575
  });
565
- const session = this.sessions.get(connectedTo);
576
+ let session = this.sessions.get(connectedTo);
577
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
578
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
579
+ log?.debug(
580
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
581
+ );
582
+ session.resetBufferedMessages();
583
+ session.closeStaleConnection();
584
+ this.deleteSession(session);
585
+ session = void 0;
586
+ }
587
+ this.connectedInstanceIds.set(connectedTo, instanceId);
566
588
  if (session === void 0) {
567
589
  const newSession = this.createSession(connectedTo, conn);
568
590
  log?.info(
@@ -628,11 +650,13 @@ var Transport = class {
628
650
  const parsedMsg = this.codec.fromBuffer(msg);
629
651
  if (parsedMsg === null) {
630
652
  const decodedBuffer = new TextDecoder().decode(msg);
631
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
653
+ log?.error(
654
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
655
+ );
632
656
  return null;
633
657
  }
634
658
  if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
635
- log?.warn(
659
+ log?.error(
636
660
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
637
661
  parsedMsg
638
662
  )}`
@@ -651,9 +675,6 @@ var Transport = class {
651
675
  * @param msg The received message.
652
676
  */
653
677
  handleMsg(msg) {
654
- if (!msg) {
655
- return;
656
- }
657
678
  const session = this.sessionByClientId(msg.from);
658
679
  session.cancelGrace();
659
680
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -755,7 +776,6 @@ var ClientTransport = class extends Transport {
755
776
  */
756
777
  inflightConnectionPromises;
757
778
  tryReconnecting = true;
758
- serverInstanceIds = /* @__PURE__ */ new Map();
759
779
  constructor(clientId, providedOptions) {
760
780
  super(clientId, providedOptions);
761
781
  this.inflightConnectionPromises = /* @__PURE__ */ new Map();
@@ -763,7 +783,14 @@ var ClientTransport = class extends Transport {
763
783
  handleConnection(conn, to) {
764
784
  const bootHandler = this.receiveWithBootSequence(conn, () => {
765
785
  conn.removeDataListener(bootHandler);
766
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
786
+ conn.addDataListener((data) => {
787
+ const parsed = this.parseMsg(data);
788
+ if (!parsed) {
789
+ conn.close();
790
+ return;
791
+ }
792
+ this.handleMsg(parsed);
793
+ });
767
794
  });
768
795
  conn.addDataListener(bootHandler);
769
796
  conn.addCloseListener(() => {
@@ -795,7 +822,7 @@ var ClientTransport = class extends Transport {
795
822
  try {
796
823
  const conn = await reconnectPromise;
797
824
  this.state = "open";
798
- const requestMsg = bootRequestMessage(this.clientId, to);
825
+ const requestMsg = bootRequestMessage(this.clientId, to, this.instanceId);
799
826
  log?.debug(`${this.clientId} -- sending boot handshake to ${to}`);
800
827
  conn.send(this.codec.toBuffer(requestMsg));
801
828
  } catch (error) {
@@ -818,8 +845,10 @@ var ClientTransport = class extends Transport {
818
845
  receiveWithBootSequence(conn, sessionCb) {
819
846
  const bootHandler = (data) => {
820
847
  const parsed = this.parseMsg(data);
821
- if (!parsed)
848
+ if (!parsed) {
849
+ conn.close();
822
850
  return;
851
+ }
823
852
  if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
824
853
  log?.warn(
825
854
  `${this.clientId} -- received invalid handshake resp: ${JSON.stringify(parsed)}`
@@ -834,22 +863,11 @@ var ClientTransport = class extends Transport {
834
863
  );
835
864
  return;
836
865
  }
837
- const oldSession = this.sessions.get(parsed.from);
838
866
  const serverInstanceId = parsed.payload.status.instanceId;
839
- const lastServerInstanceId = this.serverInstanceIds.get(parsed.from);
840
- if (oldSession && lastServerInstanceId !== serverInstanceId && lastServerInstanceId !== void 0) {
841
- log?.debug(
842
- `${this.clientId} -- handshake from ${parsed.from} has different server instance (got: ${serverInstanceId}, last connected to: ${lastServerInstanceId}), starting a new session`
843
- );
844
- oldSession.resetBufferedMessages();
845
- oldSession.closeStaleConnection();
846
- this.deleteSession(oldSession);
847
- }
848
867
  log?.debug(
849
868
  `${this.clientId} -- handshake from ${parsed.from} ok (server instance: ${serverInstanceId})`
850
869
  );
851
- this.serverInstanceIds.set(parsed.from, serverInstanceId);
852
- sessionCb(this.onConnect(conn, parsed.from));
870
+ sessionCb(this.onConnect(conn, parsed.from, serverInstanceId));
853
871
  };
854
872
  return bootHandler;
855
873
  }
@@ -1,5 +1,5 @@
1
- import { a as ClientTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
2
- import { U as UdsConnection } from '../../../connection-cd963ed5.js';
1
+ import { a as ClientTransport, b as TransportClientId, c as TransportOptions } from '../../../index-0c0a69f6.js';
2
+ import { U as UdsConnection } from '../../../connection-d880aa4a.js';
3
3
  import '../../../types-3e5768ec.js';
4
4
  import '@sinclair/typebox';
5
5
  import 'node:net';
@@ -1,5 +1,5 @@
1
- import { a as ClientTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
2
- import { U as UdsConnection } from '../../../connection-cd963ed5.js';
1
+ import { a as ClientTransport, b as TransportClientId, c as TransportOptions } from '../../../index-0c0a69f6.js';
2
+ import { U as UdsConnection } from '../../../connection-d880aa4a.js';
3
3
  import '../../../types-3e5768ec.js';
4
4
  import '@sinclair/typebox';
5
5
  import 'node:net';
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  UdsConnection
3
- } from "../../../chunk-XOTIAXAH.js";
3
+ } from "../../../chunk-TKINU53F.js";
4
4
  import "../../../chunk-IIBVKYDB.js";
5
5
  import {
6
6
  ClientTransport
7
- } from "../../../chunk-ANGOKBE5.js";
7
+ } from "../../../chunk-QEYN2Z6O.js";
8
8
  import "../../../chunk-GZ7HCLLM.js";
9
- import "../../../chunk-WTOIOXB7.js";
9
+ import "../../../chunk-XFFS4UOD.js";
10
10
  import {
11
11
  log
12
12
  } from "../../../chunk-H4BYJELI.js";
@@ -54,7 +54,8 @@ var ControlMessageCloseSchema = import_typebox.Type.Object({
54
54
  var PROTOCOL_VERSION = "v1";
55
55
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
56
56
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
57
- protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION)
57
+ protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION),
58
+ instanceId: import_typebox.Type.String()
58
59
  });
59
60
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
60
61
  type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
@@ -144,9 +145,9 @@ var Connection = class {
144
145
  this.debugId = `conn-${unsafeId()}`;
145
146
  }
146
147
  };
147
- var HEARTBEAT_INTERVAL_MS = 250;
148
- var HEARTBEATS_TILL_DEAD = 4;
149
- var SESSION_DISCONNECT_GRACE_MS = 3e3;
148
+ var HEARTBEAT_INTERVAL_MS = 1e3;
149
+ var HEARTBEATS_TILL_DEAD = 2;
150
+ var SESSION_DISCONNECT_GRACE_MS = 5e3;
150
151
  var Session = class {
151
152
  codec;
152
153
  /**
@@ -229,11 +230,13 @@ var Session = class {
229
230
  return fullMsg.id;
230
231
  }
231
232
  sendHeartbeat() {
232
- if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD && this.connection) {
233
- log?.info(
234
- `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
235
- );
236
- this.halfCloseConnection();
233
+ if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD) {
234
+ if (this.connection) {
235
+ log?.info(
236
+ `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
237
+ );
238
+ this.halfCloseConnection();
239
+ }
237
240
  return;
238
241
  }
239
242
  this.send(
@@ -270,7 +273,6 @@ var Session = class {
270
273
  }
271
274
  }
272
275
  updateBookkeeping(ack, seq) {
273
- this.heartbeatMisses = 0;
274
276
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
275
277
  this.ack = seq + 1;
276
278
  }
@@ -302,6 +304,7 @@ var Session = class {
302
304
  }, SESSION_DISCONNECT_GRACE_MS);
303
305
  }
304
306
  cancelGrace() {
307
+ this.heartbeatMisses = 0;
305
308
  clearTimeout(this.disconnectionGrace);
306
309
  }
307
310
  get connected() {
@@ -409,6 +412,13 @@ var defaultTransportOptions = {
409
412
  codec: NaiveJsonCodec
410
413
  };
411
414
  var Transport = class {
415
+ /**
416
+ * Unique per instance of the transport.
417
+ * This allows us to distinguish reconnects to different
418
+ * transports.
419
+ */
420
+ instanceId = (0, import_nanoid3.nanoid)();
421
+ connectedInstanceIds = /* @__PURE__ */ new Map();
412
422
  /**
413
423
  * A flag indicating whether the transport has been destroyed.
414
424
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -470,12 +480,23 @@ var Transport = class {
470
480
  * and we know the identity of the connected client.
471
481
  * @param conn The connection object.
472
482
  */
473
- onConnect(conn, connectedTo) {
483
+ onConnect(conn, connectedTo, instanceId) {
474
484
  this.eventDispatcher.dispatchEvent("connectionStatus", {
475
485
  status: "connect",
476
486
  conn
477
487
  });
478
- const session = this.sessions.get(connectedTo);
488
+ let session = this.sessions.get(connectedTo);
489
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
490
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
491
+ log?.debug(
492
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
493
+ );
494
+ session.resetBufferedMessages();
495
+ session.closeStaleConnection();
496
+ this.deleteSession(session);
497
+ session = void 0;
498
+ }
499
+ this.connectedInstanceIds.set(connectedTo, instanceId);
479
500
  if (session === void 0) {
480
501
  const newSession = this.createSession(connectedTo, conn);
481
502
  log?.info(
@@ -541,11 +562,13 @@ var Transport = class {
541
562
  const parsedMsg = this.codec.fromBuffer(msg);
542
563
  if (parsedMsg === null) {
543
564
  const decodedBuffer = new TextDecoder().decode(msg);
544
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
565
+ log?.error(
566
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
567
+ );
545
568
  return null;
546
569
  }
547
570
  if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
548
- log?.warn(
571
+ log?.error(
549
572
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
550
573
  parsedMsg
551
574
  )}`
@@ -564,9 +587,6 @@ var Transport = class {
564
587
  * @param msg The received message.
565
588
  */
566
589
  handleMsg(msg) {
567
- if (!msg) {
568
- return;
569
- }
570
590
  const session = this.sessionByClientId(msg.from);
571
591
  session.cancelGrace();
572
592
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -663,14 +683,6 @@ var Transport = class {
663
683
  }
664
684
  };
665
685
  var ServerTransport = class extends Transport {
666
- /**
667
- * Unique per instance of server transport.
668
- * This allows us to distinguish reconnects to different
669
- * server transports at the same reachable address and signal
670
- * the appropriate session disconnect back to the client at the
671
- * boot stage.
672
- */
673
- instanceId = (0, import_nanoid3.nanoid)();
674
686
  constructor(clientId, providedOptions) {
675
687
  super(clientId, providedOptions);
676
688
  log?.info(
@@ -685,7 +697,14 @@ var ServerTransport = class extends Transport {
685
697
  (establishedSession) => {
686
698
  session = establishedSession;
687
699
  conn.removeDataListener(bootHandler);
688
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
700
+ conn.addDataListener((data) => {
701
+ const parsed = this.parseMsg(data);
702
+ if (!parsed) {
703
+ conn.close();
704
+ return;
705
+ }
706
+ this.handleMsg(parsed);
707
+ });
689
708
  }
690
709
  );
691
710
  conn.addDataListener(bootHandler);
@@ -708,8 +727,10 @@ var ServerTransport = class extends Transport {
708
727
  receiveWithBootSequence(conn, sessionCb) {
709
728
  const bootHandler = (data) => {
710
729
  const parsed = this.parseMsg(data);
711
- if (!parsed)
730
+ if (!parsed) {
731
+ conn.close();
712
732
  return;
733
+ }
713
734
  if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
714
735
  const responseMsg2 = bootResponseMessage(
715
736
  this.clientId,
@@ -725,8 +746,9 @@ var ServerTransport = class extends Transport {
725
746
  );
726
747
  return;
727
748
  }
749
+ const instanceId = parsed.payload.instanceId;
728
750
  log?.debug(
729
- `${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
751
+ `${this.clientId} -- handshake from ${parsed.from} ok (instance id: ${instanceId}), responding with handshake success`
730
752
  );
731
753
  const responseMsg = bootResponseMessage(
732
754
  this.clientId,
@@ -735,7 +757,7 @@ var ServerTransport = class extends Transport {
735
757
  true
736
758
  );
737
759
  conn.send(this.codec.toBuffer(responseMsg));
738
- sessionCb(this.onConnect(conn, parsed.from));
760
+ sessionCb(this.onConnect(conn, parsed.from, instanceId));
739
761
  };
740
762
  return bootHandler;
741
763
  }
@@ -1,6 +1,6 @@
1
1
  import { Server, Socket } from 'node:net';
2
- import { S as ServerTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
3
- import { U as UdsConnection } from '../../../connection-cd963ed5.js';
2
+ import { S as ServerTransport, b as TransportClientId, c as TransportOptions } from '../../../index-0c0a69f6.js';
3
+ import { U as UdsConnection } from '../../../connection-d880aa4a.js';
4
4
  import '../../../types-3e5768ec.js';
5
5
  import '@sinclair/typebox';
6
6
  import '../../../messageFraming-b200ef25.js';