@replit/river 0.7.2 → 0.8.1

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 (56) hide show
  1. package/README.md +2 -0
  2. package/dist/__tests__/bandwidth.bench.js +6 -6
  3. package/dist/__tests__/e2e.test.js +112 -23
  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/observable.d.ts +26 -0
  8. package/dist/__tests__/fixtures/observable.d.ts.map +1 -0
  9. package/dist/__tests__/fixtures/observable.js +38 -0
  10. package/dist/__tests__/fixtures/observable.test.d.ts +2 -0
  11. package/dist/__tests__/fixtures/observable.test.d.ts.map +1 -0
  12. package/dist/__tests__/fixtures/observable.test.js +39 -0
  13. package/dist/__tests__/{fixtures.d.ts → fixtures/services.d.ts} +61 -18
  14. package/dist/__tests__/fixtures/services.d.ts.map +1 -0
  15. package/dist/__tests__/{fixtures.js → fixtures/services.js} +35 -3
  16. package/dist/__tests__/handler.test.js +24 -7
  17. package/dist/__tests__/invariants.test.d.ts +2 -0
  18. package/dist/__tests__/invariants.test.d.ts.map +1 -0
  19. package/dist/__tests__/invariants.test.js +136 -0
  20. package/dist/__tests__/serialize.test.js +2 -1
  21. package/dist/router/builder.d.ts +10 -4
  22. package/dist/router/builder.d.ts.map +1 -1
  23. package/dist/router/client.d.ts +14 -5
  24. package/dist/router/client.d.ts.map +1 -1
  25. package/dist/router/client.js +42 -11
  26. package/dist/router/server.d.ts +14 -0
  27. package/dist/router/server.d.ts.map +1 -1
  28. package/dist/router/server.js +85 -48
  29. package/dist/transport/impls/stdio/stdio.d.ts +0 -4
  30. package/dist/transport/impls/stdio/stdio.d.ts.map +1 -1
  31. package/dist/transport/impls/stdio/stdio.js +0 -5
  32. package/dist/transport/impls/stdio/stdio.test.js +6 -1
  33. package/dist/transport/impls/ws/client.d.ts.map +1 -1
  34. package/dist/transport/impls/ws/client.js +2 -2
  35. package/dist/transport/impls/ws/connection.d.ts.map +1 -1
  36. package/dist/transport/impls/ws/connection.js +2 -1
  37. package/dist/transport/impls/ws/server.d.ts +0 -2
  38. package/dist/transport/impls/ws/server.d.ts.map +1 -1
  39. package/dist/transport/impls/ws/server.js +4 -9
  40. package/dist/transport/impls/ws/ws.test.js +31 -11
  41. package/dist/transport/index.d.ts +3 -3
  42. package/dist/transport/index.d.ts.map +1 -1
  43. package/dist/transport/index.js +1 -1
  44. package/dist/transport/message.d.ts +10 -0
  45. package/dist/transport/message.d.ts.map +1 -1
  46. package/dist/transport/message.js +15 -0
  47. package/dist/transport/transport.d.ts +37 -11
  48. package/dist/transport/transport.d.ts.map +1 -1
  49. package/dist/transport/transport.js +37 -13
  50. package/dist/{testUtils.d.ts → util/testHelpers.d.ts} +27 -8
  51. package/dist/util/testHelpers.d.ts.map +1 -0
  52. package/dist/{testUtils.js → util/testHelpers.js} +51 -5
  53. package/package.json +3 -3
  54. package/dist/__tests__/fixtures.d.ts.map +0 -1
  55. package/dist/testUtils.d.ts.map +0 -1
  56. /package/dist/__tests__/{largePayload.json → fixtures/largePayload.json} +0 -0
@@ -1,10 +1,12 @@
1
1
  import { Type } from '@sinclair/typebox';
2
- import { ServiceBuilder } from '../router/builder';
3
- import { reply } from '../transport/message';
4
- import { Err, Ok } from '../router/result';
2
+ import { ServiceBuilder } from '../../router/builder';
3
+ import { reply } from '../../transport/message';
4
+ import { Err, Ok } from '../../router/result';
5
+ import { Observable } from './observable';
5
6
  export const EchoRequest = Type.Object({
6
7
  msg: Type.String(),
7
8
  ignore: Type.Boolean(),
9
+ end: Type.Optional(Type.Boolean()),
8
10
  });
9
11
  export const EchoResponse = Type.Object({ response: Type.String() });
10
12
  export const TestServiceConstructor = () => ServiceBuilder.create('test')
