@replit/river 0.12.6 → 0.13.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 (51) hide show
  1. package/README.md +4 -1
  2. package/dist/{builder-c593de11.d.ts → builder-169fbf7f.d.ts} +16 -7
  3. package/dist/{chunk-AFLZ6INU.js → chunk-CBRQM65K.js} +29 -10
  4. package/dist/{chunk-IIBVKYDB.js → chunk-CDH7QSB4.js} +39 -1
  5. package/dist/{chunk-XFFS4UOD.js → chunk-MGGIUH5O.js} +7 -7
  6. package/dist/{chunk-VLBVQX5H.js → chunk-NPXAAD7M.js} +1 -1
  7. package/dist/{chunk-4SDJ5VN4.js → chunk-R2IMXRVU.js} +150 -116
  8. package/dist/{connection-ba37d174.d.ts → connection-ab681c08.d.ts} +1 -1
  9. package/dist/{messageFraming-b200ef25.d.ts → connection-dd789651.d.ts} +17 -2
  10. package/dist/{index-54e0f99c.d.ts → index-21c1b21d.d.ts} +29 -13
  11. package/dist/router/index.cjs +31 -13
  12. package/dist/router/index.d.cts +5 -5
  13. package/dist/router/index.d.ts +5 -5
  14. package/dist/router/index.js +2 -2
  15. package/dist/transport/impls/uds/client.cjs +143 -121
  16. package/dist/transport/impls/uds/client.d.cts +2 -3
  17. package/dist/transport/impls/uds/client.d.ts +2 -3
  18. package/dist/transport/impls/uds/client.js +5 -6
  19. package/dist/transport/impls/uds/server.cjs +151 -127
  20. package/dist/transport/impls/uds/server.d.cts +2 -3
  21. package/dist/transport/impls/uds/server.d.ts +2 -3
  22. package/dist/transport/impls/uds/server.js +4 -5
  23. package/dist/transport/impls/ws/client.cjs +147 -123
  24. package/dist/transport/impls/ws/client.d.cts +4 -4
  25. package/dist/transport/impls/ws/client.d.ts +4 -4
  26. package/dist/transport/impls/ws/client.js +7 -7
  27. package/dist/transport/impls/ws/server.cjs +151 -127
  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 +4 -4
  31. package/dist/transport/index.cjs +202 -167
  32. package/dist/transport/index.d.cts +1 -1
  33. package/dist/transport/index.d.ts +1 -1
  34. package/dist/transport/index.js +3 -3
  35. package/dist/util/testHelpers.cjs +294 -16
  36. package/dist/util/testHelpers.d.cts +2 -2
  37. package/dist/util/testHelpers.d.ts +2 -2
  38. package/dist/util/testHelpers.js +30 -8
  39. package/package.json +1 -9
  40. package/dist/chunk-PBPXYLI6.js +0 -44
  41. package/dist/chunk-Q7GL34DZ.js +0 -47
  42. package/dist/connection-1f9971d8.d.ts +0 -17
  43. package/dist/connection-24d878ac.d.ts +0 -18
  44. package/dist/transport/impls/stdio/client.cjs +0 -904
  45. package/dist/transport/impls/stdio/client.d.cts +0 -27
  46. package/dist/transport/impls/stdio/client.d.ts +0 -27
  47. package/dist/transport/impls/stdio/client.js +0 -42
  48. package/dist/transport/impls/stdio/server.cjs +0 -879
  49. package/dist/transport/impls/stdio/server.d.cts +0 -25
  50. package/dist/transport/impls/stdio/server.d.ts +0 -25
  51. package/dist/transport/impls/stdio/server.js +0 -33
package/README.md CHANGED
@@ -8,7 +8,7 @@ It's like tRPC/gRPC but with
8
8
  - result types and error handling
9
9
  - snappy DX (no code-generation)
10
10
  - transparent reconnect support for long-lived sessions
