@replit/river 0.8.0 → 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.
Files changed (57) hide show
  1. package/README.md +2 -0
  2. package/dist/__tests__/bandwidth.bench.js +1 -1
  3. package/dist/__tests__/e2e.test.js +119 -5
  4. package/dist/__tests__/fixtures/cleanup.d.ts +12 -0
  5. package/dist/__tests__/fixtures/cleanup.d.ts.map +1 -0
  6. package/dist/__tests__/fixtures/cleanup.js +39 -0
  7. package/dist/__tests__/fixtures/services.d.ts +72 -0
  8. package/dist/__tests__/fixtures/services.d.ts.map +1 -1
  9. package/dist/__tests__/fixtures/services.js +55 -0
  10. package/dist/__tests__/handler.test.js +35 -2
  11. package/dist/__tests__/invariants.test.d.ts +2 -0
  12. package/dist/__tests__/invariants.test.d.ts.map +1 -0
  13. package/dist/__tests__/invariants.test.js +136 -0
  14. package/dist/__tests__/serialize.test.js +40 -0
  15. package/dist/__tests__/typescript-stress.test.d.ts +392 -196
  16. package/dist/__tests__/typescript-stress.test.d.ts.map +1 -1
  17. package/dist/__tests__/typescript-stress.test.js +13 -3
  18. package/dist/router/builder.d.ts +49 -11
  19. package/dist/router/builder.d.ts.map +1 -1
  20. package/dist/router/builder.js +8 -2
  21. package/dist/router/client.d.ts +18 -2
  22. package/dist/router/client.d.ts.map +1 -1
  23. package/dist/router/client.js +52 -11
  24. package/dist/router/index.d.ts +1 -1
  25. package/dist/router/index.d.ts.map +1 -1
  26. package/dist/router/server.d.ts +15 -1
  27. package/dist/router/server.d.ts.map +1 -1
  28. package/dist/router/server.js +106 -44
  29. package/dist/transport/events.d.ts +19 -0
  30. package/dist/transport/events.d.ts.map +1 -0
  31. package/dist/transport/events.js +26 -0
  32. package/dist/transport/impls/stdio/stdio.d.ts +0 -4
  33. package/dist/transport/impls/stdio/stdio.d.ts.map +1 -1
  34. package/dist/transport/impls/stdio/stdio.js +0 -5
  35. package/dist/transport/impls/stdio/stdio.test.js +5 -0
  36. package/dist/transport/impls/ws/client.d.ts.map +1 -1
  37. package/dist/transport/impls/ws/client.js +2 -2
  38. package/dist/transport/impls/ws/connection.d.ts.map +1 -1
  39. package/dist/transport/impls/ws/connection.js +2 -1
  40. package/dist/transport/impls/ws/server.d.ts +0 -2
  41. package/dist/transport/impls/ws/server.d.ts.map +1 -1
  42. package/dist/transport/impls/ws/server.js +4 -9
  43. package/dist/transport/impls/ws/ws.test.js +30 -10
  44. package/dist/transport/index.d.ts +3 -3
  45. package/dist/transport/index.d.ts.map +1 -1
  46. package/dist/transport/index.js +3 -3
  47. package/dist/transport/message.d.ts +10 -0
  48. package/dist/transport/message.d.ts.map +1 -1
  49. package/dist/transport/message.js +15 -0
  50. package/dist/transport/transport.d.ts +48 -19
  51. package/dist/transport/transport.d.ts.map +1 -1
  52. package/dist/transport/transport.js +60 -27
  53. package/dist/util/testHelpers.d.ts +58 -7
  54. package/dist/util/testHelpers.d.ts.map +1 -1
  55. package/dist/util/testHelpers.js +133 -3
  56. package/package.json +12 -13
  57. /package/dist/__tests__/{largePayload.json → fixtures/largePayload.json} +0 -0
@@ -1,26 +1,53 @@
1
1
  import { Codec } from '../codec/types';