@@ -33,6 +35,9 @@ export const TestServiceConstructor = () => ServiceBuilder.create('test')
33
35
  if (!req.ignore) {
34
36
  returnStream.push(reply(msg, Ok({ response: req.msg })));
35
37
  }
38
+ if (req.end) {
39
+ returnStream.end();
40
+ }
36
41
  }
37
42
  },
38
43
  })
@@ -139,3 +144,30 @@ export const FallibleServiceConstructor = () => ServiceBuilder.create('fallible'
139
144
  },
140
145
  })
141
146
  .finalize();
147
+ export const SubscribableServiceConstructor = () => ServiceBuilder.create('subscribable')
148
+ .initialState({
149
+ count: new Observable(0),
150
+ })
151
+ .defineProcedure('add', {
152
+ type: 'rpc',
153
+ input: Type.Object({ n: Type.Number() }),
154
+ output: Type.Object({ result: Type.Number() }),
155
+ errors: Type.Never(),
156
+ async handler(ctx, msg) {
157
+ const { n } = msg.payload;
158
+ ctx.state.count.set((prev) => prev + n);
159
+ return reply(msg, Ok({ result: ctx.state.count.get() }));
160
+ },
161
+ })
162
+ .defineProcedure('value', {
163
+ type: 'subscription',
164
+ input: Type.Object({}),
165
+ output: Type.Object({ result: Type.Number() }),
166
+ errors: Type.Never(),
167
+ async handler(ctx, msg, returnStream) {
168
+ ctx.state.count.observe((count) => {
169
+ returnStream.push(reply(msg, Ok({ result: count })));
170
+ });
171
+ },
172
+ })
173
+ .finalize();
@@ -1,7 +1,8 @@
1
- import { asClientRpc, asClientStream } from '../testUtils';
1
+ import { asClientRpc, asClientStream, asClientSubscription, iterNext, } from '../util/testHelpers';
2
2
  import { assert, describe, expect, test } from 'vitest';
3
- import { DIV_BY_ZERO, FallibleServiceConstructor, STREAM_ERROR, TestServiceConstructor, } from './fixtures';
3
+ import { DIV_BY_ZERO, FallibleServiceConstructor, STREAM_ERROR, SubscribableServiceConstructor, TestServiceConstructor, } from './fixtures/services';
4
4
  import { UNCAUGHT_ERROR } from '../router/result';
