@replit/river 0.207.3 → 0.208.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 (52) hide show
  1. package/dist/{adapter-f2b6e211.d.ts → adapter-ChksXKVN.d.ts} +2 -2
  2. package/dist/adapter-Cuc4JtfV.d.cts +46 -0
  3. package/dist/{chunk-BO7MFCO6.js → chunk-2JNVDUMN.js} +55 -97
  4. package/dist/chunk-2JNVDUMN.js.map +1 -0
  5. package/dist/{chunk-B7REV3ZV.js → chunk-DKW3GC3M.js} +2 -2
  6. package/dist/{chunk-QGPYCXV4.js → chunk-ETZAHFGQ.js} +80 -61
  7. package/dist/chunk-ETZAHFGQ.js.map +1 -0
  8. package/dist/codec/index.d.cts +3 -3
  9. package/dist/codec/index.d.ts +3 -3
  10. package/dist/codec/index.js +2 -2
  11. package/dist/connection-BF4zg6Qv.d.cts +35 -0
  12. package/dist/{connection-06d72f2e.d.ts → connection-Donr3JRB.d.ts} +4 -4
  13. package/dist/index-C9tpZjBN.d.cts +37 -0
  14. package/dist/{index-02554794.d.ts → index-D8IOd3LG.d.ts} +2 -2
  15. package/dist/logging/index.d.cts +2 -2
  16. package/dist/logging/index.d.ts +2 -2
  17. package/dist/{message-01c3e85a.d.ts → message-Di94OL80.d.cts} +1 -1
  18. package/dist/message-Di94OL80.d.ts +108 -0
  19. package/dist/router/index.cjs +62 -43
  20. package/dist/router/index.cjs.map +1 -1
  21. package/dist/router/index.d.cts +27 -8
  22. package/dist/router/index.d.ts +27 -8
  23. package/dist/router/index.js +1 -1
  24. package/dist/testUtil/index.cjs +56 -105
  25. package/dist/testUtil/index.cjs.map +1 -1
  26. package/dist/testUtil/index.d.cts +5 -5
  27. package/dist/testUtil/index.d.ts +5 -5
  28. package/dist/testUtil/index.js +7 -14
  29. package/dist/testUtil/index.js.map +1 -1
  30. package/dist/transport/impls/ws/client.cjs +51 -80
  31. package/dist/transport/impls/ws/client.cjs.map +1 -1
  32. package/dist/transport/impls/ws/client.d.cts +6 -6
  33. package/dist/transport/impls/ws/client.d.ts +6 -6
  34. package/dist/transport/impls/ws/client.js +3 -3
  35. package/dist/transport/impls/ws/server.cjs +52 -85
  36. package/dist/transport/impls/ws/server.cjs.map +1 -1
  37. package/dist/transport/impls/ws/server.d.cts +6 -6
  38. package/dist/transport/impls/ws/server.d.ts +6 -6
  39. package/dist/transport/impls/ws/server.js +3 -3
  40. package/dist/transport/index.cjs +52 -94
  41. package/dist/transport/index.cjs.map +1 -1
  42. package/dist/transport/index.d.cts +6 -6
  43. package/dist/transport/index.d.ts +6 -6
  44. package/dist/transport/index.js +3 -3
  45. package/dist/transport-CCaWx1Rb.d.cts +1566 -0
  46. package/dist/{services-87887bc5.d.ts → transport-CZb3vdB4.d.ts} +344 -347
  47. package/dist/{wslike-e0b32dd5.d.ts → wslike-Dng9H1C7.d.cts} +1 -1
  48. package/dist/wslike-Dng9H1C7.d.ts +40 -0
  49. package/package.json +3 -3
  50. package/dist/chunk-BO7MFCO6.js.map +0 -1
  51. package/dist/chunk-QGPYCXV4.js.map +0 -1
  52. /package/dist/{chunk-B7REV3ZV.js.map → chunk-DKW3GC3M.js.map} +0 -0