11
- - over any transport (WebSockets, stdio, Unix Domain Socket out of the box)
11
+ - over any transport (WebSockets and Unix Domain Socket out of the box)
12
12
 
13
13
  ## Installation
14
14
 
@@ -47,6 +47,7 @@ import { Type } from '@sinclair/typebox';
47
47
 
48
48
  export const ExampleServiceConstructor = () =>
49
49
  ServiceBuilder.create('example')
50
+ // initializer for shared state
50
51
  .initialState({
51
52
  count: 0,
52
53
  })
@@ -55,7 +56,9 @@ export const ExampleServiceConstructor = () =>
55
56
  input: Type.Object({ n: Type.Number() }),
56
57
  output: Type.Object({ result: Type.Number() }),
57
58
  errors: Type.Never(),
59
+ // note that a handler is unique per user RPC
58
60
  async handler(ctx, { n }) {
61
+ // access and mutate shared state
59
62
  ctx.state.count += n;
60
63
  return Ok({ result: ctx.state.count });
61
64
  },
@@ -1,5 +1,6 @@
1
1
  import { TObject, TUnion, TString, TSchema, TNever, TLiteral, Static } from '@sinclair/typebox';
2
2
  import { Pushable } from 'it-pushable';
3
+ import { b as TransportClientId, d as Session, C as Connection } from './index-21c1b21d.js';
3
4
 
4
5
  /**
5
6
  * The context for services/procedures. This is used only on
@@ -21,6 +22,7 @@ import { Pushable } from 'it-pushable';
21
22
  * }
22
23
  * ```
23
24
  */
25
+
24
26
  interface ServiceContext {
25
27
  }