5
+ import { Observable } from './fixtures/observable';
5
6
  describe('server-side test', () => {
6
7
  const service = TestServiceConstructor();
7
8
  const initialState = { count: 0 };
@@ -39,10 +40,10 @@ describe('server-side test', () => {
39
40
  input.push({ msg: 'def', ignore: true });
40
41
  input.push({ msg: 'ghi', ignore: false });
41
42
  input.end();
42
- const result1 = await output.next().then((res) => res.value);
43
+ const result1 = await iterNext(output);
43
44
  assert(result1 && result1.ok);
44
45
  expect(result1.payload).toStrictEqual({ response: 'abc' });
45
- const result2 = await output.next().then((res) => res.value);
46
+ const result2 = await iterNext(output);
46
47
  assert(result2 && result2.ok);
47
48
  expect(result2.payload).toStrictEqual({ response: 'ghi' });
48
49
  expect(output.readableLength).toBe(0);
@@ -51,15 +52,15 @@ describe('server-side test', () => {
51
52
  const service = FallibleServiceConstructor();
52
53
  const [input, output] = asClientStream({}, service.procedures.echo);
53
54
  input.push({ msg: 'abc', throwResult: false, throwError: false });
54
- const result1 = await output.next().then((res) => res.value);
55
+ const result1 = await iterNext(output);
55
56
  assert(result1 && result1.ok);
56
57
  expect(result1.payload).toStrictEqual({ response: 'abc' });
57
58
  input.push({ msg: 'def', throwResult: true, throwError: false });
58
- const result2 = await output.next().then((res) => res.value);
59
+ const result2 = await iterNext(output);
59
60
  assert(result2 && !result2.ok);
60
61
  expect(result2.payload.code).toStrictEqual(STREAM_ERROR);
61
62
  input.push({ msg: 'ghi', throwResult: false, throwError: true });
62
- const result3 = await output.next().then((res) => res.value);
63
+ const result3 = await iterNext(output);
63
64
  assert(result3 && !result3.ok);
64
65
  expect(result3.payload).toStrictEqual({
65
66
  code: UNCAUGHT_ERROR,
@@ -68,4 +69,20 @@ describe('server-side test', () => {
68
69
  input.end();
69
70
  expect(output.readableLength).toBe(0);
70
71
  });
72
+ test('subscriptions', async () => {
73
+ const service = SubscribableServiceConstructor();
74
+ const state = { count: new Observable(0) };
75
+ const add = asClientRpc(state, service.procedures.add);
76
+ const subscribe = asClientSubscription(state, service.procedures.value);
77
+ const stream = await subscribe({});
78
+ const streamResult1 = await iterNext(stream);
79
+ assert(streamResult1 && streamResult1.ok);
80
+ expect(streamResult1.payload).toStrictEqual({ result: 0 });
81
+ const result = await add({ n: 3 });
82
+ assert(result.ok);
83
+ expect(result.payload).toStrictEqual({ result: 3 });
84
+ const streamResult2 = await iterNext(stream);
85
+ assert(streamResult2 && streamResult1.ok);
86
+ expect(streamResult2.payload).toStrictEqual({ result: 3 });
87
+ });
71
88
  });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=invariants.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariants.test.d.ts","sourceRoot":"","sources":["../../__tests__/invariants.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,136 @@
1
+ import { afterAll, assert, describe, expect, test } from 'vitest';
2
+ import http from 'http';
3
+ import { createWebSocketServer, createWsTransports, iterNext, onServerReady, } from '../util/testHelpers';
4
+ import { SubscribableServiceConstructor, TestServiceConstructor, } from './fixtures/services';
5
+ import { createClient, createServer } from '../router';
6
+ import { ensureServerIsClean, ensureTransportQueuesAreEventuallyEmpty, waitUntil, } from './fixtures/cleanup';
7
+ describe('procedures should leave no trace after finishing', async () => {
8
+ const httpServer = http.createServer();
9
+ const port = await onServerReady(httpServer);
10
+ const webSocketServer = await createWebSocketServer(httpServer);
11
+ const getTransports = () => createWsTransports(port, webSocketServer);
12
+ afterAll(() => {
13
+ webSocketServer.close();
14
+ httpServer.close();
15
+ });
16
+ test('closing a transport from the client cleans up connection on the server', async () => {
17
+ const [clientTransport, serverTransport] = getTransports();
18
+ const serviceDefs = { test: TestServiceConstructor() };
19
+ const server = await createServer(serverTransport, serviceDefs);
20
+ const client = createClient(clientTransport);
21
+ expect(clientTransport.connections.size).toEqual(0);
22
+ expect(serverTransport.connections.size).toEqual(0);
23
+ // start procedure
24
+ await client.test.add.rpc({ n: 3 });
25
+ // end procedure
26
+ expect(clientTransport.connections.size).toEqual(1);
27
+ expect(serverTransport.connections.size).toEqual(1);
28
+ // should be back to 0 connections after client closes
29
+ clientTransport.close();
30
+ expect(clientTransport.connections.size).toEqual(0);
31
+ await waitUntil(() => serverTransport.connections.size, 0, 'server should cleanup connection after client closes');
32
+ });
33
+ test('closing a transport from the server cleans up connection on the client', async () => {
34
+ const [clientTransport, serverTransport] = getTransports();
35
+ const serviceDefs = { test: TestServiceConstructor() };
36
+ const server = await createServer(serverTransport, serviceDefs);
37
+ const client = createClient(clientTransport);
38
+ expect(clientTransport.connections.size).toEqual(0);
39
+ expect(serverTransport.connections.size).toEqual(0);
40
+ // start procedure
41
+ await client.test.add.rpc({ n: 3 });
42
+ // end procedure
43
+ expect(clientTransport.connections.size).toEqual(1);
44
+ expect(serverTransport.connections.size).toEqual(1);
45
+ // should be back to 0 connections after client closes
46
+ serverTransport.close();
47
+ expect(serverTransport.connections.size).toEqual(0);
48
+ await waitUntil(() => clientTransport.connections.size, 0, 'client should cleanup connection after server closes');
49
+ });
50
+ test('rpc', async () => {
51
+ const [clientTransport, serverTransport] = getTransports();
52
+ const serviceDefs = { test: TestServiceConstructor() };
53
+ const server = await createServer(serverTransport, serviceDefs);
54
+ const client = createClient(clientTransport);
55
+ let serverListeners = serverTransport.messageHandlers.size;
56
+ let clientListeners = clientTransport.messageHandlers.size;
57
+ // start procedure
58
+ await client.test.add.rpc({ n: 3 });
59
+ // end procedure
60
+ // number of message handlers shouldn't increase after rpc
61
+ expect(serverTransport.messageHandlers.size).toEqual(serverListeners);
62
+ expect(clientTransport.messageHandlers.size).toEqual(clientListeners);
63
+ // check number of connections
64
+ expect(serverTransport.connections.size).toEqual(1);
65
+ expect(clientTransport.connections.size).toEqual(1);
66
+ await ensureTransportQueuesAreEventuallyEmpty(clientTransport);
67
+ await ensureTransportQueuesAreEventuallyEmpty(serverTransport);
68
+ // ensure we have no streams left on the server
69
+ await ensureServerIsClean(server);
70
+ });
71
+ test('stream', async () => {
72
+ const [clientTransport, serverTransport] = getTransports();
73
+ const serviceDefs = { test: TestServiceConstructor() };
74
+ const server = await createServer(serverTransport, serviceDefs);
75
+ const client = createClient(clientTransport);
76
+ let serverListeners = serverTransport.messageHandlers.size;
77
+ let clientListeners = clientTransport.messageHandlers.size;
78
+ // start procedure
79
+ const [input, output, close] = await client.test.echo.stream();
80
+ input.push({ msg: '1', ignore: false });
81
+ input.push({ msg: '2', ignore: false, end: true });
82
+ input.end();
83
+ const result1 = await iterNext(output);
84
+ assert(result1.ok);
85
+ expect(result1.payload).toStrictEqual({ response: '1' });
86
+ const result2 = await iterNext(output);
87
+ assert(result2.ok);
88
+ expect(result2.payload).toStrictEqual({ response: '2' });
89
+ // ensure we exactly have one stream even after we send multiple messages
90
+ expect(server.streams.size).toEqual(1);
91
+ const result3 = await output.next();
92
+ assert(result3.done);
93
+ close();
94
+ // end procedure
95
+ // number of message handlers shouldn't increase after stream ends
96
+ expect(serverTransport.messageHandlers.size).toEqual(serverListeners);
97
+ expect(clientTransport.messageHandlers.size).toEqual(clientListeners);
98
+ // check number of connections
99
+ expect(serverTransport.connections.size).toEqual(1);
100
+ expect(clientTransport.connections.size).toEqual(1);
101
+ await ensureTransportQueuesAreEventuallyEmpty(clientTransport);
102
+ await ensureTransportQueuesAreEventuallyEmpty(serverTransport);
103
+ // ensure we have no streams left on the server
104
+ await ensureServerIsClean(server);
105
+ });
106
+ test('subscription', async () => {
107
+ const [clientTransport, serverTransport] = getTransports();
108
+ const serviceDefs = { test: SubscribableServiceConstructor() };
109
+ const server = await createServer(serverTransport, serviceDefs);
110
+ const client = createClient(clientTransport);
111
+ let serverListeners = serverTransport.messageHandlers.size;
112
+ let clientListeners = clientTransport.messageHandlers.size;
113
+ // start procedure
114
+ const [subscription, close] = await client.test.value.subscribe({});
115
+ let result = await iterNext(subscription);
116
+ assert(result.ok);
117
+ expect(result.payload).toStrictEqual({ result: 0 });
118
+ const add1 = await client.test.add.rpc({ n: 1 });
119
+ assert(add1.ok);
120
+ result = await iterNext(subscription);
121
+ assert(result.ok);
122
+ expect(result.payload).toStrictEqual({ result: 1 });
123
+ close();
124
+ // end procedure
125
+ // number of message handlers shouldn't increase after stream ends
126
+ expect(serverTransport.messageHandlers.size).toEqual(serverListeners);
127
+ expect(clientTransport.messageHandlers.size).toEqual(clientListeners);
128
+ // check number of connections
129
+ expect(serverTransport.connections.size).toEqual(1);
130
+ expect(clientTransport.connections.size).toEqual(1);
131
+ await ensureTransportQueuesAreEventuallyEmpty(clientTransport);
132
+ await ensureTransportQueuesAreEventuallyEmpty(serverTransport);
133
+ // ensure we have no streams left on the server
134
+ await ensureServerIsClean(server);
135
+ });
136
+ });
@@ -1,6 +1,6 @@
1
1
  import { expect, describe, test } from 'vitest';
2
2
  import { serializeService } from '../router/builder';
3
- import { BinaryFileServiceConstructor, FallibleServiceConstructor, TestServiceConstructor, } from './fixtures';
3
+ import { BinaryFileServiceConstructor, FallibleServiceConstructor, TestServiceConstructor, } from './fixtures/services';
4
4
  describe('serialize service to jsonschema', () => {
5
5
  test('serialize basic service', () => {
6
6
  const service = TestServiceConstructor();
@@ -31,6 +31,7 @@ describe('serialize service to jsonschema', () => {
31
31
  properties: {
32
32
  msg: { type: 'string' },
33
33
  ignore: { type: 'boolean' },
34
+ end: { type: 'boolean' },
34
35
  },
35
36
  required: ['msg', 'ignore'],
36
37
  type: 'object',
@@ -6,7 +6,7 @@ import { Result, RiverError, RiverUncaughtSchema } from './result';
6
6
  /**
7
7
  * The valid {@link Procedure} types.
8
8
  */
9
- export type ValidProcType = 'stream' | 'rpc';
9
+ export type ValidProcType = 'rpc' | 'stream' | 'subscription';
10
10
  /**
11
11
  * A generic procedure listing where the keys are the names of the procedures
12
12
  * and the values are the {@link Procedure} definitions. This is not meant to
@@ -65,7 +65,7 @@ export type ProcType<S extends AnyService, ProcName extends keyof S['procedures'
65
65
  /**
66
66
  * Defines a Procedure type that can be either an RPC or a stream procedure.
67
67
  * @template State - The TypeBox schema of the state object.
68
- * @template Ty - The type of the procedure, either 'rpc' or 'stream'.
68
+ * @template Ty - The type of the procedure.
69
69
  * @template I - The TypeBox schema of the input object.
70
70
  * @template O - The TypeBox schema of the output object.
71
71
  */
@@ -75,13 +75,19 @@ export type Procedure<State extends object | unknown, Ty extends ValidProcType,
75
75
  errors: E;
76
76
  handler: (context: ServiceContextWithState<State>, input: TransportMessage<Static<I>>) => Promise<TransportMessage<Result<Static<O>, Static<E>>>>;
77
77
  type: Ty;
78
- } : {
78
+ } : Ty extends 'stream' ? {
79
79
  input: I;
80
80
  output: O;
81
81
  errors: E;
82
82
  handler: (context: ServiceContextWithState<State>, input: AsyncIterable<TransportMessage<Static<I>>>, output: Pushable<TransportMessage<Result<Static<O>, Static<E>>>>) => Promise<void>;
83
83
  type: Ty;
84
- };
84
+ } : Ty extends 'subscription' ? {
85
+ input: I;
86
+ output: O;
87
+ errors: E;
88
+ handler: (context: ServiceContextWithState<State>, input: TransportMessage<Static<I>>, output: Pushable<TransportMessage<Result<Static<O>, Static<E>>>>) => Promise<void>;
89
+ type: Ty;
90
+ } : never;
85
91
  export type AnyProcedure = Procedure<object, ValidProcType, TObject, TObject, RiverError>;
86
92
  /**
87
93
  * A builder class for creating River Services.
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../router/builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAQ,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,WAAW,OAAO,CACtB,IAAI,SAAS,MAAM,EACnB,KAAK,SAAS,MAAM,EAIpB,KAAK,SAAS,WAAW;IAEzB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,KAAK,CAAC;CACnB;AACD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAgBtD;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,CACrB,CAAC,SAAS,UAAU,EACpB,QAAQ,SAAS,MAAM,CAAC,CAAC,YAAY,CAAC,IACpC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;AAEzC;;;;GAIG;AACH,MAAM,MAAM,SAAS,CACnB,CAAC,SAAS,UAAU,EACpB,QAAQ,SAAS,MAAM,CAAC,CAAC,YAAY,CAAC,IACpC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;AAEvC;;;;GAIG;AACH,MAAM,MAAM,UAAU,CACpB,CAAC,SAAS,UAAU,EACpB,QAAQ,SAAS,MAAM,CAAC,CAAC,YAAY,CAAC,IACpC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,UAAU,CACpB,CAAC,SAAS,UAAU,EACpB,QAAQ,SAAS,MAAM,CAAC,CAAC,YAAY,CAAC,IACpC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,mBAAmB,CAAC,CAAC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,QAAQ,CAClB,CAAC,SAAS,UAAU,EACpB,QAAQ,SAAS,MAAM,CAAC,CAAC,YAAY,CAAC,IACpC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,CACnB,KAAK,SAAS,MAAM,GAAG,OAAO,EAC9B,EAAE,SAAS,aAAa,EACxB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,UAAU,IAClB,EAAE,SAAS,KAAK,GAChB;IACE,KAAK,EAAE,CAAC,CAAC;IACT,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,EAAE,CACP,OAAO,EAAE,uBAAuB,CAAC,KAAK,CAAC,EACvC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAC/B,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,IAAI,EAAE,EAAE,CAAC;CACV,GACD;IACE,KAAK,EAAE,CAAC,CAAC;IACT,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,EAAE,CACP,OAAO,EAAE,uBAAuB,CAAC,KAAK,CAAC,EACvC,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EACjD,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAC7D,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,IAAI,EAAE,EAAE,CAAC;CACV,CAAC;AACN,MAAM,MAAM,YAAY,GAAG,SAAS,CAClC,MAAM,EACN,aAAa,EACb,OAAO,EACP,OAAO,EACP,UAAU,CACX,CAAC;AAEF;;;;GAIG;AACH,qBAAa,cAAc,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC;IACxE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAI;IAC3B,OAAO;IAIP;;;OAGG;IACH,QAAQ,IAAI,CAAC;IAIb;;;;;OAKG;IACH,YAAY,CAAC,SAAS,SAAS,CAAC,CAAC,OAAO,CAAC,EACvC,KAAK,EAAE,SAAS,GACf,cAAc,CAAC;QAChB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAChB,KAAK,EAAE,SAAS,CAAC;QACjB,UAAU,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;KAC7B,CAAC;IAOF;;;;;OAKG;IACH,eAAe,CACb,QAAQ,SAAS,MAAM,EACvB,EAAE,SAAS,aAAa,EACxB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,UAAU,EAEpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC1C,cAAc,CAAC;QAChB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAClB,UAAU,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG;aAC3B,CAAC,IAAI,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACpD,CAAC;KACH,CAAC;IAgBF;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,SAAS,MAAM,EAC/B,IAAI,EAAE,IAAI,GACT,cAAc,CAAC;QAChB,IAAI,EAAE,IAAI,CAAC;QACX,KAAK,EAAE,EAAE,CAAC;QACV,UAAU,EAAE,EAAE,CAAC;KAChB,CAAC;CAOH"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../router/builder.ts"],"names":[],"mappings":"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"}
@@ -12,11 +12,20 @@ type AsyncIter<T> = AsyncGenerator<T, T, unknown>;
12
12
  * @template Router - The type of the Router.
13
13
  */
14
14
  type ServiceClient<Router extends AnyService> = {
15
- [ProcName in keyof Router['procedures']]: ProcType<Router, ProcName> extends 'rpc' ? (input: Static<ProcInput<Router, ProcName>>) => Promise<Result<Static<ProcOutput<Router, ProcName>>, Static<ProcErrors<Router, ProcName>>>> : () => Promise<[
16
- Pushable<Static<ProcInput<Router, ProcName>>>,
17
- AsyncIter<Result<Static<ProcOutput<Router, ProcName>>, Static<ProcErrors<Router, ProcName>>>>,
18
- () => void
19
- ]>;
15
+ [ProcName in keyof Router['procedures']]: ProcType<Router, ProcName> extends 'rpc' ? {
16
+ rpc: (input: Static<ProcInput<Router, ProcName>>) => Promise<Result<Static<ProcOutput<Router, ProcName>>, Static<ProcErrors<Router, ProcName>>>>;
17
+ } : ProcType<Router, ProcName> extends 'stream' ? {
18
+ stream: () => Promise<[
19
+ Pushable<Static<ProcInput<Router, ProcName>>>,
20
+ AsyncIter<Result<Static<ProcOutput<Router, ProcName>>, Static<ProcErrors<Router, ProcName>>>>,
21
+ () => void
22
+ ]>;
23
+ } : ProcType<Router, ProcName> extends 'subscription' ? {
24
+ subscribe: (input: Static<ProcInput<Router, ProcName>>) => Promise<[
25
+ AsyncIter<Result<Static<ProcOutput<Router, ProcName>>, Static<ProcErrors<Router, ProcName>>>>,
26
+ () => void
27
+ ]>;
28
+ } : never;
20
29
  };
21
30
  /**
22
31
  * Defines a type that represents a client for a server with a set of services.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../router/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACT,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAIL,iBAAiB,EAElB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,KAAK,SAAS,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAElD;;;;GAIG;AACH,KAAK,aAAa,CAAC,MAAM,SAAS,UAAU,IAAI;KAC7C,QAAQ,IAAI,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,QAAQ,CAChD,MAAM,EACN,QAAQ,CACT,SAAS,KAAK,GAEX,CACE,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,KACvC,OAAO,CACV,MAAM,CACJ,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EACpC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CACrC,CACF,GAED,MAAM,OAAO,CACX;QACE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC7C,SAAS,CACP,MAAM,CACJ,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EACpC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CACrC,CACF;QACD,MAAM,IAAI;KACX,CACF;CACN,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,IAAI;KACxE,OAAO,IAAI,MAAM,GAAG,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;CAC5E,CAAC;AAgCF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,8DACZ,UAAU,UAAU,CAAC,aACtB,iBAAiB,sBAkFA,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../router/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACT,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAIL,iBAAiB,EAGlB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,KAAK,SAAS,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAElD;;;;GAIG;AACH,KAAK,aAAa,CAAC,MAAM,SAAS,UAAU,IAAI;KAC7C,QAAQ,IAAI,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,QAAQ,CAChD,MAAM,EACN,QAAQ,CACT,SAAS,KAAK,GACX;QACE,GAAG,EAAE,CACH,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,KACvC,OAAO,CACV,MAAM,CACJ,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EACpC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CACrC,CACF,CAAC;KACH,GACD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,QAAQ,GAC3C;QACE,MAAM,EAAE,MAAM,OAAO,CACnB;YACE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7C,SAAS,CACP,MAAM,CACJ,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EACpC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CACrC,CACF;YACD,MAAM,IAAI;SACX,CACF,CAAC;KACH,GACD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,cAAc,GACjD;QACE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,OAAO,CAChE;YACE,SAAS,CACP,MAAM,CACJ,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EACpC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CACrC,CACF;YACD,MAAM,IAAI;SACX,CACF,CAAC;KACH,GACD,KAAK;CACV,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,IAAI;KACxE,OAAO,IAAI,MAAM,GAAG,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;CAC5E,CAAC;AAgCF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,8DACZ,UAAU,UAAU,CAAC,aACtB,iBAAiB,sBAoIA,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { pushable } from 'it-pushable';
2
- import { msg, } from '../transport/message';
2
+ import { msg, isStreamClose, closeStream, } from '../transport/message';
3
3
  import { waitForMessage } from '../transport';
4
4
  import { nanoid } from 'nanoid';
5
5
  const noop = () => { };
@@ -35,7 +35,10 @@ function _createRecursiveProxy(callback, path) {
35
35
  * @returns The client for the server.
36
36
  */
37
37
  export const createClient = (transport, serverId = 'SERVER') => _createRecursiveProxy(async (opts) => {
38
- const [serviceName, procName] = [...opts.path];
38
+ const [serviceName, procName, procType] = [...opts.path];
39
+ if (!(serviceName && procName && procType)) {
40
+ throw new Error('invalid river call, ensure the service and procedure you are calling exists');
41
+ }
39
42
  const [input] = opts.args;
40
43
  const streamId = nanoid();
41
44
  function belongsToSameStream(msg) {
@@ -43,22 +46,28 @@ export const createClient = (transport, serverId = 'SERVER') => _createRecursive
43
46
  msg.procedureName === procName &&
44
47
  msg.streamId === streamId);
45
48
  }
46
- if (input === undefined) {
47
- // stream case (stream methods are called with zero arguments)
49
+ if (procType === 'stream') {
48
50
  const inputStream = pushable({ objectMode: true });
49
51
  const outputStream = pushable({ objectMode: true });
52
+ let firstMessage = true;
50
53
  // input -> transport
51
54
  // this gets cleaned up on i.end() which is called by closeHandler
52
55
  (async () => {
53
56
  for await (const rawIn of inputStream) {
54
57
  const m = msg(transport.clientId, serverId, serviceName, procName, streamId, rawIn);
55
- m.controlFlags |= 2 /* ControlFlags.StreamOpenBit */;
58
+ if (firstMessage) {
59
+ m.controlFlags |= 2 /* ControlFlags.StreamOpenBit */;
60
+ firstMessage = false;
61
+ }
56
62
  transport.send(m);
57
63
  }
58
64
  })();
59
65
  // transport -> output
60
66
  const listener = (msg) => {
61
- if (belongsToSameStream(msg)) {
67
+ if (isStreamClose(msg.controlFlags)) {
68
+ outputStream.end();
69
+ }
70
+ else if (belongsToSameStream(msg)) {
62
71
  outputStream.push(msg.payload);
63
72
  }
64
73
  };
@@ -66,15 +75,12 @@ export const createClient = (transport, serverId = 'SERVER') => _createRecursive
66
75
  const closeHandler = () => {
67
76
  inputStream.end();
68
77
  outputStream.end();
69
- const closeMessage = msg(transport.clientId, serverId, serviceName, procName, streamId, { type: 'CLOSE' });
70
- closeMessage.controlFlags |= 4 /* ControlFlags.StreamClosedBit */;
71
- transport.send(closeMessage);
78
+ transport.send(closeStream(transport.clientId, serverId, serviceName, procName, streamId));
72
79
  transport.removeMessageListener(listener);
73
80
  };
74
81
  return [inputStream, outputStream, closeHandler];
75
82
  }
76
- else {
77
- // rpc case
83
+ else if (procType === 'rpc') {
78
84
  const m = msg(transport.clientId, serverId, serviceName, procName, streamId, input);
79
85
  // rpc is a stream open + close
80
86
  m.controlFlags |=
@@ -82,4 +88,29 @@ export const createClient = (transport, serverId = 'SERVER') => _createRecursive
82
88
  transport.send(m);
83
89
  return waitForMessage(transport, belongsToSameStream);
84
90
  }
91
+ else if (procType === 'subscribe') {
92
+ const m = msg(transport.clientId, serverId, serviceName, procName, streamId, input);
93
+ m.controlFlags |= 2 /* ControlFlags.StreamOpenBit */;
94
+ transport.send(m);
95
+ // transport -> output
96
+ const outputStream = pushable({ objectMode: true });
97
+ const listener = (msg) => {
98
+ if (belongsToSameStream(msg)) {
99
+ outputStream.push(msg.payload);
100
+ }
101
+ if (isStreamClose(msg.controlFlags)) {
102
+ outputStream.end();
103
+ }
104
+ };
105
+ transport.addMessageListener(listener);
106
+ const closeHandler = () => {
107
+ outputStream.end();
108
+ transport.send(closeStream(transport.clientId, serverId, serviceName, procName, streamId));
109
+ transport.removeMessageListener(listener);
110
+ };
111
+ return [outputStream, closeHandler];
112
+ }
113
+ else {
114
+ throw new Error(`invalid river call, unknown procedure type ${procType}`);
115
+ }
85
116
  }, []);
@@ -1,14 +1,27 @@
1
+ import { Static, TObject } from '@sinclair/typebox';
1
2
  import { Connection, Transport } from '../transport/transport';
2
3
  import { AnyService } from './builder';
4
+ import type { Pushable } from 'it-pushable';
5
+ import { TransportMessage } from '../transport/message';
3
6
  import { ServiceContext } from './context';
7
+ import { Result, RiverError } from './result';
4
8
  /**
5
9
  * Represents a server with a set of services. Use {@link createServer} to create it.
6
10
  * @template Services - The type of services provided by the server.
7
11
  */
8
12
  export interface Server<Services> {
9
13
  services: Services;
14
+ streams: Map<string, ProcStream>;
10
15
  close(): Promise<void>;
11
16
  }
17
+ interface ProcStream {
18
+ incoming: Pushable<TransportMessage>;
19
+ outgoing: Pushable<TransportMessage<Result<Static<TObject>, Static<RiverError>>>>;
20
+ promises: {
21
+ outputHandler: Promise<unknown>;
22
+ inputHandler: Promise<unknown>;
23
+ };
24
+ }
12
25
  /**
13
26
  * Creates a server instance that listens for incoming messages from a transport and routes them to the appropriate service and procedure.
14
27
  * The server tracks the state of each service along with open streams and the extended context object.
@@ -18,4 +31,5 @@ export interface Server<Services> {
18
31
  * @returns A promise that resolves to a server instance with the registered services.
19
32
  */
20
33
  export declare function createServer<Services extends Record<string, AnyService>>(transport: Transport<Connection>, services: Services, extendedContext?: Omit<ServiceContext, 'state'>): Promise<Server<Services>>;
34
+ export {};
21
35
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../router/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAgB,UAAU,EAAE,MAAM,WAAW,CAAC;AAWrD,OAAO,EAAE,cAAc,EAA2B,MAAM,WAAW,CAAC;AAWpE;;;GAGG;AACH,MAAM,WAAW,MAAM,CAAC,QAAQ;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAWD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAC5E,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,EAChC,QAAQ,EAAE,QAAQ,EAClB,eAAe,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAqJ3B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../router/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAgB,UAAU,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAGL,gBAAgB,EAKjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAA2B,MAAM,WAAW,CAAC;AAGpE,OAAO,EAEL,MAAM,EACN,UAAU,EAGX,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,WAAW,MAAM,CAAC,QAAQ;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,UAAU,UAAU;IAClB,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACrC,QAAQ,EAAE,QAAQ,CAChB,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAC9D,CAAC;IACF,QAAQ,EAAE;QACR,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;CACH;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAC5E,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,EAChC,QAAQ,EAAE,QAAQ,EAClB,eAAe,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAuM3B"}