@replit/river 0.12.0 → 0.12.2

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-ANGOKBE5.js → chunk-CT57CKBS.js} +67 -48
  3. package/dist/{chunk-4HOR4NUO.js → chunk-NHSJ4RDY.js} +1 -1
  4. package/dist/{chunk-XOTIAXAH.js → chunk-PIF32FUL.js} +1 -1
  5. package/dist/{chunk-IUDKWAOK.js → chunk-R6YJHJV7.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 +57 -38
  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 +55 -32
  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 +57 -38
  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 +55 -32
  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 +63 -38
  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 +55 -32
  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 +71 -50
  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.closeStaleConnection(this.connection);
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() {
@@ -351,6 +355,7 @@ var Session = class {
351
355
  */
352
356
  halfCloseConnection() {
353
357
  this.connection?.close();
358
+ clearInterval(this.heartbeat);
354
359
  }
355
360
  inspectSendBuffer() {
356
361
  return this.sendBuffer;
@@ -430,6 +435,13 @@ var defaultTransportOptions = {
430
435
  codec: NaiveJsonCodec
431
436
  };
432
437
  var Transport = class {
438
+ /**
439
+ * Unique per instance of the transport.
440
+ * This allows us to distinguish reconnects to different
441
+ * transports.
442
+ */
443
+ instanceId = (0, import_nanoid3.nanoid)();
444
+ connectedInstanceIds = /* @__PURE__ */ new Map();
433
445
  /**
434
446
  * A flag indicating whether the transport has been destroyed.
435
447
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -491,12 +503,23 @@ var Transport = class {
491
503
  * and we know the identity of the connected client.
492
504
  * @param conn The connection object.
493
505
  */
494
- onConnect(conn, connectedTo) {
506
+ onConnect(conn, connectedTo, instanceId) {
495
507
  this.eventDispatcher.dispatchEvent("connectionStatus", {
496
508
  status: "connect",
497
509
  conn
498
510
  });
499
- const session = this.sessions.get(connectedTo);
511
+ let session = this.sessions.get(connectedTo);
512
+ const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
513
+ if (session && lastInstanceId !== instanceId && lastInstanceId !== void 0) {
514
+ log?.warn(
515
+ `${this.clientId} -- handshake from ${connectedTo} has different server instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
516
+ );
517
+ session.resetBufferedMessages();
518
+ session.closeStaleConnection(conn);
519
+ this.deleteSession(session);
520
+ session = void 0;
521
+ }
522
+ this.connectedInstanceIds.set(connectedTo, instanceId);
500
523
  if (session === void 0) {
501
524
  const newSession = this.createSession(connectedTo, conn);
502
525
  log?.info(
@@ -527,13 +550,13 @@ var Transport = class {
527
550
  }
528
551
  deleteSession(session) {
529
552
  this.sessions.delete(session.to);
553
+ log?.info(
554
+ `${this.clientId} -- session ${session.debugId} disconnect from ${session.to}`
555
+ );
530
556
  this.eventDispatcher.dispatchEvent("sessionStatus", {
531
557
  status: "disconnect",
532
558
  session
533
559
  });
534
- log?.info(
535
- `${this.clientId} -- session ${session.debugId} disconnect from ${session.to}`
536
- );
537
560
  }
538
561
  /**
539
562
  * The downstream implementation needs to call this when a connection is closed.
@@ -562,11 +585,13 @@ var Transport = class {
562
585
  const parsedMsg = this.codec.fromBuffer(msg);
563
586
  if (parsedMsg === null) {
564
587
  const decodedBuffer = new TextDecoder().decode(msg);
565
- log?.warn(`${this.clientId} -- received malformed msg: ${decodedBuffer}`);
588
+ log?.error(
589
+ `${this.clientId} -- received malformed msg, killing conn: ${decodedBuffer}`
590
+ );
566
591
  return null;
567
592
  }
568
593
  if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
569
- log?.warn(
594
+ log?.error(
570
595
  `${this.clientId} -- received invalid msg: ${JSON.stringify(
571
596
  parsedMsg
572
597
  )}`
@@ -585,9 +610,6 @@ var Transport = class {
585
610
  * @param msg The received message.
586
611
  */
587
612
  handleMsg(msg) {
588
- if (!msg) {
589
- return;
590
- }
591
613
  const session = this.sessionByClientId(msg.from);
592
614
  session.cancelGrace();
593
615
  log?.debug(`${this.clientId} -- received msg: ${JSON.stringify(msg)}`);
@@ -689,7 +711,6 @@ var ClientTransport = class extends Transport {
689
711
  */
690
712
  inflightConnectionPromises;
691
713
  tryReconnecting = true;
692
- serverInstanceIds = /* @__PURE__ */ new Map();
693
714
  constructor(clientId, providedOptions) {
694
715
  super(clientId, providedOptions);
695
716
  this.inflightConnectionPromises = /* @__PURE__ */ new Map();
@@ -697,7 +718,14 @@ var ClientTransport = class extends Transport {
697
718
  handleConnection(conn, to) {
698
719
  const bootHandler = this.receiveWithBootSequence(conn, () => {
699
720
  conn.removeDataListener(bootHandler);
700
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
721
+ conn.addDataListener((data) => {
722
+ const parsed = this.parseMsg(data);
723
+ if (!parsed) {
724
+ conn.close();
725
+ return;
726
+ }
727
+ this.handleMsg(parsed);
728
+ });
701
729
  });
702
730
  conn.addDataListener(bootHandler);
703
731
  conn.addCloseListener(() => {
@@ -729,7 +757,7 @@ var ClientTransport = class extends Transport {
729
757
  try {
730
758
  const conn = await reconnectPromise;
731
759
  this.state = "open";
732
- const requestMsg = bootRequestMessage(this.clientId, to);
760
+ const requestMsg = bootRequestMessage(this.clientId, to, this.instanceId);
733
761
  log?.debug(`${this.clientId} -- sending boot handshake to ${to}`);
734
762
  conn.send(this.codec.toBuffer(requestMsg));
735
763
  } catch (error) {
@@ -752,8 +780,10 @@ var ClientTransport = class extends Transport {
752
780
  receiveWithBootSequence(conn, sessionCb) {
753
781
  const bootHandler = (data) => {
754
782
  const parsed = this.parseMsg(data);
755
- if (!parsed)
783
+ if (!parsed) {
784
+ conn.close();
756
785
  return;
786
+ }
757
787
  if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
758
788
  log?.warn(
759
789
  `${this.clientId} -- received invalid handshake resp: ${JSON.stringify(parsed)}`
@@ -768,22 +798,11 @@ var ClientTransport = class extends Transport {
768
798
  );
769
799
  return;
770
800
  }
771
- const oldSession = this.sessions.get(parsed.from);
772
801
  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
802
  log?.debug(
783
803
  `${this.clientId} -- handshake from ${parsed.from} ok (server instance: ${serverInstanceId})`
784
804
  );
785
- this.serverInstanceIds.set(parsed.from, serverInstanceId);
786
- sessionCb(this.onConnect(conn, parsed.from));
805
+ sessionCb(this.onConnect(conn, parsed.from, serverInstanceId));
787
806
  };
788
807
  return bootHandler;
789
808
  }
@@ -794,14 +813,6 @@ var ClientTransport = class extends Transport {
794
813
  }
795
814
  };
796
815
  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
816
  constructor(clientId, providedOptions) {
806
817
  super(clientId, providedOptions);
807
818
  log?.info(
@@ -816,7 +827,14 @@ var ServerTransport = class extends Transport {
816
827
  (establishedSession) => {
817
828
  session = establishedSession;
818
829
  conn.removeDataListener(bootHandler);
819
- conn.addDataListener((data) => this.handleMsg(this.parseMsg(data)));
830
+ conn.addDataListener((data) => {
831
+ const parsed = this.parseMsg(data);
832
+ if (!parsed) {
833
+ conn.close();
834
+ return;
835
+ }
836
+ this.handleMsg(parsed);
837
+ });
820
838
  }
821
839
  );
822
840
  conn.addDataListener(bootHandler);
@@ -839,8 +857,10 @@ var ServerTransport = class extends Transport {
839
857
  receiveWithBootSequence(conn, sessionCb) {
840
858
  const bootHandler = (data) => {
841
859
  const parsed = this.parseMsg(data);
842
- if (!parsed)
860
+ if (!parsed) {
861
+ conn.close();
843
862
  return;
863
+ }
844
864
  if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
845
865
  const responseMsg2 = bootResponseMessage(
846
866
  this.clientId,
@@ -856,8 +876,9 @@ var ServerTransport = class extends Transport {
856
876
  );
857
877
  return;
858
878
  }
879
+ const instanceId = parsed.payload.instanceId;
859
880
  log?.debug(
860
- `${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
881
+ `${this.clientId} -- handshake from ${parsed.from} ok (instance id: ${instanceId}), responding with handshake success`
861
882
  );
862
883
  const responseMsg = bootResponseMessage(
863
884
  this.clientId,
@@ -866,7 +887,7 @@ var ServerTransport = class extends Transport {
866
887
  true
867
888
  );
868
889
  conn.send(this.codec.toBuffer(responseMsg));
869
- sessionCb(this.onConnect(conn, parsed.from));
890
+ sessionCb(this.onConnect(conn, parsed.from, instanceId));
870
891
  };
871
892
  return bootHandler;
872
893
  }
@@ -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-CT57CKBS.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.2",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {