@replit/river 0.1.10 → 0.2.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.
- package/README.md +0 -10
- package/dist/__tests__/bandwidth.bench.d.ts +1 -0
- package/dist/__tests__/bandwidth.bench.js +82 -0
- package/dist/__tests__/integration.test.js +70 -30
- package/dist/__tests__/largePayload.json +33 -0
- package/dist/__tests__/typescript-stress.test.d.ts +740 -0
- package/dist/__tests__/typescript-stress.test.js +10 -8
- package/dist/codec/codec.test.js +6 -0
- package/dist/codec/json.js +8 -1
- package/dist/codec/types.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/logging/index.d.ts +15 -0
- package/dist/logging/index.js +29 -0
- package/dist/router/client.js +9 -9
- package/dist/router/server.js +6 -3
- package/dist/transport/message.d.ts +1 -0
- package/dist/transport/message.js +2 -0
- package/dist/transport/types.js +14 -2
- package/dist/transport/util.d.ts +4 -4
- package/dist/transport/util.js +26 -21
- package/dist/transport/ws.d.ts +19 -4
- package/dist/transport/ws.js +87 -10
- package/dist/transport/ws.test.js +63 -29
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import { bench, describe } from 'vitest';
|
|
3
|
+
import { createWebSocketServer, createWsTransports, onServerReady, waitForMessage, } from '../transport/util';
|
|
4
|
+
import largePayload from './largePayload.json';
|
|
5
|
+
import { TestServiceConstructor } from './integration.test';
|
|
6
|
+
import { createServer } from '../router/server';
|
|
7
|
+
import { createClient } from '../router/client';
|
|
8
|
+
import { StupidlyLargeService } from './typescript-stress.test';
|
|
9
|
+
let smallId = 0;
|
|
10
|
+
let largeId = 0;
|
|
11
|
+
const dummyPayloadSmall = () => ({
|
|
12
|
+
id: `${smallId++}`,
|
|
13
|
+
from: 'client',
|
|
14
|
+
to: 'SERVER',
|
|
15
|
+
serviceName: 'test',
|
|
16
|
+
procedureName: 'test',
|
|
17
|
+
payload: {
|
|
18
|
+
msg: 'cool',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
const dummyPayloadLarge = () => ({
|
|
22
|
+
id: `${largeId++}`,
|
|
23
|
+
from: 'client',
|
|
24
|
+
to: 'SERVER',
|
|
25
|
+
serviceName: 'test',
|
|
26
|
+
procedureName: 'test',
|
|
27
|
+
payload: largePayload,
|
|
28
|
+
});
|
|
29
|
+
const BENCH_DURATION = 1000;
|
|
30
|
+
describe('transport level bandwidth', async () => {
|
|
31
|
+
const server = http.createServer();
|
|
32
|
+
const port = await onServerReady(server);
|
|
33
|
+
const webSocketServer = await createWebSocketServer(server);
|
|
34
|
+
const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
|
|
35
|
+
bench('send and recv (small payload)', async () => {
|
|
36
|
+
const id = clientTransport.send(dummyPayloadSmall());
|
|
37
|
+
await waitForMessage(serverTransport, (msg) => msg.id === id);
|
|
38
|
+
return;
|
|
39
|
+
}, { time: BENCH_DURATION });
|
|
40
|
+
bench('send and recv (large payload)', async () => {
|
|
41
|
+
const id = clientTransport.send(dummyPayloadLarge());
|
|
42
|
+
await waitForMessage(serverTransport, (msg) => msg.id === id);
|
|
43
|
+
return;
|
|
44
|
+
}, { time: BENCH_DURATION });
|
|
45
|
+
});
|
|
46
|
+
describe('simple router level bandwidth', async () => {
|
|
47
|
+
const httpServer = http.createServer();
|
|
48
|
+
const port = await onServerReady(httpServer);
|
|
49
|
+
const webSocketServer = await createWebSocketServer(httpServer);
|
|
50
|
+
const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
|
|
51
|
+
const serviceDefs = { test: TestServiceConstructor() };
|
|
52
|
+
const server = await createServer(serverTransport, serviceDefs);
|
|
53
|
+
const client = createClient(clientTransport);
|
|
54
|
+
bench('rpc (wait for response)', async () => {
|
|
55
|
+
await client.test.add({ n: 1 });
|
|
56
|
+
}, { time: BENCH_DURATION });
|
|
57
|
+
const [input, output] = await client.test.echo();
|
|
58
|
+
bench('stream (wait for response)', async () => {
|
|
59
|
+
input.push({ msg: 'abc', ignore: false });
|
|
60
|
+
await output.next();
|
|
61
|
+
}, { time: BENCH_DURATION });
|
|
62
|
+
bench('stream', async () => {
|
|
63
|
+
input.push({ msg: 'abc', ignore: false });
|
|
64
|
+
}, { time: BENCH_DURATION });
|
|
65
|
+
});
|
|
66
|
+
describe('complex (50 procedures) router level bandwidth', async () => {
|
|
67
|
+
const httpServer = http.createServer();
|
|
68
|
+
const port = await onServerReady(httpServer);
|
|
69
|
+
const webSocketServer = await createWebSocketServer(httpServer);
|
|
70
|
+
const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
|
|
71
|
+
const serviceDefs = {
|
|
72
|
+
a: StupidlyLargeService(),
|
|
73
|
+
b: StupidlyLargeService(),
|
|
74
|
+
c: StupidlyLargeService(),
|
|
75
|
+
d: StupidlyLargeService(),
|
|
76
|
+
};
|
|
77
|
+
const server = await createServer(serverTransport, serviceDefs);
|
|
78
|
+
const client = createClient(clientTransport);
|
|
79
|
+
bench('rpc (wait for response)', async () => {
|
|
80
|
+
await client.b.f35({ a: 1 });
|
|
81
|
+
}, { time: BENCH_DURATION });
|
|
82
|
+
});
|
|
@@ -2,7 +2,7 @@ import http from 'http';
|
|
|
2
2
|
import { Type } from '@sinclair/typebox';
|
|
3
3
|
import { ServiceBuilder, serializeService } from '../router/builder';
|
|
4
4
|
import { reply } from '../transport/message';
|
|
5
|
-
import { afterAll,
|
|
5
|
+
import { afterAll, describe, expect, test } from 'vitest';
|
|
6
6
|
import { createWebSocketServer, createWsTransports, onServerReady, } from '../transport/util';
|
|
7
7
|
import { createServer } from '../router/server';
|
|
8
8
|
import { createClient } from '../router/client';
|
|
@@ -40,6 +40,29 @@ export const TestServiceConstructor = () => ServiceBuilder.create('test')
|
|
|
40
40
|
},
|
|
41
41
|
})
|
|
42
42
|
.finalize();
|
|
43
|
+
const OrderingServiceConstructor = () => ServiceBuilder.create('test')
|
|
44
|
+
.initialState({
|
|
45
|
+
msgs: [],
|
|
46
|
+
})
|
|
47
|
+
.defineProcedure('add', {
|
|
48
|
+
type: 'rpc',
|
|
49
|
+
input: Type.Object({ n: Type.Number() }),
|
|
50
|
+
output: Type.Object({ ok: Type.Boolean() }),
|
|
51
|
+
async handler(ctx, msg) {
|
|
52
|
+
const { n } = msg.payload;
|
|
53
|
+
ctx.state.msgs.push(n);
|
|
54
|
+
return reply(msg, { ok: true });
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
.defineProcedure('getAll', {
|
|
58
|
+
type: 'rpc',
|
|
59
|
+
input: Type.Object({}),
|
|
60
|
+
output: Type.Object({ msgs: Type.Array(Type.Number()) }),
|
|
61
|
+
async handler(ctx, msg) {
|
|
62
|
+
return reply(msg, { msgs: ctx.state.msgs });
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
.finalize();
|
|
43
66
|
test('serialize service to jsonschema', () => {
|
|
44
67
|
const service = TestServiceConstructor();
|
|
45
68
|
expect(serializeService(service)).toStrictEqual({
|
|
@@ -96,59 +119,76 @@ describe('server-side test', () => {
|
|
|
96
119
|
await expect(add({ n: 6 })).resolves.toStrictEqual({ result: 11 });
|
|
97
120
|
});
|
|
98
121
|
test('stream basic', async () => {
|
|
99
|
-
const [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
await expect(
|
|
122
|
+
const [input, output] = asClientStream(initialState, service.procedures.echo);
|
|
123
|
+
input.push({ msg: 'abc', ignore: false });
|
|
124
|
+
input.push({ msg: 'def', ignore: true });
|
|
125
|
+
input.push({ msg: 'ghi', ignore: false });
|
|
126
|
+
input.end();
|
|
127
|
+
await expect(output.next().then((res) => res.value)).resolves.toStrictEqual({
|
|
105
128
|
response: 'abc',
|
|
106
129
|
});
|
|
107
|
-
await expect(
|
|
130
|
+
await expect(output.next().then((res) => res.value)).resolves.toStrictEqual({
|
|
108
131
|
response: 'ghi',
|
|
109
132
|
});
|
|
110
|
-
expect(
|
|
133
|
+
expect(output.readableLength).toBe(0);
|
|
111
134
|
});
|
|
112
135
|
});
|
|
113
|
-
|
|
114
|
-
describe('client <-> server integration test', () => {
|
|
136
|
+
describe('client <-> server integration test', async () => {
|
|
115
137
|
const server = http.createServer();
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
await onServerReady(server, port);
|
|
119
|
-
wss = await createWebSocketServer(server);
|
|
120
|
-
});
|
|
138
|
+
const port = await onServerReady(server);
|
|
139
|
+
const webSocketServer = await createWebSocketServer(server);
|
|
121
140
|
afterAll(() => {
|
|
122
|
-
|
|
141
|
+
webSocketServer.clients.forEach((socket) => {
|
|
123
142
|
socket.close();
|
|
124
143
|
});
|
|
125
144
|
server.close();
|
|
126
145
|
});
|
|
127
146
|
test('rpc', async () => {
|
|
128
|
-
const [
|
|
147
|
+
const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
|
|
129
148
|
const serviceDefs = { test: TestServiceConstructor() };
|
|
130
|
-
const server = await createServer(
|
|
131
|
-
const client = createClient(
|
|
149
|
+
const server = await createServer(serverTransport, serviceDefs);
|
|
150
|
+
const client = createClient(clientTransport);
|
|
132
151
|
await expect(client.test.add({ n: 3 })).resolves.toStrictEqual({
|
|
133
152
|
result: 3,
|
|
134
153
|
});
|
|
135
154
|
});
|
|
136
155
|
test('stream', async () => {
|
|
137
|
-
const [
|
|
156
|
+
const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
|
|
138
157
|
const serviceDefs = { test: TestServiceConstructor() };
|
|
139
|
-
const server = await createServer(
|
|
140
|
-
const client = createClient(
|
|
141
|
-
const [
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
await expect(
|
|
158
|
+
const server = await createServer(serverTransport, serviceDefs);
|
|
159
|
+
const client = createClient(clientTransport);
|
|
160
|
+
const [input, output, close] = await client.test.echo();
|
|
161
|
+
input.push({ msg: 'abc', ignore: false });
|
|
162
|
+
input.push({ msg: 'def', ignore: true });
|
|
163
|
+
input.push({ msg: 'ghi', ignore: false });
|
|
164
|
+
input.end();
|
|
165
|
+
await expect(output.next().then((res) => res.value)).resolves.toStrictEqual({
|
|
147
166
|
response: 'abc',
|
|
148
167
|
});
|
|
149
|
-
await expect(
|
|
168
|
+
await expect(output.next().then((res) => res.value)).resolves.toStrictEqual({
|
|
150
169
|
response: 'ghi',
|
|
151
170
|
});
|
|
152
171
|
close();
|
|
153
172
|
});
|
|
173
|
+
test('message order is preserved in the face of disconnects', async () => {
|
|
174
|
+
const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
|
|
175
|
+
const serviceDefs = { test: OrderingServiceConstructor() };
|
|
176
|
+
const server = await createServer(serverTransport, serviceDefs);
|
|
177
|
+
const client = createClient(clientTransport);
|
|
178
|
+
const expected = [];
|
|
179
|
+
for (let i = 0; i < 50; i++) {
|
|
180
|
+
expected.push(i);
|
|
181
|
+
if (i == 10) {
|
|
182
|
+
clientTransport.ws?.close();
|
|
183
|
+
}
|
|
184
|
+
if (i == 42) {
|
|
185
|
+
clientTransport.ws?.terminate();
|
|
186
|
+
}
|
|
187
|
+
await client.test.add({
|
|
188
|
+
n: i,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const res = await client.test.getAll({});
|
|
192
|
+
return expect(res.msgs).toStrictEqual(expected);
|
|
193
|
+
});
|
|
154
194
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [
|
|
3
|
+
{
|
|
4
|
+
"type": "articles",
|
|
5
|
+
"id": "1",
|
|
6
|
+
"attributes": {
|
|
7
|
+
"title": "Example article",
|
|
8
|
+
"body": "The shortest article. Ever.",
|
|
9
|
+
"created": "2015-05-22T14:56:29.000Z",
|
|
10
|
+
"updated": "2015-05-22T14:56:28.000Z"
|
|
11
|
+
},
|
|
12
|
+
"relationships": {
|
|
13
|
+
"author": {
|
|
14
|
+
"data": {
|
|
15
|
+
"id": "42",
|
|
16
|
+
"type": "people"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"included": [
|
|
23
|
+
{
|
|
24
|
+
"type": "people",
|
|
25
|
+
"id": "42",
|
|
26
|
+
"attributes": {
|
|
27
|
+
"name": "John",
|
|
28
|
+
"age": 21,
|
|
29
|
+
"gender": "male"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|