@replit/river 0.8.1 → 0.9.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.
@@ -1,6 +1,7 @@
1
1
  import { Value } from '@sinclair/typebox/value';
2
2
  import { OpaqueTransportMessageSchema, TransportAckSchema, isAck, reply, } from './message';
3
3
  import { log } from '../logging';
4
+ import { EventDispatcher } from './events';
4
5
  /**
5
6
  * A 1:1 connection between two transports. Once this is created,
6
7
  * the {@link Connection} is expected to take over responsibility for
@@ -64,10 +65,6 @@ export class Transport {
64
65
  * The client ID of this transport.
65
66
  */
66
67
  clientId;
67
- /**
68
- * The set of message handlers registered with this transport.
69
- */
70
- messageHandlers;
71
68
  /**
72
69
  * An array of message IDs that are waiting to be sent over the WebSocket connection.
73
70
  * This builds up if the WebSocket is down for a period of time.
@@ -81,13 +78,17 @@ export class Transport {
81
78
  * The map of {@link Connection}s managed by this transport.
82
79
  */
83
80
  connections;
81
+ /**
82
+ * The event dispatcher for handling events of type EventTypes.
83
+ */
84
+ eventDispatcher;
84
85
  /**
85
86
  * Creates a new Transport instance.
86
87
  * @param codec The codec used to encode and decode messages.
87
88
  * @param clientId The client ID of this transport.
88
89
  */