@@ -0,0 +1,108 @@
1
+ import * as _sinclair_typebox from '@sinclair/typebox';
2
+ import { TSchema } from '@sinclair/typebox';
3
+ import { Span, Context } from '@opentelemetry/api';
4
+
5
+ interface PropagationContext {
6
+ traceparent: string;
7
+ tracestate: string;
8
+ }
9
+ interface TelemetryInfo {
10
+ span: Span;
11
+ ctx: Context;
12
+ }
13
+
14
+ /**
15
+ * Generic Typebox schema for a transport message.
16
+ * @template T The type of the payload.
17
+ * @param {T} t The payload schema.
18
+ * @returns The transport message schema.
19
+ */
20
+ declare const TransportMessageSchema: <T extends TSchema>(t: T) => _sinclair_typebox.TObject<{
21
+ id: _sinclair_typebox.TString;
22
+ from: _sinclair_typebox.TString;
23
+ to: _sinclair_typebox.TString;
24
+ seq: _sinclair_typebox.TInteger;
25
+ ack: _sinclair_typebox.TInteger;
26
+ serviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
27
+ procedureName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
28
+ streamId: _sinclair_typebox.TString;
29
+ controlFlags: _sinclair_typebox.TInteger;
30
+ tracing: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
31
+ traceparent: _sinclair_typebox.TString;
32
+ tracestate: _sinclair_typebox.TString;
33
+ }>>;
34
+ payload: T;
35
+ }>;
36
+ type ProtocolVersion = 'v1.1' | 'v2.0';
37
+ declare const HandshakeErrorCustomHandlerFatalResponseCodes: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"REJECTED_UNSUPPORTED_CLIENT">, _sinclair_typebox.TLiteral<"REJECTED_BY_CUSTOM_HANDLER">]>;
38
+ declare const HandshakeErrorResponseCodes: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"SESSION_STATE_MISMATCH">, _sinclair_typebox.TUnion<[_sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"REJECTED_UNSUPPORTED_CLIENT">, _sinclair_typebox.TLiteral<"REJECTED_BY_CUSTOM_HANDLER">]>, _sinclair_typebox.TLiteral<"MALFORMED_HANDSHAKE_META">, _sinclair_typebox.TLiteral<"MALFORMED_HANDSHAKE">, _sinclair_typebox.TLiteral<"PROTOCOL_VERSION_MISMATCH">]>]>;
39
+ /**
40
+ * Defines the schema for an opaque transport message that is agnostic to any
41
+ * procedure/service.
42
+ * @returns The transport message schema.
43
+ */
44
+ declare const OpaqueTransportMessageSchema: _sinclair_typebox.TObject<{
45
+ id: _sinclair_typebox.TString;
46
+ from: _sinclair_typebox.TString;
47
+ to: _sinclair_typebox.TString;
48
+ seq: _sinclair_typebox.TInteger;
49
+ ack: _sinclair_typebox.TInteger;
50
+ serviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
51
+ procedureName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
52
+ streamId: _sinclair_typebox.TString;
53
+ controlFlags: _sinclair_typebox.TInteger;
54
+ tracing: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
55
+ traceparent: _sinclair_typebox.TString;
56
+ tracestate: _sinclair_typebox.TString;
57
+ }>>;
58
+ payload: _sinclair_typebox.TUnknown;
59
+ }>;
60
+ /**
61
+ * Represents a transport message. This is the same type as {@link TransportMessageSchema} but
62
+ * we can't statically infer generics from generic Typebox schemas so we have to define it again here.
63
+ *
64
+ * TypeScript can't enforce types when a bitmask is involved, so these are the semantics of
65
+ * `controlFlags`:
66
+ * * If `controlFlags & StreamOpenBit == StreamOpenBit`, `streamId` must be set to a unique value
67
+ * (suggestion: use `nanoid`).
68
+ * * If `controlFlags & StreamOpenBit == StreamOpenBit`, `serviceName` and `procedureName` must be set.
69
+ * * If `controlFlags & StreamClosedBit == StreamClosedBit` and the kind is `stream` or `subscription`,
70
+ * `payload` should be discarded (usually contains a control message).
71
+ * * If `controlFlags & AckBit == AckBit`, the message is an explicit acknowledgement message and doesn't
72
+ * contain any payload that is relevant to the application so should not be delivered.
73
+ * @template Payload The type of the payload.
74
+ */
75
+ interface TransportMessage<Payload = unknown> {
76
+ id: string;
77
+ from: TransportClientId;
78
+ to: TransportClientId;
79
+ seq: number;
80
+ ack: number;
81
+ serviceName?: string;
82
+ procedureName?: string;
83
+ streamId: string;
84
+ controlFlags: number;
85
+ tracing?: PropagationContext;
86
+ payload: Payload;
87
+ }
88
+ type PartialTransportMessage<Payload = unknown> = Omit<TransportMessage<Payload>, 'id' | 'from' | 'to' | 'seq' | 'ack'>;
89
+ /**
90
+ * A type alias for a transport message with an opaque payload.
91
+ * @template T - The type of the opaque payload.
92
+ */
93
+ type OpaqueTransportMessage = TransportMessage;
94
+ type TransportClientId = string;
95
+ /**
96
+ * Checks if the given control flag (usually found in msg.controlFlag) is a stream open message.
97
+ * @param controlFlag - The control flag to check.
98
+ * @returns True if the control flag contains the StreamOpenBit, false otherwise.
99
+ */
100
+ declare function isStreamOpen(controlFlag: number): boolean;
101
+ /**
102
+ * Checks if the given control flag (usually found in msg.controlFlag) is a stream close message.
103
+ * @param controlFlag - The control flag to check.
104
+ * @returns True if the control flag contains the StreamCloseBit, false otherwise.
105
+ */
106
+ declare function isStreamClose(controlFlag: number): boolean;
107
+
108
+ export { HandshakeErrorCustomHandlerFatalResponseCodes as H, type OpaqueTransportMessage as O, type ProtocolVersion as P, type TransportClientId as T, type PartialTransportMessage as a, type TelemetryInfo as b, type TransportMessage as c, HandshakeErrorResponseCodes as d, TransportMessageSchema as e, OpaqueTransportMessageSchema as f, isStreamClose as g, isStreamOpen as i };
@@ -68,10 +68,11 @@ function castTypeboxValueErrors(errors) {
68
68
  }