2
2
  import { MessageId, OpaqueTransportMessage, TransportClientId } from './message';
3
+ import { EventDispatcher, EventHandler, EventTypes } from './events';
3
4
  /**
4
- * Abstract base for a connection between two nodes in a River network.
5
- * A connection is responsible for sending and receiving messages on a 1:1
6
- * basis between nodes.
7
- * Connections can be reused across different transports.
8
- * @abstract
5
+ * A 1:1 connection between two transports. Once this is created,
6
+ * the {@link Connection} is expected to take over responsibility for
7
+ * reading and writing messages from the underlying connection.
8
+ *
9
+ * 1) Messages received on the {@link Connection} are dispatched back to the {@link Transport}
10
+ * via {@link Transport.onMessage}. The {@link Transport} then notifies any registered message listeners.
11
+ * 2) When {@link Transport.send}(msg) is called, the transport looks up the appropriate
12
+ * connection in the {@link connections} map via `msg.to` and calls {@link send}(bytes)
13
+ * so the connection can send it.
9
14
  */
10
15
  export declare abstract class Connection {
11
16
  connectedTo: TransportClientId;
12
17
  transport: Transport<Connection>;
13
18
  constructor(transport: Transport<Connection>, connectedTo: TransportClientId);
14
- onMessage(msg: Uint8Array): void;
15
19
  abstract send(msg: Uint8Array): boolean;
16
- abstract close(): Promise<void>;
20
+ abstract close(): void;
17
21
  }
18
22
  export type TransportStatus = 'open' | 'closed' | 'destroyed';
19
23
  /**
20
- * Abstract base for a transport layer for communication between nodes in a River network.
21
- * A transport is responsible for handling the 1:n connection logic between nodes and
22
- * delegating sending/receiving to connections.
23
- * Any River transport methods need to implement this interface.
24
+ * Transports manage the lifecycle (creation/deletion) of connections. Its responsibilities include:
25
+ *
26
+ * 1) Constructing a new {@link Connection} on {@link TransportMessage}s from new clients.
27
+ * After constructing the {@link Connection}, {@link onConnect} is called which adds it to the connection map.
28
+ * 2) Delegating message listening of the connection to the newly created {@link Connection}.
29
+ * From this point on, the {@link Connection} is responsible for *reading* and *writing*
30
+ * messages from the connection.
31
+ * 3) When a connection is closed, the {@link Transport} calls {@link onDisconnect} which closes the
32
+ * connection via {@link Connection.close} and removes it from the {@link connections} map.
33
+
34
+ *
35
+ * ```plaintext
36
+ * ▲
37
+ * incoming │
38
+ * messages │
39
+ * ▼
40
+ * ┌─────────────┐ 1:N ┌────────────┐
41
+ * │ Transport │ ◄─────► │ Connection │
42
+ * └─────────────┘ └────────────┘
43
+ * ▲
44
+ * │
45
+ * ▼
46
+ * ┌───────────┐
47
+ * │ Message │
48
+ * │ Listeners │
49
+ * └───────────┘
50
+ * ```
24
51
  * @abstract
25
52
  */
