@replit/river 0.16.1 → 0.17.0

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 (39) hide show
  1. package/README.md +25 -11
  2. package/dist/{chunk-Q6WPGM3K.js → chunk-7IQO434V.js} +11 -3
  3. package/dist/{chunk-7SPCAA6Q.js → chunk-LQMPJI3S.js} +101 -97
  4. package/dist/{chunk-GFRAOY75.js → chunk-VH3NGOXQ.js} +8 -17
  5. package/dist/{chunk-L65XWBX2.js → chunk-VJRLJ3JU.js} +1 -1
  6. package/dist/{chunk-XLJGKNV2.js → chunk-Y6DLSCKU.js} +1 -1
  7. package/dist/{connection-94896f3b.d.ts → connection-0767dc6b.d.ts} +1 -1
  8. package/dist/{connection-99346822.d.ts → connection-f31edbcd.d.ts} +1 -1
  9. package/dist/{index-2e402bb8.d.ts → index-8df0bdfb.d.ts} +27 -31
  10. package/dist/{procedures-f0226890.d.ts → procedures-b5ddb54d.d.ts} +1 -1
  11. package/dist/router/index.cjs +12 -4
  12. package/dist/router/index.d.cts +8 -4
  13. package/dist/router/index.d.ts +8 -4
  14. package/dist/router/index.js +2 -2
  15. package/dist/transport/impls/uds/client.cjs +80 -69
  16. package/dist/transport/impls/uds/client.d.cts +2 -2
  17. package/dist/transport/impls/uds/client.d.ts +2 -2
  18. package/dist/transport/impls/uds/client.js +3 -3
  19. package/dist/transport/impls/uds/server.cjs +82 -94
  20. package/dist/transport/impls/uds/server.d.cts +2 -2
  21. package/dist/transport/impls/uds/server.d.ts +2 -2
  22. package/dist/transport/impls/uds/server.js +3 -3
  23. package/dist/transport/impls/ws/client.cjs +80 -69
  24. package/dist/transport/impls/ws/client.d.cts +2 -2
  25. package/dist/transport/impls/ws/client.d.ts +2 -2
  26. package/dist/transport/impls/ws/client.js +3 -3
  27. package/dist/transport/impls/ws/server.cjs +82 -94
  28. package/dist/transport/impls/ws/server.d.cts +2 -2
  29. package/dist/transport/impls/ws/server.d.ts +2 -2
  30. package/dist/transport/impls/ws/server.js +3 -3
  31. package/dist/transport/index.cjs +107 -115
  32. package/dist/transport/index.d.cts +1 -1
  33. package/dist/transport/index.d.ts +1 -1
  34. package/dist/transport/index.js +2 -2
  35. package/dist/util/testHelpers.cjs +45 -18
  36. package/dist/util/testHelpers.d.cts +4 -9
  37. package/dist/util/testHelpers.d.ts +4 -9
  38. package/dist/util/testHelpers.js +8 -14
  39. package/package.json +1 -1
@@ -51,18 +51,18 @@ var ControlMessageAckSchema = import_typebox.Type.Object({
51
51
  var ControlMessageCloseSchema = import_typebox.Type.Object({
52
52
  type: import_typebox.Type.Literal("CLOSE")
53
53
  });
54
- var PROTOCOL_VERSION = "v1";
54
+ var PROTOCOL_VERSION = "v1.1";
55
55
  var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
56
56
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
57
57
  protocolVersion: import_typebox.Type.String(),
58
- instanceId: import_typebox.Type.String()
58
+ sessionId: import_typebox.Type.String()
59
59
  });
60
60
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
61
61
  type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