69
69
  return result;
70
70
  }
71
- var CancelResultSchema = import_typebox.Type.Object({
71
+ var CancelErrorSchema = import_typebox.Type.Object({
72
72
  code: import_typebox.Type.Literal(CANCEL_CODE),
73
73
  message: import_typebox.Type.String()
74
74
  });
75
+ var CancelResultSchema = ErrResultSchema(CancelErrorSchema);
75
76
  var ReaderErrorSchema = import_typebox.Type.Union([
76
77
  import_typebox.Type.Object({
77
78
  code: import_typebox.Type.Literal(UNCAUGHT_ERROR_CODE),
@@ -91,8 +92,9 @@ var ReaderErrorSchema = import_typebox.Type.Union([
91
92
  })
92
93
  )
93
94
  }),
94
- CancelResultSchema
95
+ CancelErrorSchema
95
96
  ]);
97
+ var ReaderErrorResultSchema = ErrResultSchema(ReaderErrorSchema);
96
98
  function isUnion(schema) {
97
99
  return schema[import_typebox.Kind] === "Union";
98
100
  }
@@ -900,15 +902,13 @@ var WritableImpl = class {
900
902
 
901
903
  // router/client.ts
902
904
  var import_value = require("@sinclair/typebox/value");
903
- var ReaderErrResultSchema = ErrResultSchema(ReaderErrorSchema);
904
905
  var noop = () => {
905
906
  };
906
907
  function _createRecursiveProxy(callback, path) {
907
908
  const proxy = new Proxy(noop, {
908
909
  // property access, recurse and add field to path
909
910
  get(_obj, key) {
910
- if (typeof key !== "string")
911
- return void 0;
911
+ if (typeof key !== "string") return void 0;
912
912
  return _createRecursiveProxy(callback, [...path, key]);
913
913
  },
914
914
  // hit the end, let's invoke the handler
@@ -1037,8 +1037,7 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1037
1037
  );
1038
1038
  }
1039
1039
  function onMessage(msg) {
1040
- if (msg.streamId !== streamId)
1041
- return;
1040
+ if (msg.streamId !== streamId) return;
1042
1041
  if (msg.to !== transport.clientId) {
1043
1042
  transport.log?.error("got stream message from unexpected client", {
1044
1043
  clientId: transport.clientId,
@@ -1050,20 +1049,20 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1050
1049
  cleanClose = false;
1051
1050
  span.addEvent("received cancel");
1052
1051
  let cancelResult;
1053
- if (import_value.Value.Check(ReaderErrResultSchema, msg.payload)) {
1052
+ if (import_value.Value.Check(ReaderErrorResultSchema, msg.payload)) {
1054
1053
  cancelResult = msg.payload;
1055
1054
  } else {
1056
1055
  cancelResult = Err({
1057
1056
  code: CANCEL_CODE,
1058
1057
  message: "stream cancelled with invalid payload"
1059
1058
  });
1060
- transport.log?.error(
1059
+ transport.log?.warn(
1061
1060
  "got stream cancel without a valid protocol error",
1062
1061
  {
1063
1062
  clientId: transport.clientId,
1064
1063
  transportMessage: msg,
1065
1064
  validationErrors: [
1066
- ...import_value.Value.Errors(ReaderErrResultSchema, msg.payload)
1065
+ ...import_value.Value.Errors(ReaderErrorResultSchema, msg.payload)
1067
1066
  ]
1068
1067
  }
1069
1068
  );
@@ -1191,6 +1190,7 @@ var RiverServer = class {
1191
1190
  transport;
1192
1191
  contextMap;
1193
1192
  log;
1193
+ middlewares;
1194
1194
  /**
1195
1195
  * We create a tombstones for streams cancelled by the server
1196
1196
  * so that we don't hit errors when the client has inflight
@@ -1203,8 +1203,9 @@ var RiverServer = class {
1203
1203
  streams;
1204
1204
  services;
1205
1205
  unregisterTransportListeners;
1206
- constructor(transport, services, handshakeOptions, extendedContext, maxCancelledStreamTombstonesPerSession = 200) {
1206
+ constructor(transport, services, handshakeOptions, extendedContext, maxCancelledStreamTombstonesPerSession = 200, middlewares = []) {
1207
1207
  const instances = {};
1208
+ this.middlewares = middlewares;
1208
1209
  this.services = instances;
1209
1210
  this.contextMap = /* @__PURE__ */ new Map();
1210
1211
  for (const [name, service] of Object.entries(services)) {
@@ -1261,8 +1262,7 @@ var RiverServer = class {
1261
1262
  );
1262
1263
  };
1263
1264
  const handleSessionStatus = (evt) => {
1264
- if (evt.status !== "closing")
1265
- return;
1265
+ if (evt.status !== "closing") return;
1266
1266
  const disconnectedClientId = evt.session.to;
1267
1267
  this.log?.info(
1268
1268
  `got session disconnect from ${disconnectedClientId}, cleaning up streams`,
@@ -1276,8 +1276,7 @@ var RiverServer = class {
1276
1276
  this.serverCancelledStreams.delete(disconnectedClientId);
1277
1277
  };
1278
1278
  const handleTransportStatus = (evt) => {
1279
- if (evt.status !== "closed")
1280
- return;
1279
+ if (evt.status !== "closed") return;
1281
1280
  this.unregisterTransportListeners();
1282
1281
  };
1283
1282
  this.unregisterTransportListeners = () => {
@@ -1328,7 +1327,7 @@ var RiverServer = class {
1328
1327
  if (isStreamCancelBackwardsCompat(msg.controlFlags, protocolVersion)) {
1329
1328
  let cancelResult;
1330
1329
  if (import_value2.Value.Check(CancelResultSchema, msg.payload)) {
1331
- cancelResult = Err(msg.payload);
1330
+ cancelResult = msg.payload;
1332
1331
  } else {
1333
1332
  cancelResult = Err({
1334
1333
  code: CANCEL_CODE,
@@ -1524,12 +1523,12 @@ var RiverServer = class {
1524
1523
  if (procClosesWithInit) {
1525
1524
  closeReadable();
1526
1525
  }
1527
- const handlerContextWithSpan = (span2) => ({
1526
+ const handlerContextWithSpan = {
1528
1527
  ...serviceContext,
1529
1528
  from,
1530
1529
  sessionId,
1531
1530
  metadata: sessionMetadata,
1532
- span: span2,
1531
+ span,
1533
1532
  cancel: (message) => {
1534
1533
  const errRes = {
1535
1534
  code: CANCEL_CODE,
@@ -1539,13 +1538,24 @@ var RiverServer = class {
1539
1538
  return Err(errRes);
1540
1539
  },
1541
1540
  signal: finishedController.signal
1542
- });
1543
- switch (procedure.type) {
1544
- case "rpc":
1545
- void (async () => {
1541
+ };
1542
+ const middlewareContext = {
1543
+ ...serviceContext,
1544
+ sessionId,
1545
+ from,
1546
+ metadata: sessionMetadata,
1547
+ span,
1548
+ signal: finishedController.signal,
1549
+ streamId,
1550
+ procedureName,
1551
+ serviceName
1552
+ };
1553
+ const runProcedureHandler = async () => {
1554
+ switch (procedure.type) {
1555
+ case "rpc":
1546
1556
  try {
1547
1557
  const responsePayload = await procedure.handler({
1548
- ctx: handlerContextWithSpan(span),
1558
+ ctx: handlerContextWithSpan,
1549
1559
  reqInit: initPayload
1550
1560
  });
1551
1561
  if (resWritable.isClosed()) {
@@ -1557,13 +1567,11 @@ var RiverServer = class {
1557
1567
  } finally {
1558
1568
  span.end();
1559
1569
  }
1560
- })();
1561
- break;
1562
- case "stream":
1563
- void (async () => {
1570
+ break;
1571
+ case "stream":
1564
1572
  try {
1565
1573
  await procedure.handler({
1566
- ctx: handlerContextWithSpan(span),
1574
+ ctx: handlerContextWithSpan,
1567
1575
  reqInit: initPayload,
1568
1576
  reqReadable,
1569
1577
  resWritable
@@ -1573,13 +1581,11 @@ var RiverServer = class {
1573
1581
  } finally {
1574
1582
  span.end();
1575
1583
  }
1576
- })();
1577
- break;
1578
- case "subscription":
1579
- void (async () => {
1584
+ break;
1585
+ case "subscription":
1580
1586
  try {
1581
1587
  await procedure.handler({
1582
- ctx: handlerContextWithSpan(span),
1588
+ ctx: handlerContextWithSpan,
1583
1589
  reqInit: initPayload,
1584
1590
  resWritable
1585
1591
  });
@@ -1588,13 +1594,11 @@ var RiverServer = class {
1588
1594
  } finally {
1589
1595
  span.end();
1590
1596
  }
1591
- })();
1592
- break;
1593
- case "upload":
1594
- void (async () => {
1597
+ break;
1598
+ case "upload":
1595
1599
  try {
1596
1600
  const responsePayload = await procedure.handler({
1597
- ctx: handlerContextWithSpan(span),
1601
+ ctx: handlerContextWithSpan,
1598
1602
  reqInit: initPayload,
1599
1603
  reqReadable
1600
1604
  });
@@ -1607,9 +1611,23 @@ var RiverServer = class {
1607
1611
  } finally {
1608
1612
  span.end();
1609
1613
  }
1610
- })();
1611
- break;
1612
- }
1614
+ break;
1615
+ }
1616
+ };
1617
+ this.middlewares.reduceRight(
1618
+ (next, middleware) => {
1619
+ return () => {
1620
+ middleware({
1621
+ ctx: middlewareContext,
1622
+ reqInit: initPayload,
1623
+ next
1624
+ });
1625
+ };
1626
+ },
1627
+ () => {
1628
+ void runProcedureHandler();
1629
+ }
1630
+ )();
1613
1631
  if (!finishedController.signal.aborted) {
1614
1632
  this.streams.set(streamId, procStream);
1615
1633
  }
@@ -1860,7 +1878,8 @@ function createServer(transport, services, providedServerOptions) {
1860
1878
  services,
1861
1879
  providedServerOptions?.handshakeOptions,
1862
1880
  providedServerOptions?.extendedContext,
1863
- providedServerOptions?.maxCancelledStreamTombstonesPerSession
1881
+ providedServerOptions?.maxCancelledStreamTombstonesPerSession,
1882
+ providedServerOptions?.middlewares
1864
1883
  );
1865
1884
  }
1866
1885
 
@@ -1873,7 +1892,7 @@ function createServerHandshakeOptions(schema, validate) {
1873
1892
  }
1874
1893
 
1875
1894
  // package.json
1876
- var version = "0.207.3";
1895
+ var version = "0.208.0";
1877
1896
  // Annotate the CommonJS export names for ESM import in node:
1878
1897
  0 && (module.exports = {
1879
1898
  CANCEL_CODE,