26
28
  /**
@@ -29,6 +31,13 @@ interface ServiceContext {
29
31
  type ServiceContextWithState<State> = ServiceContext & {
30
32
  state: State;
31
33
  };
34
+ type ServiceContextWithTransportInfo<State> = ServiceContext & {
35
+ state: State;
36
+ to: TransportClientId;
37
+ from: TransportClientId;
38
+ streamId: string;
39
+ session: Session<Connection>;
40
+ };
32
41
 
33
42
  type TLiteralString = TLiteral<string>;
34
43
  type RiverErrorSchema = TObject<{
@@ -145,39 +154,39 @@ type Procedure<State, Ty extends ValidProcType, I extends PayloadType, O extends
145
154
  input: I;
146
155
  output: O;
147
156
  errors: E;
148
- handler: (context: ServiceContextWithState<State>, input: Static<I>) => Promise<Result<Static<O>, Static<E>>>;
157
+ handler: (context: ServiceContextWithTransportInfo<State>, input: Static<I>) => Promise<Result<Static<O>, Static<E>>>;
149
158
  type: Ty;
150
159
  } : never : Ty extends 'upload' ? Init extends PayloadType ? {
151
160
  init: Init;
152
161
  input: I;
153
162
  output: O;
154
163
  errors: E;
155
- handler: (context: ServiceContextWithState<State>, init: Static<Init>, input: AsyncIterableIterator<Static<I>>) => Promise<Result<Static<O>, Static<E>>>;
164
+ handler: (context: ServiceContextWithTransportInfo<State>, init: Static<Init>, input: AsyncIterableIterator<Static<I>>) => Promise<Result<Static<O>, Static<E>>>;
156
165
  type: Ty;
157
166
  } : {
158
167
  input: I;
159
168
  output: O;
160
169
  errors: E;
161
- handler: (context: ServiceContextWithState<State>, input: AsyncIterableIterator<Static<I>>) => Promise<Result<Static<O>, Static<E>>>;
170
+ handler: (context: ServiceContextWithTransportInfo<State>, input: AsyncIterableIterator<Static<I>>) => Promise<Result<Static<O>, Static<E>>>;
162
171
  type: Ty;
163
172
  } : Ty extends 'subscription' ? Init extends null ? {
164
173
  input: I;
165
174
  output: O;
166
175
  errors: E;
167
- handler: (context: ServiceContextWithState<State>, input: Static<I>, output: Pushable<Result<Static<O>, Static<E>>>) => Promise<void>;
176
+ handler: (context: ServiceContextWithTransportInfo<State>, input: Static<I>, output: Pushable<Result<Static<O>, Static<E>>>) => Promise<void>;
168
177
  type: Ty;
169
178
  } : never : Ty extends 'stream' ? Init extends PayloadType ? {
170
179
  init: Init;
171
180
  input: I;
172
181
  output: O;
173
182
  errors: E;
174
- handler: (context: ServiceContextWithState<State>, init: Static<Init>, input: AsyncIterableIterator<Static<I>>, output: Pushable<Result<Static<O>, Static<E>>>) => Promise<void>;
183
+ handler: (context: ServiceContextWithTransportInfo<State>, init: Static<Init>, input: AsyncIterableIterator<Static<I>>, output: Pushable<Result<Static<O>, Static<E>>>) => Promise<void>;
175
184
  type: Ty;
176
185
  } : {
177
186
  input: I;
178
187
  output: O;
179
188
  errors: E;
180
- handler: (context: ServiceContextWithState<State>, input: AsyncIterableIterator<Static<I>>, output: Pushable<Result<Static<O>, Static<E>>>) => Promise<void>;
189
+ handler: (context: ServiceContextWithTransportInfo<State>, input: AsyncIterableIterator<Static<I>>, output: Pushable<Result<Static<O>, Static<E>>>) => Promise<void>;
181
190
  type: Ty;
182
191
  } : never;
183
192
  type AnyProcedure = Procedure<object, ValidProcType, PayloadType, PayloadType, RiverError, PayloadType | null>;
@@ -230,4 +239,4 @@ declare class ServiceBuilder<T extends Service<string, object, ProcListing>> {
230
239
  }>;
231
240
  }
232
241
 
233
- export { AnyService as A, Err as E, Ok as O, PayloadType as P, RiverError as R, ServiceContext as S, UNCAUGHT_ERROR as U, ValidProcType as V, Procedure as a, Result as b, RiverUncaughtSchema as c, ProcType as d, ProcInput as e, ProcOutput as f, ProcErrors as g, ProcHasInit as h, ProcInit as i, ServiceBuilder as j, ProcListing as k, Service as l, ProcHandler as m, ServiceContextWithState as n, RiverErrorSchema as o, serializeService as s };
242
+ export { AnyService as A, Err as E, Ok as O, PayloadType as P, RiverError as R, ServiceContext as S, UNCAUGHT_ERROR as U, ValidProcType as V, Procedure as a, Result as b, RiverUncaughtSchema as c, ProcType as d, ProcInput as e, ProcOutput as f, ProcErrors as g, ProcHasInit as h, ProcInit as i, ServiceBuilder as j, ProcListing as k, Service as l, ProcHandler as m, ServiceContextWithState as n, ServiceContextWithTransportInfo as o, RiverErrorSchema as p, serializeService as s };
@@ -3,7 +3,7 @@ import {
3
3
  coerceErrorString,
4
4
  isStreamClose,
5
5
  isStreamOpen
6
- } from "./chunk-XFFS4UOD.js";
6
+ } from "./chunk-MGGIUH5O.js";
7
7
  import {
8
8
  log
9
9
  } from "./chunk-H4BYJELI.js";
@@ -429,7 +429,8 @@ function _createRecursiveProxy(callback, path) {
429
429
  });
430
430
  return proxy;
431
431
  }
432
- var createClient = (transport, serverId = "SERVER") => _createRecursiveProxy(async (opts) => {
432
+ var createClient = (transport) => _createRecursiveProxy(async (opts) => {
433
+ const serverId = transport.connectedTo;
433
434
  const [serviceName, procName, procType] = [...opts.path];
434
435
  if (!(serviceName && procName && procType)) {
435
436
  throw new Error(
@@ -781,7 +782,13 @@ var RiverServer = class {
781
782
  );
782
783
  return;
783
784
  }
784
- if (!message.serviceName || !(message.serviceName in this.services)) {
785
+ if (!message.procedureName || !message.serviceName) {
786
+ log?.warn(
787
+ `${this.transport.clientId} -- missing procedure or service name in stream open message`
788
+ );
789
+ return;
790
+ }
791
+ if (!(message.serviceName in this.services)) {
785
792
  log?.warn(
786
793
  `${this.transport.clientId} -- couldn't find service ${message.serviceName}`
787
794
  );
@@ -789,7 +796,7 @@ var RiverServer = class {
789
796
  }
790
797
  const service = this.services[message.serviceName];
791
798
  const serviceContext = this.getContext(service);
792
- if (!message.procedureName || !(message.procedureName in service.procedures)) {
799
+ if (!(message.procedureName in service.procedures)) {
793
800
  log?.warn(
794
801
  `${this.transport.clientId} -- couldn't find a matching procedure for ${message.serviceName}.${message.procedureName}`
795
802
  );
@@ -835,6 +842,13 @@ var RiverServer = class {
835
842
  };
836
843
  let inputHandler;
837
844
  const procHasInitMessage = "init" in procedure;
845
+ const serviceContextWithTransportInfo = {
846
+ ...serviceContext,
847
+ to: message.to,
848
+ from: message.from,
849
+ streamId: message.streamId,
850
+ session
851
+ };
838
852
  switch (procedure.type) {
839
853
  case "rpc":
840
854
  inputHandler = (async () => {
@@ -844,7 +858,7 @@ var RiverServer = class {
844
858
  }
845
859
  try {
846
860
  const outputMessage = await procedure.handler(
847
- serviceContext,
861
+ serviceContextWithTransportInfo,
848
862
  inputMessage.value
849
863
  );
850
864
  outgoing.push(outputMessage);
@@ -860,10 +874,15 @@ var RiverServer = class {
860
874
  if (initMessage.done) {
861
875
  return;
862
876
  }
863
- return procedure.handler(serviceContext, initMessage.value, incoming, outgoing).catch(errorHandler);
877
+ return procedure.handler(
878
+ serviceContextWithTransportInfo,
879
+ initMessage.value,
880
+ incoming,
881
+ outgoing
882
+ ).catch(errorHandler);
864
883
  })();
865
884
  } else {
866
- inputHandler = procedure.handler(serviceContext, incoming, outgoing).catch(errorHandler);
885
+ inputHandler = procedure.handler(serviceContextWithTransportInfo, incoming, outgoing).catch(errorHandler);
867
886
  }
868
887
  break;
869
888
  case "subscription":
@@ -874,7 +893,7 @@ var RiverServer = class {
874
893
  }
875
894
  try {
876
895
  await procedure.handler(
877
- serviceContext,
896
+ serviceContextWithTransportInfo,
878
897
  inputMessage.value,
879
898
  outgoing
880
899
  );
@@ -892,7 +911,7 @@ var RiverServer = class {
892
911
  }
893
912
  try {
894
913
  const outputMessage = await procedure.handler(
895
- serviceContext,
914
+ serviceContextWithTransportInfo,
896
915
  initMessage.value,
897
916
  incoming
898
917
  );
@@ -907,7 +926,7 @@ var RiverServer = class {
907
926
  inputHandler = (async () => {
908
927
  try {
909
928
  const outputMessage = await procedure.handler(
910
- serviceContext,
929
+ serviceContextWithTransportInfo,
911
930
  incoming
912
931
  );
913
932
  if (!this.disconnectedSessions.has(message.from)) {
@@ -1,3 +1,7 @@
1
+ import {
2
+ Connection
3
+ } from "./chunk-R2IMXRVU.js";
4
+
1
5
  // transport/transforms/messageFraming.ts
2
6
  import { Transform } from "node:stream";
3
7
  var Uint32LengthPrefixFraming = class extends Transform {
@@ -57,6 +61,40 @@ var MessageFramer = {
57
61
  }
58
62
  };
59
63
 
64
+ // transport/impls/uds/connection.ts
65
+ var UdsConnection = class extends Connection {
66
+ sock;
67
+ input;
68
+ framer;
69
+ constructor(sock) {
70
+ super();
71
+ this.framer = MessageFramer.createFramedStream();
72
+ this.sock = sock;
73
+ this.input = sock.pipe(this.framer);
74
+ }
75
+ addDataListener(cb) {
76
+ this.input.on("data", cb);
77
+ }
78
+ removeDataListener(cb) {
79
+ this.input.off("data", cb);
80
+ }
81
+ addCloseListener(cb) {
82
+ this.sock.on("close", cb);
83
+ }
84
+ addErrorListener(cb) {
85
+ this.sock.on("error", cb);
86
+ }
87
+ send(payload) {
88
+ if (this.framer.destroyed || !this.sock.writable)
89
+ return false;
90
+ return this.sock.write(MessageFramer.write(payload));
91
+ }
92
+ close() {
93
+ this.sock.destroy();
94
+ this.framer.destroy();
95
+ }
96
+ };
97
+
60
98
  export {
61
- MessageFramer
99
+ UdsConnection
62
100
  };
@@ -7,8 +7,8 @@ var TransportMessageSchema = (t) => Type.Object({
7
7
  to: Type.String(),
8
8
  seq: Type.Integer(),
9
9
  ack: Type.Integer(),
10
- serviceName: Type.Optional(Type.Union([Type.String(), Type.Null()])),
11
- procedureName: Type.Optional(Type.Union([Type.String(), Type.Null()])),
10
+ serviceName: Type.Optional(Type.String()),
11
+ procedureName: Type.Optional(Type.String()),
12
12
  streamId: Type.String(),
13
13
  controlFlags: Type.Integer(),
14
14
  payload: t
@@ -22,7 +22,7 @@ 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.String(),
26
26
  instanceId: Type.String()
27
27
  });
28
28
  var ControlMessageHandshakeResponseSchema = Type.Object({
@@ -47,7 +47,7 @@ var ControlMessagePayloadSchema = Type.Union([
47
47
  var OpaqueTransportMessageSchema = TransportMessageSchema(
48
48
  Type.Unknown()
49
49
  );
50
- function bootRequestMessage(from, to, instanceId) {
50
+ function handshakeRequestMessage(from, to, instanceId) {
51
51
  return {
52
52
  id: nanoid(),
53
53
  from,
@@ -63,7 +63,7 @@ function bootRequestMessage(from, to, instanceId) {
63
63
  }
64
64
  };
65
65
  }
66
- function bootResponseMessage(from, instanceId, to, ok) {
66
+ function handshakeResponseMessage(from, instanceId, to, ok) {
67
67
  return {
68
68
  id: nanoid(),
69
69
  from,
@@ -118,8 +118,8 @@ export {
118
118
  ControlMessageHandshakeResponseSchema,
119
119
  ControlMessagePayloadSchema,
120
120
  OpaqueTransportMessageSchema,
121
- bootRequestMessage,
122
- bootResponseMessage,
121
+ handshakeRequestMessage,
122
+ handshakeResponseMessage,
123
123
  isAck,
124
124
  isStreamOpen,
125
125
  isStreamClose,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Connection
3
- } from "./chunk-4SDJ5VN4.js";
3
+ } from "./chunk-R2IMXRVU.js";
4
4
 
5
5
  // transport/impls/ws/connection.ts
6
6
  var WebSocketConnection = class extends Connection {