89
90
  constructor(codec, clientId) {
90
- this.messageHandlers = new Set();
91
+ this.eventDispatcher = new EventDispatcher();
91
92
  this.sendBuffer = new Map();
92
93
  this.sendQueue = new Map();
93
94
  this.connections = new Map();
@@ -102,6 +103,10 @@ export class Transport {
102
103
  onConnect(conn) {
103
104
  log?.info(`${this.clientId} -- new connection to ${conn.connectedTo}`);
104
105
  this.connections.set(conn.connectedTo, conn);
106
+ this.eventDispatcher.dispatchEvent('connectionStatus', {
107
+ status: 'connect',
108
+ conn,
109
+ });
105
110
  // send outstanding
106
111
  const outstanding = this.sendQueue.get(conn.connectedTo);
107
112
  if (!outstanding) {
@@ -125,6 +130,10 @@ export class Transport {
125
130
  log?.info(`${this.clientId} -- disconnect from ${conn.connectedTo}`);
126
131
  conn.close();
127
132
  this.connections.delete(conn.connectedTo);
133
+ this.eventDispatcher.dispatchEvent('connectionStatus', {
134
+ status: 'disconnect',
135
+ conn,
136
+ });
128
137
  }
129
138
  /**
130
139
  * Handles a message received by this transport. Thin wrapper around {@link handleMsg} and {@link parseMsg}.
@@ -175,9 +184,7 @@ export class Transport {
175
184
  if (msg.to !== this.clientId) {
176
185
  return;
177
186
  }
178
- for (const handler of this.messageHandlers) {
179
- handler(msg);
180
- }
187
+ this.eventDispatcher.dispatchEvent('message', msg);
181
188
  if (!isAck(msg.controlFlags)) {
182
189
  const ackMsg = reply(msg, { ack: msg.id });
183
190
  ackMsg.controlFlags = 1 /* ControlFlags.AckBit */;
@@ -187,18 +194,20 @@ export class Transport {
187
194
  }
188
195
  }
189
196
  /**
190
- * Adds a message listener to this transport.
197
+ * Adds a listener to this transport.
198
+ * @param the type of event to listen for
191
199
  * @param handler The message handler to add.
192
200
  */
193
- addMessageListener(handler) {
194
- this.messageHandlers.add(handler);
201
+ addEventListener(type, handler) {
202
+ this.eventDispatcher.addEventListener(type, handler);
195
203
  }
196
204
  /**
197
- * Removes a message listener from this transport.
205
+ * Removes a listener from this transport.
206
+ * @param the type of event to unlisten on
198
207
  * @param handler The message handler to remove.
199
208
  */
200
- removeMessageListener(handler) {
201
- this.messageHandlers.delete(handler);
209
+ removeEventListener(type, handler) {
210
+ this.eventDispatcher.removeEventListener(type, handler);
202
211
  }
203
212
  /**
204
213
  * Sends a message over this transport, delegating to the appropriate connection to actually
@@ -3,13 +3,14 @@ import WebSocket from 'isomorphic-ws';
3
3
  import { WebSocketServer } from 'ws';
4
4
  import http from 'http';
5
5
  import { WebSocketClientTransport } from '../transport/impls/ws/client';
6
- import { Static, TObject } from '@sinclair/typebox';
6
+ import { Static } from '@sinclair/typebox';
7
7
  import { Procedure, ServiceContext } from '../router';
8
8
  import { OpaqueTransportMessage, TransportClientId, TransportMessage } from '../transport';
9
9
  import { Pushable } from 'it-pushable';
10
10
  import { Result, RiverError, RiverUncaughtSchema } from '../router/result';
11
11
  import { Codec } from '../codec';
12
12
  import { WebSocketServerTransport } from '../transport/impls/ws/server';
13
+ import { PayloadType } from '../router/builder';
13
14
  /**
14
15
  * Creates a WebSocket server instance using the provided HTTP server.
15
16
  * Only used as helper for testing.
@@ -46,11 +47,11 @@ export declare function createWsTransports(port: number, wss: WebSocketServer, c
46
47
  * @template I - The type of the input message payload.
47
48
  * @template O - The type of the output message payload.
48
49
  * @param {State} state - The state object.
49
- * @param {Procedure<State, 'rpc', I, O>} proc - The RPC procedure to invoke.
50
+ * @param {Procedure<State, 'rpc', I, O, E, null>} proc - The RPC procedure to invoke.
50
51
  * @param {Omit<ServiceContext, 'state'>} [extendedContext] - Optional extended context.
51
52
  * @returns A function that can be used to invoke the RPC procedure.
52
53
  */
53
- export declare function asClientRpc<State extends object | unknown, I extends TObject, O extends TObject, E extends RiverError>(state: State, proc: Procedure<State, 'rpc', I, O, E>, extendedContext?: Omit<ServiceContext, 'state'>): (msg: Static<I>) => Promise<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>;
54
+ export declare function asClientRpc<State extends object | unknown, I extends PayloadType, O extends PayloadType, E extends RiverError>(state: State, proc: Procedure<State, 'rpc', I, O, E, null>, extendedContext?: Omit<ServiceContext, 'state'>): (msg: Static<I>) => Promise<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>;
54
55
  /**
55
56
  * Transforms a stream procedure definition into a pair of input and output streams.
56
57
  * Input messages can be pushed into the input stream.
@@ -59,11 +60,27 @@ export declare function asClientRpc<State extends object | unknown, I extends TO
59
60
  * @template I - The type of the input object.
60
61
  * @template O - The type of the output object.
61
62
  * @param {State} state - The state object.
62
- * @param {Procedure<State, 'stream', I, O>} proc - The procedure to handle the stream.
63
+ * @param {Procedure<State, 'stream', I, O, E, null>} proc - The procedure to handle the stream.
63
64
  * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
64
65
  * @returns Pair of input and output streams.
65
66
  */
66
- export declare function asClientStream<State extends object | unknown, I extends TObject, O extends TObject, E extends RiverError>(state: State, proc: Procedure<State, 'stream', I, O, E>, extendedContext?: Omit<ServiceContext, 'state'>): [
67
+ export declare function asClientStream<State extends object | unknown, I extends PayloadType, O extends PayloadType, E extends RiverError>(state: State, proc: Procedure<State, 'stream', I, O, E, null>, extendedContext?: Omit<ServiceContext, 'state'>): [
68
+ Pushable<Static<I>>,
69
+ Pushable<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>
70
+ ];
71
+ /**
72
+ * Transforms a stream procedure definition into a pair of input and output streams.
73
+ * Input messages can be pushed into the input stream.
74
+ * This should only be used for testing.
75
+ * @template State - The type of the state object.
76
+ * @template I - The type of the input object.
77
+ * @template O - The type of the output object.
78
+ * @param {State} state - The state object.
79
+ * @param {Procedure<State, 'stream', I, O, E, null>} proc - The procedure to handle the stream.
80
+ * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
81
+ * @returns Pair of input and output streams.
82
+ */
83
+ export declare function asClientStreamWithInitialization<State extends object | unknown, I extends PayloadType, O extends PayloadType, E extends RiverError, Init extends PayloadType>(state: State, proc: Procedure<State, 'stream', I, O, E, Init>, init: Static<PayloadType>, extendedContext?: Omit<ServiceContext, 'state'>): [
67
84
  Pushable<Static<I>>,
68
85
  Pushable<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>
69
86
  ];
@@ -75,11 +92,45 @@ export declare function asClientStream<State extends object | unknown, I extends
75
92
  * @template I - The type of the input object.
76
93
  * @template O - The type of the output object.
77
94
  * @param {State} state - The state object.
78
- * @param {Procedure<State, 'stream', I, O>} proc - The procedure to handle the stream.
95
+ * @param {Procedure<State, 'stream', I, O, E, null>} proc - The procedure to handle the stream.
96
+ * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
97
+ * @returns A function that when passed a message, returns the output stream.
98
+ */
99
+ export declare function asClientSubscription<State extends object | unknown, I extends PayloadType, O extends PayloadType, E extends RiverError>(state: State, proc: Procedure<State, 'subscription', I, O, E, null>, extendedContext?: Omit<ServiceContext, 'state'>): (msg: Static<I>) => Promise<Pushable<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>>;
100
+ /**
101
+ * Transforms an upload procedure definition into a procedure that returns an input stream.
102
+ * Input messages can be pushed into the input stream.
103
+ * This should only be used for testing.
104
+ * @template State - The type of the state object.
105
+ * @template I - The type of the input object.
106
+ * @template O - The type of the output object.
107
+ * @param {State} state - The state object.
108
+ * @param {Procedure<State, 'upload', I, O, E, null>} proc - The procedure to handle the stream.
79
109
  * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
80
110
  * @returns A function that when passed a message, returns the output stream.
81
111
  */
82
- export declare function asClientSubscription<State extends object | unknown, I extends TObject, O extends TObject, E extends RiverError>(state: State, proc: Procedure<State, 'subscription', I, O, E>, extendedContext?: Omit<ServiceContext, 'state'>): (msg: Static<I>) => Promise<Pushable<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>>;
112
+ export declare function asClientUpload<State extends object | unknown, I extends PayloadType, O extends PayloadType, E extends RiverError>(state: State, proc: Procedure<State, 'upload', I, O, E, null>, extendedContext?: Omit<ServiceContext, 'state'>): [
113
+ Pushable<Static<I>>,
114
+ Promise<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>
115
+ ];
116
+ /**
117
+ * Transforms an upload with initialization procedure definition into a procedure that returns an
118
+ * input stream.
119
+ * Input messages can be pushed into the input stream.
120
+ * This should only be used for testing.
121
+ * @template State - The type of the state object.
122
+ * @template Init - The type of the init object.
123
+ * @template I - The type of the input object.
124
+ * @template O - The type of the output object.
125
+ * @param {State} state - The state object.
126
+ * @param {Procedure<State, 'upload', I, O, E, Init>} proc - The procedure to handle the stream.
127
+ * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
128
+ * @returns A function that when passed a message, returns the output stream.
129
+ */
130
+ export declare function asClientUploadWithInitialization<State extends object | unknown, I extends PayloadType, O extends PayloadType, E extends RiverError, Init extends PayloadType>(state: State, proc: Procedure<State, 'upload', I, O, E, Init>, init: Static<Init>, extendedContext?: Omit<ServiceContext, 'state'>): [
131
+ Pushable<Static<I>>,
132
+ Promise<Result<Static<O>, Static<E> | Static<typeof RiverUncaughtSchema>>>
133
+ ];
83
134
  /**
84
135
  * Converts a payload object to a transport message with reasonable defaults.
85
136
  * This should only be used for testing.
@@ -1 +1 @@
1
- {"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../util/testHelpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../util/testHelpers.ts"],"names":[],"mappings":"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"}
@@ -65,7 +65,7 @@ export function createWsTransports(port, wss, codec) {
65
65
  * @template I - The type of the input message payload.
66
66
  * @template O - The type of the output message payload.
67
67
  * @param {State} state - The state object.
68
- * @param {Procedure<State, 'rpc', I, O>} proc - The RPC procedure to invoke.
68
+ * @param {Procedure<State, 'rpc', I, O, E, null>} proc - The RPC procedure to invoke.
69
69
  * @param {Omit<ServiceContext, 'state'>} [extendedContext] - Optional extended context.
70
70
  * @returns A function that can be used to invoke the RPC procedure.
71
71
  */
@@ -89,7 +89,7 @@ export function asClientRpc(state, proc, extendedContext) {
89
89
  * @template I - The type of the input object.
90
90
  * @template O - The type of the output object.
91
91
  * @param {State} state - The state object.
92
- * @param {Procedure<State, 'stream', I, O>} proc - The procedure to handle the stream.
92
+ * @param {Procedure<State, 'stream', I, O, E, null>} proc - The procedure to handle the stream.
93
93
  * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
94
94
  * @returns Pair of input and output streams.
95
95
  */
@@ -133,6 +133,58 @@ export function asClientStream(state, proc, extendedContext) {
133
133
  })();
134
134
  return [rawInput, rawOutput];
135
135
  }
136
+ /**
137
+ * Transforms a stream procedure definition into a pair of input and output streams.
138
+ * Input messages can be pushed into the input stream.
139
+ * This should only be used for testing.
140
+ * @template State - The type of the state object.
141
+ * @template I - The type of the input object.
142
+ * @template O - The type of the output object.
143
+ * @param {State} state - The state object.
144
+ * @param {Procedure<State, 'stream', I, O, E, null>} proc - The procedure to handle the stream.
145
+ * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
146
+ * @returns Pair of input and output streams.
147
+ */
148
+ export function asClientStreamWithInitialization(state, proc, init, extendedContext) {
149
+ const rawInput = pushable({ objectMode: true });
150
+ const rawOutput = pushable({
151
+ objectMode: true,
152
+ });
153
+ const transportInput = pushable({
154
+ objectMode: true,
155
+ });
156
+ const transportOutput = pushable({
157
+ objectMode: true,
158
+ });
159
+ // wrapping in transport
160
+ (async () => {
161
+ for await (const rawIn of rawInput) {
162
+ transportInput.push(payloadToTransportMessage(rawIn));
163
+ }
164
+ transportInput.end();
165
+ })();
166
+ // unwrap from transport
167
+ (async () => {
168
+ for await (const transportRes of transportOutput) {
169
+ rawOutput.push(transportRes.payload);
170
+ }
171
+ })();
172
+ // handle
173
+ (async () => {
174
+ try {
175
+ await proc.handler({ ...extendedContext, state }, payloadToTransportMessage(init), transportInput, transportOutput);
176
+ }
177
+ catch (err) {
178
+ const errorMsg = err instanceof Error ? err.message : `[coerced to error] ${err}`;
179
+ transportOutput.push(reply(payloadToTransportMessage({}), Err({
180
+ code: UNCAUGHT_ERROR,
181
+ message: errorMsg,
182
+ })));
183
+ }
184
+ transportOutput.end();
185
+ })();
186
+ return [rawInput, rawOutput];
187
+ }
136
188
  /**
137
189
  * Transforms a subscription procedure definition into a procedure that returns an output stream.
138
190
  * Input messages can be pushed into the input stream.
@@ -141,7 +193,7 @@ export function asClientStream(state, proc, extendedContext) {
141
193
  * @template I - The type of the input object.
142
194
  * @template O - The type of the output object.
143
195
  * @param {State} state - The state object.
144
- * @param {Procedure<State, 'stream', I, O>} proc - The procedure to handle the stream.
196
+ * @param {Procedure<State, 'stream', I, O, E, null>} proc - The procedure to handle the stream.
145
197
  * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
146
198
  * @returns A function that when passed a message, returns the output stream.
147
199
  */
@@ -171,6 +223,84 @@ export function asClientSubscription(state, proc, extendedContext) {
171
223
  return rawOutput;
172
224
  };
173
225
  }
226
+ /**
227
+ * Transforms an upload procedure definition into a procedure that returns an input stream.
228
+ * Input messages can be pushed into the input stream.
229
+ * This should only be used for testing.
230
+ * @template State - The type of the state object.
231
+ * @template I - The type of the input object.
232
+ * @template O - The type of the output object.
233
+ * @param {State} state - The state object.
234
+ * @param {Procedure<State, 'upload', I, O, E, null>} proc - The procedure to handle the stream.
235
+ * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
236
+ * @returns A function that when passed a message, returns the output stream.
237
+ */
238
+ export function asClientUpload(state, proc, extendedContext) {
239
+ const rawInput = pushable({ objectMode: true });
240
+ const transportInput = pushable({
241
+ objectMode: true,
242
+ });
243
+ // wrapping in transport
244
+ (async () => {
245
+ for await (const rawIn of rawInput) {
246
+ transportInput.push(payloadToTransportMessage(rawIn));
247
+ }
248
+ transportInput.end();
249
+ })();
250
+ return [
251
+ rawInput,
252
+ proc
253
+ .handler({ ...extendedContext, state }, transportInput)
254
+ .then((res) => res.payload)
255
+ .catch((err) => {
256
+ const errorMsg = err instanceof Error ? err.message : `[coerced to error] ${err}`;
257
+ return Err({
258
+ code: UNCAUGHT_ERROR,
259
+ message: errorMsg,
260
+ });
261
+ }),
262
+ ];
263
+ }
264
+ /**
265
+ * Transforms an upload with initialization procedure definition into a procedure that returns an
266
+ * input stream.
267
+ * Input messages can be pushed into the input stream.
268
+ * This should only be used for testing.
269
+ * @template State - The type of the state object.
270
+ * @template Init - The type of the init object.
271
+ * @template I - The type of the input object.
272
+ * @template O - The type of the output object.
273
+ * @param {State} state - The state object.
274
+ * @param {Procedure<State, 'upload', I, O, E, Init>} proc - The procedure to handle the stream.
275
+ * @param {Omit<ServiceContext, 'state'>} [extendedContext] - The extended context object.
276
+ * @returns A function that when passed a message, returns the output stream.
277
+ */
278
+ export function asClientUploadWithInitialization(state, proc, init, extendedContext) {
279
+ const rawInput = pushable({ objectMode: true });
280
+ const transportInput = pushable({
281
+ objectMode: true,
282
+ });
283
+ // wrapping in transport
284
+ (async () => {
285
+ for await (const rawIn of rawInput) {
286
+ transportInput.push(payloadToTransportMessage(rawIn));
287
+ }
288
+ transportInput.end();
289
+ })();
290
+ return [
291
+ rawInput,
292
+ proc
293
+ .handler({ ...extendedContext, state }, payloadToTransportMessage(init), transportInput)
294
+ .then((res) => res.payload)
295
+ .catch((err) => {
296
+ const errorMsg = err instanceof Error ? err.message : `[coerced to error] ${err}`;
297
+ return Err({
298
+ code: UNCAUGHT_ERROR,
299
+ message: errorMsg,
300
+ });
301
+ }),
302
+ ];
303
+ }
174
304
  /**
175
305
  * Converts a payload object to a transport message with reasonable defaults.
176
306
  * This should only be used for testing.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@replit/river",
3
3
  "sideEffects": false,
4
4
  "description": "It's like tRPC but... with JSON Schema Support, duplex streaming and support for service multiplexing. Transport agnostic!",
5
- "version": "0.8.1",
5
+ "version": "0.9.0",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./dist/router/index.js",
@@ -33,16 +33,6 @@
33
33
  "typescript": "^5.2.2",
34
34
  "vitest": "^1.0.1"
35
35
  },
36
- "scripts": {
37
- "check": "tsc --noEmit && npx prettier . --check",
38
- "format": "npx prettier . --write",
39
- "build": "rm -rf ./dist && tsc",
40
- "prepack": "npm run build",
41
- "release": "npm publish --access public",
42
- "test:ui": "echo \"remember to go to /__vitest__ in the webview\" && vitest --ui --api.host 0.0.0.0 --api.port 3000",
43
- "test": "vitest --test-timeout=500",
44
- "bench": "vitest bench"
45
- },
46
36
  "engines": {
47
37
  "node": ">=16"
48
38
  },
@@ -52,5 +42,14 @@
52
42
  "jsonschema"
53
43
  ],
54
44
  "author": "Jacky Zhao",
55
- "license": "MIT"
56
- }
45
+ "license": "MIT",
46
+ "scripts": {
47
+ "check": "tsc --noEmit && npx prettier . --check",
48
+ "format": "npx prettier . --write",
49
+ "build": "rm -rf ./dist && tsc",
50
+ "release": "npm publish --access public",
51
+ "test:ui": "echo \"remember to go to /__vitest__ in the webview\" && vitest --ui --api.host 0.0.0.0 --api.port 3000",
52
+ "test": "vitest --test-timeout=500",
53
+ "bench": "vitest bench"
54
+ }
55
+ }