@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
@@ -3,7 +3,7 @@ import {
3
3
  coerceErrorString,
4
4
  isStreamClose,
5
5
  isStreamOpen
6
- } from "./chunk-WTOIOXB7.js";
6
+ } from "./chunk-XFFS4UOD.js";
7
7
  import {
8
8
  log
9
9
  } from "./chunk-H4BYJELI.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-IIBVKYDB.js";
4
4
  import {
5
5
  Connection
6
- } from "./chunk-ANGOKBE5.js";
6
+ } from "./chunk-QEYN2Z6O.js";
7
7
 
8
8
  // transport/impls/stdio/connection.ts
9
9
  var StreamConnection = class extends Connection {
@@ -10,7 +10,7 @@ import {
10
10
  bootResponseMessage,
11
11
  coerceErrorString,
12
12
  isAck
13
- } from "./chunk-WTOIOXB7.js";
13
+ } from "./chunk-XFFS4UOD.js";
14
14
  import {
15
15
  log
16
16
  } from "./chunk-H4BYJELI.js";
@@ -53,9 +53,9 @@ var Connection = class {
53
53
  this.debugId = `conn-${unsafeId()}`;
54
54
  }
55
55
  };
56
- var HEARTBEAT_INTERVAL_MS = 250;
57
- var HEARTBEATS_TILL_DEAD = 4;
58
- var SESSION_DISCONNECT_GRACE_MS = 3e3;
56
+ var HEARTBEAT_INTERVAL_MS = 1e3;
57
+ var HEARTBEATS_TILL_DEAD = 2;
58
+ var SESSION_DISCONNECT_GRACE_MS = 5e3;
59
59
  var Session = class {
60
60
  codec;
61
61
  /**
@@ -138,11 +138,13 @@ var Session = class {
138
138
  return fullMsg.id;
139
139
  }
140
140
  sendHeartbeat() {
141
- if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD && this.connection) {
142
- log?.info(
143
- `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
144
- );
145
- this.halfCloseConnection();
141
+ if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD) {
142
+ if (this.connection) {
143
+ log?.info(
144
+ `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
145
+ );
146
+ this.halfCloseConnection();
147
+ }
146
148
  return;
147
149
  }
148
150
  this.send(
@@ -179,7 +181,6 @@ var Session = class {
179
181
  }
180
182
  }
181
183
  updateBookkeeping(ack, seq) {
182
- this.heartbeatMisses = 0;
183
184
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
184
185
  this.ack = seq + 1;
185
186
  }
@@ -211,6 +212,7 @@ var Session = class {
211
212
  }, SESSION_DISCONNECT_GRACE_MS);
212
213
  }
213
214
  cancelGrace() {
215
+ this.heartbeatMisses = 0;
214
216
  clearTimeout(this.disconnectionGrace);
215
217
  }
216
218
  get connected() {
@@ -257,6 +259,13 @@ var defaultTransportOptions = {
257
259
  codec: NaiveJsonCodec
258
260
  };
259
261
  var Transport = class {
262
+ /**
263
+ * Unique per instance of the transport.
264
+ * This allows us to distinguish reconnects to different
265
+ * transports.
266
+ */
267
+ instanceId = nanoid2();
268
+ connectedInstanceIds = /* @__PURE__ */ new Map();
260
269
  /**
261
270
  * A flag indicating whether the transport has been destroyed.
262
271
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -318,12 +327,23 @@ var Transport = class {
318
327
  * and we know the identity of the connected client.
319
328
  * @param conn The connection object.
320
329
  */
321
- onConnect(conn, connectedTo) {
330
+ onConnect(conn, connectedTo, instanceId) {
322
331
  this.eventDispatcher.dispatchEvent("connectionStatus", {
323
332
  status: "connect",
324
333
  conn
325
334
  });
326
- const session = this.sessions.get(connectedTo);
335
+ let session = this.sessions.get(connectedTo);
336
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
337
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
338
+ log?.debug(
339
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
340
+ );
341
+ session.resetBufferedMessages();
342
+ session.closeStaleConnection();
343
+ this.deleteSession(session);
344
+ session = void 0;
345
+ }
346
+ this.connectedInstanceIds.set(connectedTo, instanceId);
327
347
  if (session === void 0) {
328
348
  const newSession = this.createSession(connectedTo, conn);
329
349
  log?.info(
@@ -389,11 +409,13 @@ var Transport = class {
389
409
  const parsedMsg = this.codec.fromBuffer(msg);
390
410
  if (parsedMsg === null) {
391
411
  const decodedBuffer = new TextDecoder().decode(msg);
392
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
412
+ log?.error(
413
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
414
+ );
393
415
  return null;
394
416
  }
395
417
  if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
396
- log?.warn(
418
+ log?.error(
397
419
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
398
420
  parsedMsg
399
421
  )}`
@@ -412,9 +434,6 @@ var Transport = class {
412
434
  * @param msg The received message.
413
435
  */
414
436
  handleMsg(msg) {
415
- if (!msg) {
416
- return;
417
- }
418
437
  const session = this.sessionByClientId(msg.from);
419
438
  session.cancelGrace();
420
439
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -516,7 +535,6 @@ var ClientTransport = class extends Transport {
516
535
  */
517
536
  inflightConnectionPromises;
518
537
  tryReconnecting = true;
519
- serverInstanceIds = /* @__PURE__ */ new Map();
520
538
  constructor(clientId, providedOptions) {
521
539
  super(clientId, providedOptions);
522
540
  this.inflightConnectionPromises = /* @__PURE__ */ new Map();
@@ -524,7 +542,14 @@ var ClientTransport = class extends Transport {
524
542
  handleConnection(conn, to) {
525
543
  const bootHandler = this.receiveWithBootSequence(conn, () => {
526
544
  conn.removeDataListener(bootHandler);
527
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
545
+ conn.addDataListener((data) => {
546
+ const parsed = this.parseMsg(data);
547
+ if (!parsed) {
548
+ conn.close();
549
+ return;
550
+ }
551
+ this.handleMsg(parsed);
552
+ });
528
553
  });
529
554
  conn.addDataListener(bootHandler);
530
555
  conn.addCloseListener(() => {
@@ -556,7 +581,7 @@ var ClientTransport = class extends Transport {
556
581
  try {
557
582
  const conn = await reconnectPromise;
558
583
  this.state = "open";
559
- const requestMsg = bootRequestMessage(this.clientId, to);
584
+ const requestMsg = bootRequestMessage(this.clientId, to, this.instanceId);
560
585
  log?.debug(`${this.clientId} -- sending boot handshake to ${to}`);
561
586
  conn.send(this.codec.toBuffer(requestMsg));
562
587
  } catch (error) {
@@ -579,8 +604,10 @@ var ClientTransport = class extends Transport {
579
604
  receiveWithBootSequence(conn, sessionCb) {
580
605
  const bootHandler = (data) => {
581
606
  const parsed = this.parseMsg(data);
582
- if (!parsed)
607
+ if (!parsed) {
608
+ conn.close();
583
609
  return;
610
+ }
584
611
  if (!Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
585
612
  log?.warn(
586
613
  `${this.clientId} -- received invalid handshake resp: ${JSON.stringify(parsed)}`
@@ -595,22 +622,11 @@ var ClientTransport = class extends Transport {
595
622
  );
596
623
  return;
597
624
  }
598
- const oldSession = this.sessions.get(parsed.from);
599
625
  const serverInstanceId = parsed.payload.status.instanceId;
600
- const lastServerInstanceId = this.serverInstanceIds.get(parsed.from);
601
- if (oldSession && lastServerInstanceId !== serverInstanceId && lastServerInstanceId !== void 0) {
602
- log?.debug(
603
- `${this.clientId} -- handshake from ${parsed.from} has different server instance (got: ${serverInstanceId}, last connected to: ${lastServerInstanceId}), starting a new session`
604
- );
605
- oldSession.resetBufferedMessages();
606
- oldSession.closeStaleConnection();
607
- this.deleteSession(oldSession);
608
- }
609
626
  log?.debug(
610
627
  `${this.clientId} -- handshake from ${parsed.from} ok (server instance: ${serverInstanceId})`
611
628
  );
612
- this.serverInstanceIds.set(parsed.from, serverInstanceId);
613
- sessionCb(this.onConnect(conn, parsed.from));
629
+ sessionCb(this.onConnect(conn, parsed.from, serverInstanceId));
614
630
  };
615
631
  return bootHandler;
616
632
  }
@@ -621,14 +637,6 @@ var ClientTransport = class extends Transport {
621
637
  }
622
638
  };
623
639
  var ServerTransport = class extends Transport {
624
- /**
625
- * Unique per instance of server transport.
626
- * This allows us to distinguish reconnects to different
627
- * server transports at the same reachable address and signal
628
- * the appropriate session disconnect back to the client at the
629
- * boot stage.
630
- */
631
- instanceId = nanoid2();
632
640
  constructor(clientId, providedOptions) {
633
641
  super(clientId, providedOptions);
634
642
  log?.info(
@@ -643,7 +651,14 @@ var ServerTransport = class extends Transport {
643
651
  (establishedSession) => {
644
652
  session = establishedSession;
645
653
  conn.removeDataListener(bootHandler);
646
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
654
+ conn.addDataListener((data) => {
655
+ const parsed = this.parseMsg(data);
656
+ if (!parsed) {
657
+ conn.close();
658
+ return;
659
+ }
660
+ this.handleMsg(parsed);
661
+ });
647
662
  }
648
663
  );
649
664
  conn.addDataListener(bootHandler);
@@ -666,8 +681,10 @@ var ServerTransport = class extends Transport {
666
681
  receiveWithBootSequence(conn, sessionCb) {
667
682
  const bootHandler = (data) => {
668
683
  const parsed = this.parseMsg(data);
669
- if (!parsed)
684
+ if (!parsed) {
685
+ conn.close();
670
686
  return;
687
+ }
671
688
  if (!Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
672
689
  const responseMsg2 = bootResponseMessage(
673
690
  this.clientId,
@@ -683,8 +700,9 @@ var ServerTransport = class extends Transport {
683
700
  );
684
701
  return;
685
702
  }
703
+ const instanceId = parsed.payload.instanceId;
686
704
  log?.debug(
687
- `${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
705
+ `${this.clientId} -- handshake from ${parsed.from} ok (instance id: ${instanceId}), responding with handshake success`
688
706
  );
689
707
  const responseMsg = bootResponseMessage(
690
708
  this.clientId,
@@ -693,7 +711,7 @@ var ServerTransport = class extends Transport {
693
711
  true
694
712
  );
695
713
  conn.send(this.codec.toBuffer(responseMsg));
696
- sessionCb(this.onConnect(conn, parsed.from));
714
+ sessionCb(this.onConnect(conn, parsed.from, instanceId));
697
715
  };
698
716
  return bootHandler;
699
717
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Connection
3
- } from "./chunk-ANGOKBE5.js";
3
+ } from "./chunk-QEYN2Z6O.js";
4
4
 
5
5
  // transport/impls/ws/connection.ts
6
6
  var WebSocketConnection = class extends Connection {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-IIBVKYDB.js";
4
4
  import {
5
5
  Connection
6
- } from "./chunk-ANGOKBE5.js";
6
+ } from "./chunk-QEYN2Z6O.js";
7
7
 
8
8
  // transport/impls/uds/connection.ts
9
9
  var UdsConnection = class extends Connection {
@@ -22,7 +22,8 @@ var ControlMessageCloseSchema = Type.Object({
22
22
  var PROTOCOL_VERSION = "v1";
23
23
  var ControlMessageHandshakeRequestSchema = Type.Object({
24
24
  type: Type.Literal("HANDSHAKE_REQ"),
25
- protocolVersion: Type.Literal(PROTOCOL_VERSION)
25
+ protocolVersion: Type.Literal(PROTOCOL_VERSION),
26
+ instanceId: Type.String()
26
27
  });
27
28
  var ControlMessageHandshakeResponseSchema = Type.Object({
28
29
  type: Type.Literal("HANDSHAKE_RESP"),
@@ -46,7 +47,7 @@ var ControlMessagePayloadSchema = Type.Union([
46
47
  var OpaqueTransportMessageSchema = TransportMessageSchema(
47
48
  Type.Unknown()
48
49
  );
49
- function bootRequestMessage(from, to) {
50
+ function bootRequestMessage(from, to, instanceId) {
50
51
  return {
51
52
  id: nanoid(),
52
53
  from,
@@ -57,7 +58,8 @@ function bootRequestMessage(from, to) {
57
58
  controlFlags: 0,
58
59
  payload: {
59
60
  type: "HANDSHAKE_REQ",
60
- protocolVersion: PROTOCOL_VERSION
61
+ protocolVersion: PROTOCOL_VERSION,
62
+ instanceId
61
63
  }
62
64
  };
63
65
  }
@@ -1,4 +1,4 @@
1
- import { C as Connection } from './index-d91775d9.js';
1
+ import { C as Connection } from './index-0c0a69f6.js';
2
2
  import { U as Uint32LengthPrefixFraming } from './messageFraming-b200ef25.js';
3
3
 
4
4
  declare class StreamConnection extends Connection {
@@ -1,4 +1,4 @@
1
- import { C as Connection } from './index-d91775d9.js';
1
+ import { C as Connection } from './index-0c0a69f6.js';
2
2
  import { Socket } from 'node:net';
3
3
  import { U as Uint32LengthPrefixFraming } from './messageFraming-b200ef25.js';
4
4
 
@@ -1,5 +1,5 @@
1
1
  import WebSocket from 'isomorphic-ws';
2
- import { C as Connection } from './index-d91775d9.js';
2
+ import { C as Connection } from './index-0c0a69f6.js';
3
3
 
4
4
  declare class WebSocketConnection extends Connection {
5
5
  ws: WebSocket;
@@ -295,6 +295,13 @@ interface TransportOptions {
295
295
  * @abstract
296
296
  */
297
297
  declare abstract class Transport<ConnType extends Connection> {
298
+ /**
299
+ * Unique per instance of the transport.
300
+ * This allows us to distinguish reconnects to different
301
+ * transports.
302
+ */
303
+ instanceId: string;
304
+ connectedInstanceIds: Map<string, string>;
298
305
  /**
299
306
  * A flag indicating whether the transport has been destroyed.
300
307
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -346,7 +353,7 @@ declare abstract class Transport<ConnType extends Connection> {
346
353
  * and we know the identity of the connected client.
347
354
  * @param conn The connection object.
348
355
  */
349
- protected onConnect(conn: ConnType, connectedTo: TransportClientId): Session<ConnType>;
356
+ protected onConnect(conn: ConnType, connectedTo: TransportClientId, instanceId: string): Session<ConnType>;
350
357
  private createSession;
351
358
  protected deleteSession(session: Session<ConnType>): void;
352
359
  /**
@@ -365,7 +372,7 @@ declare abstract class Transport<ConnType extends Connection> {
365
372
  * You generally shouldn't need to override this in downstream transport implementations.
366
373
  * @param msg The received message.
367
374
  */
368
- handleMsg(msg: OpaqueTransportMessage | null): void;
375
+ handleMsg(msg: OpaqueTransportMessage): void;
369
376
  /**
370
377
  * Adds a listener to this transport.
371
378
  * @param the type of event to listen for
@@ -405,7 +412,6 @@ declare abstract class ClientTransport<ConnType extends Connection> extends Tran
405
412
  */
406
413
  inflightConnectionPromises: Map<TransportClientId, Promise<ConnType>>;
407
414
  tryReconnecting: boolean;
408
- serverInstanceIds: Map<string, string>;
409
415
  constructor(clientId: TransportClientId, providedOptions?: Partial<TransportOptions>);
410
416
  protected handleConnection(conn: ConnType, to: TransportClientId): void;
411
417
  /**
@@ -426,14 +432,6 @@ declare abstract class ClientTransport<ConnType extends Connection> extends Tran
426
432
  onDisconnect(conn: ConnType, connectedTo: string | undefined): void;
427
433
  }
428
434
  declare abstract class ServerTransport<ConnType extends Connection> extends Transport<ConnType> {
429
- /**
430
- * Unique per instance of server transport.
431
- * This allows us to distinguish reconnects to different
432
- * server transports at the same reachable address and signal
433
- * the appropriate session disconnect back to the client at the
434
- * boot stage.
435
- */
436
- instanceId: string;
437
435
  constructor(clientId: TransportClientId, providedOptions?: Partial<TransportOptions>);
438
436
  protected handleConnection(conn: ConnType): void;
439
437
  receiveWithBootSequence(conn: ConnType, sessionCb: (sess: Session<ConnType>) => void): (data: Uint8Array) => void;
@@ -427,7 +427,8 @@ var ControlMessageCloseSchema = import_typebox2.Type.Object({
427
427
  var PROTOCOL_VERSION = "v1";
428
428
  var ControlMessageHandshakeRequestSchema = import_typebox2.Type.Object({
429
429
  type: import_typebox2.Type.Literal("HANDSHAKE_REQ"),
430
- protocolVersion: import_typebox2.Type.Literal(PROTOCOL_VERSION)
430
+ protocolVersion: import_typebox2.Type.Literal(PROTOCOL_VERSION),
431
+ instanceId: import_typebox2.Type.String()
431
432
  });
432
433
  var ControlMessageHandshakeResponseSchema = import_typebox2.Type.Object({
433
434
  type: import_typebox2.Type.Literal("HANDSHAKE_RESP"),
@@ -1,6 +1,6 @@
1
1
  import { A as AnyService, P as PayloadType, b as Result, R as RiverError, S as ServiceContext, d as ProcType, e as ProcInput, f as ProcOutput, g as ProcErrors, h as ProcHasInit, i as ProcInit } from '../builder-c593de11.js';
2
2
  export { E as Err, O as Ok, m as ProcHandler, k as ProcListing, a as Procedure, o as RiverErrorSchema, c as RiverUncaughtSchema, l as Service, j as ServiceBuilder, n as ServiceContextWithState, U as UNCAUGHT_ERROR, V as ValidProcType, s as serializeService } from '../builder-c593de11.js';
3
- import { T as Transport, C as Connection, b as TransportClientId } from '../index-d91775d9.js';
3
+ import { T as Transport, C as Connection, b as TransportClientId } from '../index-0c0a69f6.js';
4
4
  import { Pushable } from 'it-pushable';
5
5
  import { Static } from '@sinclair/typebox';
6
6
  import '../types-3e5768ec.js';
@@ -1,6 +1,6 @@
1
1
  import { A as AnyService, P as PayloadType, b as Result, R as RiverError, S as ServiceContext, d as ProcType, e as ProcInput, f as ProcOutput, g as ProcErrors, h as ProcHasInit, i as ProcInit } from '../builder-c593de11.js';
2
2
  export { E as Err, O as Ok, m as ProcHandler, k as ProcListing, a as Procedure, o as RiverErrorSchema, c as RiverUncaughtSchema, l as Service, j as ServiceBuilder, n as ServiceContextWithState, U as UNCAUGHT_ERROR, V as ValidProcType, s as serializeService } from '../builder-c593de11.js';
3
- import { T as Transport, C as Connection, b as TransportClientId } from '../index-d91775d9.js';
3
+ import { T as Transport, C as Connection, b as TransportClientId } from '../index-0c0a69f6.js';
4
4
  import { Pushable } from 'it-pushable';
5
5
  import { Static } from '@sinclair/typebox';
6
6
  import '../types-3e5768ec.js';
@@ -8,8 +8,8 @@ import {
8
8
  createClient,
9
9
  createServer,
10
10
  serializeService
11
- } from "../chunk-24O3BKZA.js";
12
- import "../chunk-WTOIOXB7.js";
11
+ } from "../chunk-55XUAPC6.js";
12
+ import "../chunk-XFFS4UOD.js";
13
13
  import "../chunk-H4BYJELI.js";
14
14
  export {
15
15
  Err,
@@ -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"),
@@ -78,7 +79,7 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
78
79
  var OpaqueTransportMessageSchema = TransportMessageSchema(
79
80
  import_typebox.Type.Unknown()
80
81
  );
81
- function bootRequestMessage(from, to) {
82
+ function bootRequestMessage(from, to, instanceId) {
82
83
  return {
83
84
  id: (0, import_nanoid.nanoid)(),
84
85
  from,
@@ -89,7 +90,8 @@ function bootRequestMessage(from, to) {
89
90
  controlFlags: 0,
90
91
  payload: {
91
92
  type: "HANDSHAKE_REQ",
92
- protocolVersion: PROTOCOL_VERSION
93
+ protocolVersion: PROTOCOL_VERSION,
94
+ instanceId
93
95
  }
94
96
  };
95
97
  }
@@ -135,9 +137,9 @@ var Connection = class {
135
137
  this.debugId = `conn-${unsafeId()}`;
136
138
  }
137
139
  };
138
- var HEARTBEAT_INTERVAL_MS = 250;
139
- var HEARTBEATS_TILL_DEAD = 4;
140
- var SESSION_DISCONNECT_GRACE_MS = 3e3;
140
+ var HEARTBEAT_INTERVAL_MS = 1e3;
141
+ var HEARTBEATS_TILL_DEAD = 2;
142
+ var SESSION_DISCONNECT_GRACE_MS = 5e3;
141
143
  var Session = class {
142
144
  codec;
143
145
  /**
@@ -220,11 +222,13 @@ var Session = class {
220
222
  return fullMsg.id;
221
223
  }
222
224
  sendHeartbeat() {
223
- if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD && this.connection) {
224
- log?.info(
225
- `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
226
- );
227
- this.halfCloseConnection();
225
+ if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD) {
226
+ if (this.connection) {
227
+ log?.info(
228
+ `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
229
+ );
230
+ this.halfCloseConnection();
231
+ }
228
232
  return;
229
233
  }
230
234
  this.send(
@@ -261,7 +265,6 @@ var Session = class {
261
265
  }
262
266
  }
263
267
  updateBookkeeping(ack, seq) {
264
- this.heartbeatMisses = 0;
265
268
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
266
269
  this.ack = seq + 1;
267
270
  }
@@ -293,6 +296,7 @@ var Session = class {
293
296
  }, SESSION_DISCONNECT_GRACE_MS);
294
297
  }
295
298
  cancelGrace() {
299
+ this.heartbeatMisses = 0;
296
300
  clearTimeout(this.disconnectionGrace);
297
301
  }
298
302
  get connected() {
@@ -400,6 +404,13 @@ var defaultTransportOptions = {
400
404
  codec: NaiveJsonCodec
401
405
  };
402
406
  var Transport = class {
407
+ /**
408
+ * Unique per instance of the transport.
409
+ * This allows us to distinguish reconnects to different
410
+ * transports.
411
+ */
412
+ instanceId = (0, import_nanoid3.nanoid)();
413
+ connectedInstanceIds = /* @__PURE__ */ new Map();
403
414
  /**
404
415
  * A flag indicating whether the transport has been destroyed.
405
416
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -461,12 +472,23 @@ var Transport = class {
461
472
  * and we know the identity of the connected client.
462
473
  * @param conn The connection object.
463
474
  */
464
- onConnect(conn, connectedTo) {
475
+ onConnect(conn, connectedTo, instanceId) {
465
476
  this.eventDispatcher.dispatchEvent("connectionStatus", {
466
477
  status: "connect",
467
478
  conn
468
479
  });
469
- const session = this.sessions.get(connectedTo);
480
+ let session = this.sessions.get(connectedTo);
481
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
482
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
483
+ log?.debug(
484
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
485
+ );
486
+ session.resetBufferedMessages();
487
+ session.closeStaleConnection();
488
+ this.deleteSession(session);
489
+ session = void 0;
490
+ }
491
+ this.connectedInstanceIds.set(connectedTo, instanceId);
470
492
  if (session === void 0) {
471
493
  const newSession = this.createSession(connectedTo, conn);
472
494
  log?.info(
@@ -532,11 +554,13 @@ var Transport = class {
532
554
  const parsedMsg = this.codec.fromBuffer(msg);
533
555
  if (parsedMsg === null) {
534
556
  const decodedBuffer = new TextDecoder().decode(msg);
535
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
557
+ log?.error(
558
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
559
+ );
536
560
  return null;
537
561
  }
538
562
  if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
539
- log?.warn(
563
+ log?.error(
540
564
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
541
565
  parsedMsg
542
566
  )}`
@@ -555,9 +579,6 @@ var Transport = class {
555
579
  * @param msg The received message.
556
580
  */
557
581
  handleMsg(msg) {
558
- if (!msg) {
559
- return;
560
- }
561
582
  const session = this.sessionByClientId(msg.from);
562
583
  session.cancelGrace();
563
584
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -659,7 +680,6 @@ var ClientTransport = class extends Transport {
659
680
  */
660
681
  inflightConnectionPromises;
661
682
  tryReconnecting = true;
662
- serverInstanceIds = /* @__PURE__ */ new Map();
663
683
  constructor(clientId, providedOptions) {
664
684
  super(clientId, providedOptions);
665
685
  this.inflightConnectionPromises = /* @__PURE__ */ new Map();
@@ -667,7 +687,14 @@ var ClientTransport = class extends Transport {
667
687
  handleConnection(conn, to) {
668
688
  const bootHandler = this.receiveWithBootSequence(conn, () => {
669
689
  conn.removeDataListener(bootHandler);
670
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
690
+ conn.addDataListener((data) => {
691
+ const parsed = this.parseMsg(data);
692
+ if (!parsed) {
693
+ conn.close();
694
+ return;
695
+ }
696
+ this.handleMsg(parsed);
697
+ });
671
698
  });
672
699
  conn.addDataListener(bootHandler);
673
700
  conn.addCloseListener(() => {
@@ -699,7 +726,7 @@ var ClientTransport = class extends Transport {
699
726
  try {
700
727
  const conn = await reconnectPromise;
701
728
  this.state = "open";
702
- const requestMsg = bootRequestMessage(this.clientId, to);
729
+ const requestMsg = bootRequestMessage(this.clientId, to, this.instanceId);
703
730
  log?.debug(`${this.clientId} -- sending boot handshake to ${to}`);
704
731
  conn.send(this.codec.toBuffer(requestMsg));
705
732
  } catch (error) {
@@ -722,8 +749,10 @@ var ClientTransport = class extends Transport {
722
749
  receiveWithBootSequence(conn, sessionCb) {
723
750
  const bootHandler = (data) => {
724
751
  const parsed = this.parseMsg(data);
725
- if (!parsed)
752
+ if (!parsed) {
753
+ conn.close();
726
754
  return;
755
+ }
727
756
  if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
728
757
  log?.warn(
729
758
  `${this.clientId} -- received invalid handshake resp: ${JSON.stringify(parsed)}`
@@ -738,22 +767,11 @@ var ClientTransport = class extends Transport {
738
767
  );
739
768
  return;
740
769
  }
741
- const oldSession = this.sessions.get(parsed.from);
742
770
  const serverInstanceId = parsed.payload.status.instanceId;
743
- const lastServerInstanceId = this.serverInstanceIds.get(parsed.from);
744
- if (oldSession && lastServerInstanceId !== serverInstanceId && lastServerInstanceId !== void 0) {
745
- log?.debug(
746
- `${this.clientId} -- handshake from ${parsed.from} has different server instance (got: ${serverInstanceId}, last connected to: ${lastServerInstanceId}), starting a new session`
747
- );
748
- oldSession.resetBufferedMessages();
749
- oldSession.closeStaleConnection();
750
- this.deleteSession(oldSession);
751
- }
752
771
  log?.debug(
753
772
  `${this.clientId} -- handshake from ${parsed.from} ok (server instance: ${serverInstanceId})`
754
773
  );
755
- this.serverInstanceIds.set(parsed.from, serverInstanceId);
756
- sessionCb(this.onConnect(conn, parsed.from));
774
+ sessionCb(this.onConnect(conn, parsed.from, serverInstanceId));
757
775
  };
758
776
  return bootHandler;
759
777
  }
@@ -1,5 +1,5 @@
1
- import { a as ClientTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
2
- import { S as StreamConnection } from '../../../connection-2956a1c5.js';
1
+ import { a as ClientTransport, 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 { a as ClientTransport, b as TransportClientId, c as TransportOptions } from '../../../index-d91775d9.js';
2
- import { S as StreamConnection } from '../../../connection-2956a1c5.js';
1
+ import { a as ClientTransport, 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';