62
62
  status: import_typebox.Type.Union([
63
63
  import_typebox.Type.Object({
64
64
  ok: import_typebox.Type.Literal(true),
65
- instanceId: import_typebox.Type.String()
65
+ sessionId: import_typebox.Type.String()
66
66
  }),
67
67
  import_typebox.Type.Object({
68
68
  ok: import_typebox.Type.Literal(false),
@@ -79,7 +79,7 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
79
79
  var OpaqueTransportMessageSchema = TransportMessageSchema(
80
80
  import_typebox.Type.Unknown()
81
81
  );
82
- function handshakeResponseMessage(from, instanceId, to, ok, reason) {
82
+ function handshakeResponseMessage(from, to, status) {
83
83
  return {
84
84
  id: (0, import_nanoid.nanoid)(),
85
85
  from,
@@ -88,18 +88,9 @@ function handshakeResponseMessage(from, instanceId, to, ok, reason) {
88
88
  ack: 0,
89
89
  streamId: (0, import_nanoid.nanoid)(),
90
90
  controlFlags: 0,
91
- payload: ok ? {
91
+ payload: {
92
92
  type: "HANDSHAKE_RESP",
93
- status: {
94
- ok: true,
95
- instanceId
96
- }
97
- } : {
98
- type: "HANDSHAKE_RESP",
99
- status: {
100
- ok: false,
101
- reason: reason ?? "Unknown reason"
102
- }
93
+ status
103
94
  }
104
95
  };
105
96
  }
@@ -111,7 +102,8 @@ function isAck(controlFlag) {
111
102
  var ProtocolError = {
112
103
  RetriesExceeded: "conn_retry_exceeded",
113
104
  HandshakeFailed: "handshake_failed",
114
- UseAfterDestroy: "use_after_destroy"
105
+ UseAfterDestroy: "use_after_destroy",
106
+ MessageOrderingViolated: "message_ordering_violated"
115
107
  };
116
108
  var EventDispatcher = class {
117
109
  eventListeners = {};
@@ -166,7 +158,12 @@ var Session = class {
166
158
  /**
167
159
  * The unique ID of this session.
168
160
  */
169
- debugId;
161
+ id;
162
+ /**
163
+ * What the other side advertised as their session ID
164
+ * for this session.
165
+ */
166
+ advertisedSessionId;
170
167
  /**
171
168
  * Number of messages we've sent along this session (excluding handshake and acks)
172
169
  */
@@ -188,11 +185,11 @@ var Session = class {
188
185
  * The interval for sending heartbeats.
189
186
  */
190
187
  heartbeat;
191
- constructor(from, connectedTo, conn, options) {
188
+ constructor(conn, from, to, options) {
189
+ this.id = `session-${nanoid2(12)}`;
192
190
  this.options = options;
193
- this.debugId = `sess-${unsafeId()}`;
194
191
  this.from = from;
195
- this.to = connectedTo;
192
+ this.to = to;
196
193
  this.connection = conn;
197
194
  this.codec = options.codec;
198
195
  this.heartbeatMisses = 0;
@@ -232,7 +229,7 @@ var Session = class {
232
229
  log?.info(
233
230
  `${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
234
231
  );
235
- this.closeStaleConnection(this.connection);
232
+ this.closeStaleConnection();
236
233
  }
237
234
  return;
238
235
  }
@@ -263,33 +260,37 @@ var Session = class {
263
260
  log?.debug(`${this.from} -- resending ${msg.id} (seq: ${msg.seq})`);
264
261
  const ok = this.connection.send(this.codec.toBuffer(msg));
265
262
  if (!ok) {
266
- const msg2 = `${this.from} -- failed to send buffered message to ${this.to} in session (id: ${this.debugId}) (if you hit this code path something is seriously wrong)`;
263
+ const msg2 = `${this.from} -- failed to send buffered message to ${this.to} in session (id: ${this.id}) (if you hit this code path something is seriously wrong)`;
267
264
  log?.error(msg2);
268
265
  throw new Error(msg2);
269
266
  }
270
267
  }
271
268
  }
272
269
  updateBookkeeping(ack, seq) {
270
+ if (seq + 1 < this.ack) {
271
+ log?.error(`${this.from} -- received stale seq ${seq} + 1 < ${this.ack}`);
272
+ return;
273
+ }
273
274
  this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
274
275
  this.ack = seq + 1;
275
276
  }
276
277
  closeStaleConnection(conn) {
277
- if (!this.connection || this.connection !== conn)
278
+ if (this.connection === void 0 || this.connection === conn)
278
279
  return;
279
280
  log?.info(
280
- `${this.from} -- closing old inner connection (id: ${this.connection.debugId}) from session (id: ${this.debugId}) to ${this.to}`
281
+ `${this.from} -- closing old inner connection (id: ${this.connection.debugId}) from session (id: ${this.id}) to ${this.to}`
281
282
  );
282
283
  this.connection.close();
283
284
  this.connection = void 0;
284
285
  }
285
286
  replaceWithNewConnection(newConn) {
286
- this.closeStaleConnection(this.connection);
287
+ this.closeStaleConnection(newConn);
287
288
  this.cancelGrace();
288
289
  this.connection = newConn;
289
290
  }
290
291
  beginGrace(cb) {
291
292
  log?.info(
292
- `${this.from} -- starting ${this.options.sessionDisconnectGraceMs}ms grace period until session (id: ${this.debugId}) to ${this.to} is closed`
293
+ `${this.from} -- starting ${this.options.sessionDisconnectGraceMs}ms grace period until session (id: ${this.id}) to ${this.to} is closed`
293
294
  );
294
295
  this.disconnectionGrace = setTimeout(() => {
295
296
  this.close();
@@ -300,11 +301,12 @@ var Session = class {
300
301
  cancelGrace() {
301
302
  this.heartbeatMisses = 0;
302
303
  clearTimeout(this.disconnectionGrace);
304
+ this.disconnectionGrace = void 0;
303
305
  }
304
306
  // closed when we want to discard the whole session
305
307
  // (i.e. shutdown or session disconnect)
306
308
  close() {
307
- this.closeStaleConnection(this.connection);
309
+ this.closeStaleConnection();
308
310
  this.cancelGrace();
309
311
  this.resetBufferedMessages();
310
312
  clearInterval(this.heartbeat);
@@ -333,9 +335,6 @@ var Session = class {
333
335
  }
334
336
  };
335
337
 
336
- // transport/transport.ts
337
- var import_nanoid3 = require("nanoid");
338
-
339
338
  // util/stringify.ts
340
339
  function coerceErrorString(err) {
341
340
  if (err instanceof Error) {
@@ -411,17 +410,10 @@ var defaultConnectionRetryOptions = {
411
410
  budgetRestoreIntervalMs: 200
412
411
  };
413
412
  var defaultClientTransportOptions = {
414
- connectionRetryOptions: defaultConnectionRetryOptions,
415
- ...defaultTransportOptions
413
+ ...defaultTransportOptions,
414
+ ...defaultConnectionRetryOptions
416
415
  };
417
416
  var Transport = class {
418
- /**
419
- * Unique per instance of the transport.
420
- * This allows us to distinguish reconnects to different
421
- * transports.
422
- */
423
- instanceId = (0, import_nanoid3.nanoid)();
424
- connectedInstanceIds = /* @__PURE__ */ new Map();
425
417
  /**
426
418
  * A flag indicating whether the transport has been destroyed.
427
419
  * A destroyed transport will not attempt to reconnect and cannot be used again.
@@ -474,41 +466,41 @@ var Transport = class {
474
466
  * and we know the identity of the connected client.
475
467
  * @param conn The connection object.
476
468
  */
477
- onConnect(conn, connectedTo, instanceId) {
469
+ onConnect(conn, connectedTo, advertisedSessionId) {
478
470
  this.eventDispatcher.dispatchEvent("connectionStatus", {
479
471
  status: "connect",
480
472
  conn
481
473
  });
482
474
  let oldSession = this.sessions.get(connectedTo);
483
- const lastInstanceId = this.connectedInstanceIds.get(connectedTo);
484
- if (oldSession && lastInstanceId !== void 0 && lastInstanceId !== instanceId) {
475
+ if (oldSession?.advertisedSessionId && oldSession.advertisedSessionId !== advertisedSessionId) {
485
476
  log?.warn(
486
- `${this.clientId} -- connection from ${connectedTo} is a different instance (got: ${instanceId}, last connected to: ${lastInstanceId}), starting a new session`
477
+ `${this.clientId} -- connection from ${connectedTo} is a different session (id: ${advertisedSessionId}, last connected to: ${oldSession.advertisedSessionId}), starting a new session`
487
478
  );
488
479
  oldSession.close();
489
480
  this.deleteSession(oldSession);
490
481
  oldSession = void 0;
491
482
  }
492
- this.connectedInstanceIds.set(connectedTo, instanceId);
493
483
  if (oldSession === void 0) {
494
484
  const newSession = this.createSession(connectedTo, conn);
485
+ newSession.advertisedSessionId = advertisedSessionId;
495
486
  log?.info(
496
- `${this.clientId} -- new connection (id: ${conn.debugId}) for new session (id: ${newSession.debugId}) to ${connectedTo}`
487
+ `${this.clientId} -- new connection (id: ${conn.debugId}) for new session (id: ${newSession.id}) to ${connectedTo}`
497
488
  );
498
489
  return newSession;
499
490
  }
500
491
  log?.info(
501
- `${this.clientId} -- new connection (id: ${conn.debugId}) for existing session (id: ${oldSession.debugId}) to ${connectedTo}`
492
+ `${this.clientId} -- new connection (id: ${conn.debugId}) for existing session (id: ${oldSession.id}) to ${connectedTo}`
502
493
  );
503
494
  oldSession.replaceWithNewConnection(conn);
504
495
  oldSession.sendBufferedMessages();
496
+ oldSession.advertisedSessionId = advertisedSessionId;
505
497
  return oldSession;
506
498
  }
507
- createSession(connectedTo, conn) {
499
+ createSession(to, conn) {
508
500
  const session = new Session(
509
- this.clientId,
510
- connectedTo,
511
501
  conn,
502
+ this.clientId,
503
+ to,
512
504
  this.options
513
505
  );
514
506
  this.sessions.set(session.to, session);
@@ -518,10 +510,20 @@ var Transport = class {
518
510
  });
519
511
  return session;
520
512
  }
513
+ getOrCreateSession(to, conn) {
514
+ let session = this.sessions.get(to);
515
+ if (!session) {
516
+ session = this.createSession(to, conn);
517
+ log?.info(
518
+ `${this.clientId} -- no session for ${to}, created a new one (id: ${session.id})`
519
+ );
520
+ }
521
+ return session;
522
+ }
521
523
  deleteSession(session) {
522
524
  this.sessions.delete(session.to);
523
525
  log?.info(
524
- `${this.clientId} -- session ${session.debugId} disconnect from ${session.to}`
526
+ `${this.clientId} -- session ${session.id} disconnect from ${session.to}`
525
527
  );
526
528
  this.eventDispatcher.dispatchEvent("sessionStatus", {
527
529
  status: "disconnect",
@@ -589,11 +591,14 @@ var Transport = class {
589
591
  )}`
590
592
  );
591
593
  } else {
594
+ const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;
592
595
  log?.error(
593
- `${this.clientId} -- received out-of-order msg (got: ${msg.seq}, wanted: ${session.nextExpectedSeq}), marking connection as dead: ${JSON.stringify(msg)}`
596
+ `${this.clientId} -- fatal: ${errMsg}, marking connection as dead: ${JSON.stringify(
597
+ msg
598
+ )}`
594
599
  );
600
+ this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
595
601
  session.close();
596
- this.deleteSession(session);
597
602
  }
598
603
  return;
599
604
  }
@@ -640,14 +645,7 @@ var Transport = class {
640
645
  );
641
646
  return void 0;
642
647
  }
643
- let session = this.sessions.get(to);
644
- if (!session) {
645
- session = this.createSession(to, void 0);
646
- log?.info(
647
- `${this.clientId} -- no session for ${to}, created a new one (id: ${session.debugId})`
648
- );
649
- }
650
- return session.send(msg);
648
+ return this.getOrCreateSession(to).send(msg);
651
649
  }
652
650
  // control helpers
653
651
  sendCloseStream(to, streamId) {
@@ -693,7 +691,7 @@ var ServerTransport = class extends Transport {
693
691
  constructor(clientId, providedOptions) {
694
692
  super(clientId, providedOptions);
695
693
  log?.info(
696
- `${this.clientId} -- initiated server transport (instance id: ${this.instanceId}, protocol: ${PROTOCOL_VERSION})`
694
+ `${this.clientId} -- initiated server transport (protocol: ${PROTOCOL_VERSION})`
697
695
  );
698
696
  }
699
697
  handleConnection(conn) {
@@ -705,12 +703,13 @@ var ServerTransport = class extends Transport {
705
703
  let session = void 0;
706
704
  const client = () => session?.to ?? "unknown";
707
705
  const handshakeHandler = (data) => {
708
- const handshake = this.receiveHandshakeRequestMessage(data, conn);
709
- if (!handshake) {
706
+ const maybeSession = this.receiveHandshakeRequestMessage(data, conn);
707
+ if (!maybeSession) {
710
708
  conn.close();
711
709
  return;
710
+ } else {
711
+ session = maybeSession;
712
712
  }
713
- session = this.onConnect(conn, handshake.from, handshake.instanceId);
714
713
  conn.removeDataListener(handshakeHandler);
715
714
  conn.addDataListener((data2) => {
716
715
  const parsed = this.parseMsg(data2);
@@ -748,18 +747,13 @@ var ServerTransport = class extends Transport {
748
747
  return false;
749
748
  }
750
749
  if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
751
- const responseMsg2 = handshakeResponseMessage(
752
- this.clientId,
753
- this.instanceId,
754
- parsed.from,
755
- false
756
- );
750
+ const reason = "received invalid handshake msg";
751
+ const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
752
+ ok: false,
753
+ reason
754
+ });
757
755
  conn.send(this.codec.toBuffer(responseMsg2));
758
- log?.warn(
759
- `${this.clientId} -- received invalid handshake msg: ${JSON.stringify(
760
- parsed
761
- )}`
762
- );
756
+ log?.warn(`${this.clientId} -- ${reason}: ${JSON.stringify(parsed)}`);
763
757
  this.protocolError(
764
758
  ProtocolError.HandshakeFailed,
765
759
  "invalid handshake request"
@@ -768,34 +762,28 @@ var ServerTransport = class extends Transport {
768
762
  }
769
763
  const gotVersion = parsed.payload.protocolVersion;
770
764
  if (gotVersion !== PROTOCOL_VERSION) {
771
- const responseMsg2 = handshakeResponseMessage(
772
- this.clientId,
773
- this.instanceId,
774
- parsed.from,
775
- false
776
- );
765
+ const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
766
+ const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
767
+ ok: false,
768
+ reason
769
+ });
777
770
  conn.send(this.codec.toBuffer(responseMsg2));
778
771
  log?.warn(
779
772
  `${this.clientId} -- received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`
780
773
  );
781
- this.protocolError(
782
- ProtocolError.HandshakeFailed,
783
- `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`
784
- );
774
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
785
775
  return false;
786
776
  }
787
- const instanceId = parsed.payload.instanceId;
777
+ const session = this.getOrCreateSession(parsed.from, conn);
788
778
  log?.debug(
789
- `${this.clientId} -- handshake from ${parsed.from} ok (instance id: ${instanceId}), responding with handshake success`
790
- );
791
- const responseMsg = handshakeResponseMessage(
792
- this.clientId,
793
- this.instanceId,
794
- parsed.from,
795
- true
779
+ `${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
796
780
  );
781
+ const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
782
+ ok: true,
783
+ sessionId: session.id
784
+ });
797
785
  conn.send(this.codec.toBuffer(responseMsg));
798
- return { instanceId, from: parsed.from };
786
+ return this.onConnect(conn, parsed.from, parsed.payload.sessionId);
799
787
  }
800
788
  };
801
789
 
@@ -1,6 +1,6 @@
1
1
  import { Server, Socket } from 'node:net';
2
- import { S as ServerTransport, b as TransportClientId, d as ProvidedTransportOptions } from '../../../index-2e402bb8.js';
3
- import { U as UdsConnection } from '../../../connection-94896f3b.js';
2
+ import { d as ServerTransport, b as TransportClientId, e as ProvidedTransportOptions } from '../../../index-8df0bdfb.js';
3
+ import { U as UdsConnection } from '../../../connection-0767dc6b.js';
4
4
  import '../../../types-3e5768ec.js';
5
5
  import '@sinclair/typebox';
6
6
  import 'node:stream';
@@ -1,6 +1,6 @@
1
1
  import { Server, Socket } from 'node:net';
2
- import { S as ServerTransport, b as TransportClientId, d as ProvidedTransportOptions } from '../../../index-2e402bb8.js';
3
- import { U as UdsConnection } from '../../../connection-94896f3b.js';
2
+ import { d as ServerTransport, b as TransportClientId, e as ProvidedTransportOptions } from '../../../index-8df0bdfb.js';
3
+ import { U as UdsConnection } from '../../../connection-0767dc6b.js';
4
4
  import '../../../types-3e5768ec.js';
5
5
  import '@sinclair/typebox';
6
6
  import 'node:stream';
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  UdsConnection
3
- } from "../../../chunk-L65XWBX2.js";
3
+ } from "../../../chunk-VJRLJ3JU.js";
4
4
  import {
5
5
  ServerTransport
6
- } from "../../../chunk-7SPCAA6Q.js";
7
- import "../../../chunk-GFRAOY75.js";
6
+ } from "../../../chunk-LQMPJI3S.js";
7
+ import "../../../chunk-VH3NGOXQ.js";
8
8
  import {
9
9
  log
10
10
  } from "../../../chunk-H4BYJELI.js";