26
53
  export declare abstract class Transport<ConnType extends Connection> {
@@ -37,10 +64,6 @@ export declare abstract class Transport<ConnType extends Connection> {
37
64
  * The client ID of this transport.
38
65
  */
39
66
  clientId: TransportClientId;
40
- /**
41
- * The set of message handlers registered with this transport.
42
- */
43
- messageHandlers: Set<(msg: OpaqueTransportMessage) => void>;
44
67
  /**
45
68
  * An array of message IDs that are waiting to be sent over the WebSocket connection.
46
69
  * This builds up if the WebSocket is down for a period of time.
@@ -54,6 +77,10 @@ export declare abstract class Transport<ConnType extends Connection> {
54
77
  * The map of {@link Connection}s managed by this transport.
55
78
  */
56
79
  connections: Map<TransportClientId, ConnType>;
80
+ /**
81
+ * The event dispatcher for handling events of type EventTypes.
82
+ */
83
+ eventDispatcher: EventDispatcher<EventTypes>;
57
84
  /**
58
85
  * Creates a new Transport instance.
59
86
  * @param codec The codec used to encode and decode messages.
@@ -100,15 +127,17 @@ export declare abstract class Transport<ConnType extends Connection> {
100
127
  */
101
128
  protected handleMsg(msg: OpaqueTransportMessage | null): void;
102
129
  /**
103
- * Adds a message listener to this transport.
130
+ * Adds a listener to this transport.
131
+ * @param the type of event to listen for
104
132
  * @param handler The message handler to add.
105
133
  */
106
- addMessageListener(handler: (msg: OpaqueTransportMessage) => void): void;
134
+ addEventListener<K extends EventTypes, T extends EventHandler<K>>(type: K, handler: T): void;
107
135
  /**
108
- * Removes a message listener from this transport.
136
+ * Removes a listener from this transport.
137
+ * @param the type of event to unlisten on
109
138
  * @param handler The message handler to remove.
110
139
  */
111
- removeMessageListener(handler: (msg: OpaqueTransportMessage) => void): void;
140
+ removeEventListener<K extends EventTypes, T extends EventHandler<K>>(type: K, handler: T): void;
112
141
  /**
113
142
  * Sends a message over this transport, delegating to the appropriate connection to actually
114
143
  * send the message.
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../transport/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAEL,SAAS,EACT,sBAAsB,EAGtB,iBAAiB,EAGlB,MAAM,WAAW,CAAC;AAGnB;;;;;;GAMG;AACH,8BAAsB,UAAU;IAC9B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;gBAG/B,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,EAChC,WAAW,EAAE,iBAAiB;IAMhC,SAAS,CAAC,GAAG,EAAE,UAAU;IAIzB,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IACvC,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE9D;;;;;;GAMG;AACH,8BAAsB,SAAS,CAAC,QAAQ,SAAS,UAAU;IACzD;;;OAGG;IACH,KAAK,EAAE,eAAe,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAE5B;;OAEG;IACH,eAAe,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,CAAC,CAAC;IAE5D;;;OAGG;IACH,SAAS,EAAE,GAAG,CAAC,iBAAiB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IAEpD;;OAEG;IACH,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAEnD;;OAEG;IACH,WAAW,EAAE,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAE9C;;;;OAIG;gBACS,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,iBAAiB;IAUrD;;;OAGG;IACH,QAAQ,CAAC,8BAA8B,IAAI,IAAI;IAE/C;;;;;OAKG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAElE;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,QAAQ;IAyBxB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,QAAQ;IAM3B;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,UAAU;IAIzB;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,sBAAsB,GAAG,IAAI;IAmBlE;;;;OAIG;IACH,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,sBAAsB,GAAG,IAAI;IAgCtD;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,GAAG,IAAI;IAIxE;;;OAGG;IACH,qBAAqB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,GAAG,IAAI;IAI3E;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IA4C5C;;;;OAIG;IACG,KAAK;IAUX;;;;OAIG;IACG,OAAO;CASd"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../transport/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAEL,SAAS,EACT,sBAAsB,EAGtB,iBAAiB,EAGlB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAErE;;;;;;;;;;GAUG;AACH,8BAAsB,UAAU;IAC9B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;gBAG/B,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,EAChC,WAAW,EAAE,iBAAiB;IAMhC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IACvC,QAAQ,CAAC,KAAK,IAAI,IAAI;CACvB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,8BAAsB,SAAS,CAAC,QAAQ,SAAS,UAAU;IACzD;;;OAGG;IACH,KAAK,EAAE,eAAe,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAE5B;;;OAGG;IACH,SAAS,EAAE,GAAG,CAAC,iBAAiB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IAEpD;;OAEG;IACH,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAEnD;;OAEG;IACH,WAAW,EAAE,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAE9C;;OAEG;IACH,eAAe,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAE7C;;;;OAIG;gBACS,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,iBAAiB;IAUrD;;;OAGG;IACH,QAAQ,CAAC,8BAA8B,IAAI,IAAI;IAE/C;;;;;OAKG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAElE;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,QAAQ;IA8BxB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,QAAQ;IAU3B;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,UAAU;IAIzB;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,sBAAsB,GAAG,IAAI;IAmBlE;;;;OAIG;IACH,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,sBAAsB,GAAG,IAAI;IA8BtD;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EAC9D,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,CAAC,GACT,IAAI;IAIP;;;;OAIG;IACH,mBAAmB,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EACjE,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,CAAC,GACT,IAAI;IAIP;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IA4C5C;;;;OAIG;IACG,KAAK;IAUX;;;;OAIG;IACG,OAAO;CASd"}
@@ -1,12 +1,17 @@
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
- * Abstract base for a connection between two nodes in a River network.
6
- * A connection is responsible for sending and receiving messages on a 1:1
7
- * basis between nodes.
8
- * Connections can be reused across different transports.
9
- * @abstract
6
+ * A 1:1 connection between two transports. Once this is created,
7
+ * the {@link Connection} is expected to take over responsibility for
8
+ * reading and writing messages from the underlying connection.
9
+ *
10
+ * 1) Messages received on the {@link Connection} are dispatched back to the {@link Transport}
11
+ * via {@link Transport.onMessage}. The {@link Transport} then notifies any registered message listeners.
12
+ * 2) When {@link Transport.send}(msg) is called, the transport looks up the appropriate
13
+ * connection in the {@link connections} map via `msg.to` and calls {@link send}(bytes)
14
+ * so the connection can send it.
10
15
  */
11
16
  export class Connection {
12
17
  connectedTo;
@@ -15,15 +20,35 @@ export class Connection {
15
20
  this.connectedTo = connectedTo;
16
21
  this.transport = transport;
17
22
  }
18
- onMessage(msg) {
19
- return this.transport.onMessage(msg);
20
- }
21
23
  }
22
24
  /**
23
- * Abstract base for a transport layer for communication between nodes in a River network.
24
- * A transport is responsible for handling the 1:n connection logic between nodes and
25
- * delegating sending/receiving to connections.
26
- * Any River transport methods need to implement this interface.
25
+ * Transports manage the lifecycle (creation/deletion) of connections. Its responsibilities include:
26
+ *
27
+ * 1) Constructing a new {@link Connection} on {@link TransportMessage}s from new clients.
28
+ * After constructing the {@link Connection}, {@link onConnect} is called which adds it to the connection map.
29
+ * 2) Delegating message listening of the connection to the newly created {@link Connection}.
30
+ * From this point on, the {@link Connection} is responsible for *reading* and *writing*
31
+ * messages from the connection.
32
+ * 3) When a connection is closed, the {@link Transport} calls {@link onDisconnect} which closes the
33
+ * connection via {@link Connection.close} and removes it from the {@link connections} map.
34
+
35
+ *
36
+ * ```plaintext
37
+ * ▲
38
+ * incoming │
39
+ * messages │
40
+ * ▼
41
+ * ┌─────────────┐ 1:N ┌────────────┐
42
+ * │ Transport │ ◄─────► │ Connection │
43
+ * └─────────────┘ └────────────┘
44
+ * ▲
45
+ * │
46
+ * ▼
47
+ * ┌───────────┐
48
+ * │ Message │
49
+ * │ Listeners │
50
+ * └───────────┘
51
+ * ```
27
52
  * @abstract
28
53
  */
29
54
  export class Transport {
@@ -40,10 +65,6 @@ export class Transport {
40
65
  * The client ID of this transport.
41
66
  */
42
67
  clientId;
43
- /**
44
- * The set of message handlers registered with this transport.
45
- */
46
- messageHandlers;
47
68
  /**
48
69
  * An array of message IDs that are waiting to be sent over the WebSocket connection.
49
70
  * This builds up if the WebSocket is down for a period of time.
@@ -57,13 +78,17 @@ export class Transport {
57
78
  * The map of {@link Connection}s managed by this transport.
58
79
  */
59
80
  connections;
81
+ /**
82
+ * The event dispatcher for handling events of type EventTypes.
83
+ */
84
+ eventDispatcher;
60
85
  /**
61
86
  * Creates a new Transport instance.
62
87
  * @param codec The codec used to encode and decode messages.
63
88
  * @param clientId The client ID of this transport.
64
89
  */
65
90
  constructor(codec, clientId) {
66
- this.messageHandlers = new Set();
91
+ this.eventDispatcher = new EventDispatcher();
67
92
  this.sendBuffer = new Map();
68
93
  this.sendQueue = new Map();
69
94
  this.connections = new Map();
@@ -78,6 +103,10 @@ export class Transport {
78
103
  onConnect(conn) {
79
104
  log?.info(`${this.clientId} -- new connection to ${conn.connectedTo}`);
80
105
  this.connections.set(conn.connectedTo, conn);
106
+ this.eventDispatcher.dispatchEvent('connectionStatus', {
107
+ status: 'connect',
108
+ conn,
109
+ });
81
110
  // send outstanding
82
111
  const outstanding = this.sendQueue.get(conn.connectedTo);
83
112
  if (!outstanding) {
@@ -91,7 +120,7 @@ export class Transport {
91
120
  }
92
121
  this.send(msg);
93
122
  }
94
- this.sendQueue.set(conn.connectedTo, []);
123
+ this.sendQueue.delete(conn.connectedTo);
95
124
  }
96
125
  /**
97
126
  * The downstream implementation needs to call this when a connection is closed.
@@ -101,6 +130,10 @@ export class Transport {
101
130
  log?.info(`${this.clientId} -- disconnect from ${conn.connectedTo}`);
102
131
  conn.close();
103
132
  this.connections.delete(conn.connectedTo);
133
+ this.eventDispatcher.dispatchEvent('connectionStatus', {
134
+ status: 'disconnect',
135
+ conn,
136
+ });
104
137
  }
105
138
  /**
106
139
  * Handles a message received by this transport. Thin wrapper around {@link handleMsg} and {@link parseMsg}.
@@ -151,9 +184,7 @@ export class Transport {
151
184
  if (msg.to !== this.clientId) {
152
185
  return;
153
186
  }
154
- for (const handler of this.messageHandlers) {
155
- handler(msg);
156
- }
187
+ this.eventDispatcher.dispatchEvent('message', msg);
157
188
  if (!isAck(msg.controlFlags)) {
158
189
  const ackMsg = reply(msg, { ack: msg.id });
159
190
  ackMsg.controlFlags = 1 /* ControlFlags.AckBit */;
@@ -163,18 +194,20 @@ export class Transport {
163
194
  }
164
195
  }
165
196
  /**
166
- * Adds a message listener to this transport.
197
+ * Adds a listener to this transport.
198
+ * @param the type of event to listen for
167
199
  * @param handler The message handler to add.
168
200
  */
169
- addMessageListener(handler) {
170
- this.messageHandlers.add(handler);
201
+ addEventListener(type, handler) {
202
+ this.eventDispatcher.addEventListener(type, handler);
171
203
  }
172
204
  /**
173
- * Removes a message listener from this transport.
205
+ * Removes a listener from this transport.
206
+ * @param the type of event to unlisten on
174
207
  * @param handler The message handler to remove.
175
208
  */
176
- removeMessageListener(handler) {
177
- this.messageHandlers.delete(handler);
209
+ removeEventListener(type, handler) {
210
+ this.eventDispatcher.removeEventListener(type, handler);
178
211
  }
179
212
  /**
180
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.0",
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",
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
+ }