@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
@@ -57,7 +57,8 @@ var ControlMessageCloseSchema = import_typebox.Type.Object({
57
57
  var PROTOCOL_VERSION = "v1";
58
58
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
59
59
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
60
- protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION)
60
+ protocolVersion: import_typebox.Type.Literal(PROTOCOL_VERSION),
61
+ instanceId: import_typebox.Type.String()
61
62
  });
62
63
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
63
64
  type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
@@ -81,7 +82,7 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
81
82
  var OpaqueTransportMessageSchema = TransportMessageSchema(
82
83
  import_typebox.Type.Unknown()
83
84
  );
84
- function bootRequestMessage(from, to) {
85
+ function bootRequestMessage(from, to, instanceId) {
85
86
  return {
86
87
  id: (0, import_nanoid.nanoid)(),
87
88
  from,
@@ -92,7 +93,8 @@ function bootRequestMessage(from, to) {
92
93
  controlFlags: 0,
93
94
  payload: {
94
95
  type: "HANDSHAKE_REQ",
95
- protocolVersion: PROTOCOL_VERSION
96
+ protocolVersion: PROTOCOL_VERSION,
97
+ instanceId
96
98
  }
97
99
  };
98
100
  }
@@ -165,9 +167,9 @@ var Connection = class {
165
167
  this.debugId = `conn-${unsafeId()}`;
166
168
  }
167
169
  };
168
- var HEARTBEAT_INTERVAL_MS = 250;
169
- var HEARTBEATS_TILL_DEAD = 4;
170
- var SESSION_DISCONNECT_GRACE_MS = 3e3;
170
+ var HEARTBEAT_INTERVAL_MS = 1e3;
171
+ var HEARTBEATS_TILL_DEAD = 2;
172
+ var SESSION_DISCONNECT_GRACE_MS = 5e3;
171
173
  var Session = class {
172
174
  codec;
173
175
  /**
@@ -250,11 +252,13 @@ var Session = class {
250
252
  return fullMsg.id;
251
253
  }
252
254
  sendHeartbeat() {
253
- if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD && this.connection) {
254
- log?.info(
255
- `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
256
- );
257
- this.halfCloseConnection();
255
+ if (this.heartbeatMisses >= HEARTBEATS_TILL_DEAD) {
256
+ if (this.connection) {
257
+ log?.info(
258
+ `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
259
+ );
260
+ this.halfCloseConnection();
261
+ }
258
262
  return;
259
263
  }
260
264
  this.send(
@@ -291,7 +295,6 @@ var Session = class {
291
295
  }
292
296
  }
293
297
  updateBookkeeping(ack, seq) {
294
- this.heartbeatMisses = 0;
295
298
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
296
299
  this.ack = seq + 1;
297
300
  }
@@ -323,6 +326,7 @@ var Session = class {
323
326
  }, SESSION_DISCONNECT_GRACE_MS);
324
327
  }
325
328
  cancelGrace() {
329
+ this.heartbeatMisses = 0;
326
330
  clearTimeout(this.disconnectionGrace);
327
331
  }
328
332
  get connected() {
@@ -430,6 +434,13 @@ var defaultTransportOptions = {
430
434
  codec: NaiveJsonCodec
431
435
  };
432
436
  var Transport = class {
437
+ /**
438
+ * Unique per instance of the transport.
439
+ * This allows us to distinguish reconnects to different
440
+ * transports.
441
+ */
442
+ instanceId = (0, import_nanoid3.nanoid)();
443
+ connectedInstanceIds = /* @__PURE__ */ new Map();
433
444
  /**
434
445
  * A flag indicating whether the transport has been destroyed.
435
446
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -491,12 +502,23 @@ var Transport = class {
491
502
  * and we know the identity of the connected client.
492
503
  * @param conn The connection object.
493
504
  */
494
- onConnect(conn, connectedTo) {
505
+ onConnect(conn, connectedTo, instanceId) {
495
506
  this.eventDispatcher.dispatchEvent("connectionStatus", {
496
507
  status: "connect",
497
508
  conn
498
509
  });
499
- const session = this.sessions.get(connectedTo);
510
+ let session = this.sessions.get(connectedTo);
511
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
512
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
513
+ log?.debug(
514
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
515
+ );
516
+ session.resetBufferedMessages();
517
+ session.closeStaleConnection();
518
+ this.deleteSession(session);
519
+ session = void 0;
520
+ }
521
+ this.connectedInstanceIds.set(connectedTo, instanceId);
500
522
  if (session === void 0) {
501
523
  const newSession = this.createSession(connectedTo, conn);
502
524
  log?.info(
@@ -562,11 +584,13 @@ var Transport = class {
562
584
  const parsedMsg = this.codec.fromBuffer(msg);
563
585
  if (parsedMsg === null) {
564
586
  const decodedBuffer = new TextDecoder().decode(msg);
565
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
587
+ log?.error(
588
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
589
+ );
566
590
  return null;
567
591
  }
568
592
  if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
569
- log?.warn(
593
+ log?.error(
570
594
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
571
595
  parsedMsg
572
596
  )}`
@@ -585,9 +609,6 @@ var Transport = class {
585
609
  * @param msg The received message.
586
610
  */
587
611
  handleMsg(msg) {
588
- if (!msg) {
589
- return;
590
- }
591
612
  const session = this.sessionByClientId(msg.from);
592
613
  session.cancelGrace();
593
614
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -689,7 +710,6 @@ var ClientTransport = class extends Transport {
689
710
  */
690
711
  inflightConnectionPromises;
691
712
  tryReconnecting = true;
692
- serverInstanceIds = /* @__PURE__ */ new Map();
693
713
  constructor(clientId, providedOptions) {
694
714
  super(clientId, providedOptions);
695
715
  this.inflightConnectionPromises = /* @__PURE__ */ new Map();
@@ -697,7 +717,14 @@ var ClientTransport = class extends Transport {
697
717
  handleConnection(conn, to) {
698
718
  const bootHandler = this.receiveWithBootSequence(conn, () => {
699
719
  conn.removeDataListener(bootHandler);
700
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
720
+ conn.addDataListener((data) => {
721
+ const parsed = this.parseMsg(data);
722
+ if (!parsed) {
723
+ conn.close();
724
+ return;
725
+ }
726
+ this.handleMsg(parsed);
727
+ });
701
728
  });
702
729
  conn.addDataListener(bootHandler);
703
730
  conn.addCloseListener(() => {
@@ -729,7 +756,7 @@ var ClientTransport = class extends Transport {
729
756
  try {
730
757
  const conn = await reconnectPromise;
731
758
  this.state = "open";
732
- const requestMsg = bootRequestMessage(this.clientId, to);
759
+ const requestMsg = bootRequestMessage(this.clientId, to, this.instanceId);
733
760
  log?.debug(`${this.clientId} -- sending boot handshake to ${to}`);
734
761
  conn.send(this.codec.toBuffer(requestMsg));
735
762
  } catch (error) {
@@ -752,8 +779,10 @@ var ClientTransport = class extends Transport {
752
779
  receiveWithBootSequence(conn, sessionCb) {
753
780
  const bootHandler = (data) => {
754
781
  const parsed = this.parseMsg(data);
755
- if (!parsed)
782
+ if (!parsed) {
783
+ conn.close();
756
784
  return;
785
+ }
757
786
  if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
758
787
  log?.warn(
759
788
  `${this.clientId} -- received invalid handshake resp: ${JSON.stringify(parsed)}`
@@ -768,22 +797,11 @@ var ClientTransport = class extends Transport {
768
797
  );
769
798
  return;
770
799
  }
771
- const oldSession = this.sessions.get(parsed.from);
772
800
  const serverInstanceId = parsed.payload.status.instanceId;
773
- const lastServerInstanceId = this.serverInstanceIds.get(parsed.from);
774
- if (oldSession && lastServerInstanceId !== serverInstanceId && lastServerInstanceId !== void 0) {
775
- log?.debug(
776
- `${this.clientId} -- handshake from ${parsed.from} has different server instance (got: ${serverInstanceId}, last connected to: ${lastServerInstanceId}), starting a new session`
777
- );
778
- oldSession.resetBufferedMessages();
779
- oldSession.closeStaleConnection();
780
- this.deleteSession(oldSession);
781
- }
782
801
  log?.debug(
783
802
  `${this.clientId} -- handshake from ${parsed.from} ok (server instance: ${serverInstanceId})`
784
803
  );
785
- this.serverInstanceIds.set(parsed.from, serverInstanceId);
786
- sessionCb(this.onConnect(conn, parsed.from));
804
+ sessionCb(this.onConnect(conn, parsed.from, serverInstanceId));
787
805
  };
788
806
  return bootHandler;
789
807
  }
@@ -794,14 +812,6 @@ var ClientTransport = class extends Transport {
794
812
  }
795
813
  };
796
814
  var ServerTransport = class extends Transport {
797
- /**
798
- * Unique per instance of server transport.
799
- * This allows us to distinguish reconnects to different
800
- * server transports at the same reachable address and signal
801
- * the appropriate session disconnect back to the client at the
802
- * boot stage.
803
- */
804
- instanceId = (0, import_nanoid3.nanoid)();
805
815
  constructor(clientId, providedOptions) {
806
816
  super(clientId, providedOptions);
807
817
  log?.info(
@@ -816,7 +826,14 @@ var ServerTransport = class extends Transport {
816
826
  (establishedSession) => {
817
827
  session = establishedSession;
818
828
  conn.removeDataListener(bootHandler);
819
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
829
+ conn.addDataListener((data) => {
830
+ const parsed = this.parseMsg(data);
831
+ if (!parsed) {
832
+ conn.close();
833
+ return;
834
+ }
835
+ this.handleMsg(parsed);
836
+ });
820
837
  }
821
838
  );
822
839
  conn.addDataListener(bootHandler);
@@ -839,8 +856,10 @@ var ServerTransport = class extends Transport {
839
856
  receiveWithBootSequence(conn, sessionCb) {
840
857
  const bootHandler = (data) => {
841
858
  const parsed = this.parseMsg(data);
842
- if (!parsed)
859
+ if (!parsed) {
860
+ conn.close();
843
861
  return;
862
+ }
844
863
  if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
845
864
  const responseMsg2 = bootResponseMessage(
846
865
  this.clientId,
@@ -856,8 +875,9 @@ var ServerTransport = class extends Transport {
856
875
  );
857
876
  return;
858
877
  }
878
+ const instanceId = parsed.payload.instanceId;
859
879
  log?.debug(
860
- `${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
880
+ `${this.clientId} -- handshake from ${parsed.from} ok (instance id: ${instanceId}), responding with handshake success`
861
881
  );
862
882
  const responseMsg = bootResponseMessage(
863
883
  this.clientId,
@@ -866,7 +886,7 @@ var ServerTransport = class extends Transport {
866
886
  true
867
887
  );
868
888
  conn.send(this.codec.toBuffer(responseMsg));
869
- sessionCb(this.onConnect(conn, parsed.from));
889
+ sessionCb(this.onConnect(conn, parsed.from, instanceId));
870
890
  };
871
891
  return bootHandler;
872
892
  }
@@ -1,3 +1,3 @@
1
- export { a as ClientTransport, C as Connection, k as EventHandler, E as EventMap, j as EventTypes, O as OpaqueTransportMessage, f as OpaqueTransportMessageSchema, S as ServerTransport, d as Session, T as Transport, b as TransportClientId, g as TransportMessage, e as TransportMessageSchema, h as isStreamClose, i as isStreamOpen } from '../index-d91775d9.js';
1
+ export { a as ClientTransport, C as Connection, k as EventHandler, E as EventMap, j as EventTypes, O as OpaqueTransportMessage, f as OpaqueTransportMessageSchema, S as ServerTransport, d as Session, T as Transport, b as TransportClientId, g as TransportMessage, e as TransportMessageSchema, h as isStreamClose, i as isStreamOpen } from '../index-0c0a69f6.js';
2
2
  import '../types-3e5768ec.js';
3
3
  import '@sinclair/typebox';
@@ -1,3 +1,3 @@
1
- export { a as ClientTransport, C as Connection, k as EventHandler, E as EventMap, j as EventTypes, O as OpaqueTransportMessage, f as OpaqueTransportMessageSchema, S as ServerTransport, d as Session, T as Transport, b as TransportClientId, g as TransportMessage, e as TransportMessageSchema, h as isStreamClose, i as isStreamOpen } from '../index-d91775d9.js';
1
+ export { a as ClientTransport, C as Connection, k as EventHandler, E as EventMap, j as EventTypes, O as OpaqueTransportMessage, f as OpaqueTransportMessageSchema, S as ServerTransport, d as Session, T as Transport, b as TransportClientId, g as TransportMessage, e as TransportMessageSchema, h as isStreamClose, i as isStreamOpen } from '../index-0c0a69f6.js';
2
2
  import '../types-3e5768ec.js';
3
3
  import '@sinclair/typebox';
@@ -5,12 +5,12 @@ import {
5
5
  ServerTransport,
6
6
  Session,
7
7
  Transport
8
- } from "../chunk-ANGOKBE5.js";
8
+ } from "../chunk-QEYN2Z6O.js";
9
9
  import "../chunk-GZ7HCLLM.js";
10
10
  import {
11
11
  OpaqueTransportMessageSchema,
12
12
  TransportMessageSchema
13
- } from "../chunk-WTOIOXB7.js";
13
+ } from "../chunk-XFFS4UOD.js";
14
14
  import "../chunk-H4BYJELI.js";
15
15
  export {
16
16
  ClientTransport,
@@ -1,7 +1,7 @@
1
1
  import * as it_pushable from 'it-pushable';
2
2
  import WebSocket from 'isomorphic-ws';
3
3
  import http from 'node:http';
4
- import { P as PartialTransportMessage, T as Transport, C as Connection, O as OpaqueTransportMessage } from '../index-d91775d9.js';
4
+ import { P as PartialTransportMessage, T as Transport, C as Connection, O as OpaqueTransportMessage } from '../index-0c0a69f6.js';
5
5
  import { P as PayloadType, R as RiverError, a as Procedure, S as ServiceContext, b as Result, c as RiverUncaughtSchema } from '../builder-c593de11.js';
6
6
  import { Static } from '@sinclair/typebox';
7
7
  import net from 'node:net';
@@ -1,7 +1,7 @@
1
1
  import * as it_pushable from 'it-pushable';
2
2
  import WebSocket from 'isomorphic-ws';
3
3
  import http from 'node:http';
4
- import { P as PartialTransportMessage, T as Transport, C as Connection, O as OpaqueTransportMessage } from '../index-d91775d9.js';
4
+ import { P as PartialTransportMessage, T as Transport, C as Connection, O as OpaqueTransportMessage } from '../index-0c0a69f6.js';
5
5
  import { P as PayloadType, R as RiverError, a as Procedure, S as ServiceContext, b as Result, c as RiverUncaughtSchema } from '../builder-c593de11.js';
6
6
  import { Static } from '@sinclair/typebox';
7
7
  import net from 'node:net';
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  UNCAUGHT_ERROR,
3
3
  pushable
4
- } from "../chunk-24O3BKZA.js";
4
+ } from "../chunk-55XUAPC6.js";
5
5
  import {
6
6
  coerceErrorString
7
- } from "../chunk-WTOIOXB7.js";
7
+ } from "../chunk-XFFS4UOD.js";
8
8
  import "../chunk-H4BYJELI.js";
9
9
 
10
10
  // util/testHelpers.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@replit/river",
3
3
  "description": "It's like tRPC but... with JSON Schema Support, duplex streaming and support for service multiplexing. Transport agnostic!",
4
- "version": "0.12.0",
4
+ "version": "0.12.1",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {