@replit/river 0.10.0 → 0.10.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/dist/{router/builder.d.ts → builder-3c4485f0.d.ts} +76 -21
- package/dist/chunk-7WJ6YLE5.js +683 -0
- package/dist/chunk-AJQU4AZG.js +284 -0
- package/dist/chunk-ORAG7IAU.js +0 -0
- package/dist/chunk-PC65ZFWJ.js +29 -0
- package/dist/chunk-R6H2BIMC.js +49 -0
- package/dist/chunk-RGMHF6PF.js +65 -0
- package/dist/chunk-SLUSVGQH.js +30 -0
- package/dist/chunk-UU2Z7LDR.js +113 -0
- package/dist/chunk-WVT5QXMZ.js +20 -0
- package/dist/chunk-ZE4MX7DF.js +75 -0
- package/dist/codec/index.cjs +94 -0
- package/dist/codec/index.d.cts +15 -0
- package/dist/codec/index.d.ts +15 -4
- package/dist/codec/index.js +10 -2
- package/dist/connection-8e19874c.d.ts +11 -0
- package/dist/connection-f7688cc1.d.ts +11 -0
- package/dist/logging/index.cjs +56 -0
- package/dist/logging/index.d.cts +28 -0
- package/dist/logging/index.d.ts +6 -6
- package/dist/logging/index.js +9 -40
- package/dist/router/index.cjs +770 -0
- package/dist/router/index.d.cts +114 -0
- package/dist/router/index.d.ts +114 -12
- package/dist/router/index.js +24 -5
- package/dist/transport/impls/ws/client.cjs +505 -0
- package/dist/transport/impls/ws/client.d.cts +42 -0
- package/dist/transport/impls/ws/client.d.ts +8 -8
- package/dist/transport/impls/ws/client.js +10 -100
- package/dist/transport/impls/ws/server.cjs +457 -0
- package/dist/transport/impls/ws/server.d.cts +21 -0
- package/dist/transport/impls/ws/server.d.ts +11 -10
- package/dist/transport/impls/ws/server.js +11 -52
- package/dist/transport/index.cjs +362 -0
- package/dist/transport/{transport.d.ts → index.d.cts} +119 -7
- package/dist/transport/index.d.ts +273 -4
- package/dist/transport/index.js +20 -2
- package/dist/{codec/types.d.ts → types-3e5768ec.d.ts} +3 -2
- package/dist/util/testHelpers.cjs +731 -0
- package/dist/util/testHelpers.d.cts +79 -0
- package/dist/util/testHelpers.d.ts +22 -19
- package/dist/util/testHelpers.js +135 -163
- package/package.json +41 -13
- package/dist/__tests__/bandwidth.bench.d.ts +0 -2
- package/dist/__tests__/bandwidth.bench.d.ts.map +0 -1
- package/dist/__tests__/bandwidth.bench.js +0 -90
- package/dist/__tests__/cleanup.test.d.ts +0 -2
- package/dist/__tests__/cleanup.test.d.ts.map +0 -1
- package/dist/__tests__/cleanup.test.js +0 -165
- package/dist/__tests__/disconnects.test.d.ts +0 -2
- package/dist/__tests__/disconnects.test.d.ts.map +0 -1
- package/dist/__tests__/disconnects.test.js +0 -163
- package/dist/__tests__/e2e.test.d.ts +0 -2
- package/dist/__tests__/e2e.test.d.ts.map +0 -1
- package/dist/__tests__/e2e.test.js +0 -317
- package/dist/__tests__/fixtures/cleanup.d.ts +0 -12
- package/dist/__tests__/fixtures/cleanup.d.ts.map +0 -1
- package/dist/__tests__/fixtures/cleanup.js +0 -36
- package/dist/__tests__/fixtures/largePayload.json +0 -33
- package/dist/__tests__/fixtures/observable.d.ts +0 -26
- package/dist/__tests__/fixtures/observable.d.ts.map +0 -1
- package/dist/__tests__/fixtures/observable.js +0 -38
- package/dist/__tests__/fixtures/observable.test.d.ts +0 -2
- package/dist/__tests__/fixtures/observable.test.d.ts.map +0 -1
- package/dist/__tests__/fixtures/observable.test.js +0 -39
- package/dist/__tests__/fixtures/services.d.ts +0 -288
- package/dist/__tests__/fixtures/services.d.ts.map +0 -1
- package/dist/__tests__/fixtures/services.js +0 -207
- package/dist/__tests__/handler.test.d.ts +0 -2
- package/dist/__tests__/handler.test.d.ts.map +0 -1
- package/dist/__tests__/handler.test.js +0 -120
- package/dist/__tests__/serialize.test.d.ts +0 -2
- package/dist/__tests__/serialize.test.d.ts.map +0 -1
- package/dist/__tests__/serialize.test.js +0 -208
- package/dist/__tests__/typescript-stress.test.d.ts +0 -1583
- package/dist/__tests__/typescript-stress.test.d.ts.map +0 -1
- package/dist/__tests__/typescript-stress.test.js +0 -123
- package/dist/codec/binary.d.ts +0 -7
- package/dist/codec/binary.d.ts.map +0 -1
- package/dist/codec/binary.js +0 -20
- package/dist/codec/codec.test.d.ts +0 -5
- package/dist/codec/codec.test.d.ts.map +0 -1
- package/dist/codec/codec.test.js +0 -41
- package/dist/codec/index.d.ts.map +0 -1
- package/dist/codec/json.d.ts +0 -7
- package/dist/codec/json.d.ts.map +0 -1
- package/dist/codec/json.js +0 -51
- package/dist/codec/types.d.ts.map +0 -1
- package/dist/codec/types.js +0 -1
- package/dist/logging/index.d.ts.map +0 -1
- package/dist/router/builder.d.ts.map +0 -1
- package/dist/router/builder.js +0 -91
- package/dist/router/client.d.ts +0 -72
- package/dist/router/client.d.ts.map +0 -1
- package/dist/router/client.js +0 -257
- package/dist/router/context.d.ts +0 -30
- package/dist/router/context.d.ts.map +0 -1
- package/dist/router/context.js +0 -1
- package/dist/router/defs.d.ts +0 -16
- package/dist/router/defs.d.ts.map +0 -1
- package/dist/router/defs.js +0 -11
- package/dist/router/index.d.ts.map +0 -1
- package/dist/router/result.d.ts +0 -26
- package/dist/router/result.d.ts.map +0 -1
- package/dist/router/result.js +0 -22
- package/dist/router/server.d.ts +0 -39
- package/dist/router/server.d.ts.map +0 -1
- package/dist/router/server.js +0 -260
- package/dist/transport/events.d.ts +0 -19
- package/dist/transport/events.d.ts.map +0 -1
- package/dist/transport/events.js +0 -26
- package/dist/transport/impls/stdio/stdio.d.ts +0 -33
- package/dist/transport/impls/stdio/stdio.d.ts.map +0 -1
- package/dist/transport/impls/stdio/stdio.js +0 -75
- package/dist/transport/impls/stdio/stdio.test.d.ts +0 -2
- package/dist/transport/impls/stdio/stdio.test.d.ts.map +0 -1
- package/dist/transport/impls/stdio/stdio.test.js +0 -24
- package/dist/transport/impls/ws/client.d.ts.map +0 -1
- package/dist/transport/impls/ws/connection.d.ts +0 -11
- package/dist/transport/impls/ws/connection.d.ts.map +0 -1
- package/dist/transport/impls/ws/connection.js +0 -23
- package/dist/transport/impls/ws/server.d.ts.map +0 -1
- package/dist/transport/impls/ws/ws.test.d.ts +0 -2
- package/dist/transport/impls/ws/ws.test.d.ts.map +0 -1
- package/dist/transport/impls/ws/ws.test.js +0 -185
- package/dist/transport/index.d.ts.map +0 -1
- package/dist/transport/message.d.ts +0 -142
- package/dist/transport/message.d.ts.map +0 -1
- package/dist/transport/message.js +0 -113
- package/dist/transport/message.test.d.ts +0 -2
- package/dist/transport/message.test.d.ts.map +0 -1
- package/dist/transport/message.test.js +0 -52
- package/dist/transport/transport.d.ts.map +0 -1
- package/dist/transport/transport.js +0 -281
- package/dist/util/testHelpers.d.ts.map +0 -1
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import http from 'http';
|
|
2
|
-
import { describe, test, expect, afterAll, vi } from 'vitest';
|
|
3
|
-
import { createWebSocketServer, createWsTransports, createDummyTransportMessage, onServerReady, createLocalWebSocketClient, waitForMessage, } from '../../../util/testHelpers';
|
|
4
|
-
import { msg } from '../..';
|
|
5
|
-
import { WebSocketServerTransport } from './server';
|
|
6
|
-
import { WebSocketClientTransport } from './client';
|
|
7
|
-
import { testFinishesCleanly, waitFor, } from '../../../__tests__/fixtures/cleanup';
|
|
8
|
-
describe('sending and receiving across websockets works', async () => {
|
|
9
|
-
const server = http.createServer();
|
|
10
|
-
const port = await onServerReady(server);
|
|
11
|
-
const wss = await createWebSocketServer(server);
|
|
12
|
-
afterAll(() => {
|
|
13
|
-
wss.close();
|
|
14
|
-
server.close();
|
|
15
|
-
});
|
|
16
|
-
test('basic send/receive', async () => {
|
|
17
|
-
const [clientTransport, serverTransport] = createWsTransports(port, wss);
|
|
18
|
-
const msg = createDummyTransportMessage();
|
|
19
|
-
const msgPromise = waitForMessage(serverTransport, (recv) => recv.id === msg.id);
|
|
20
|
-
clientTransport.send(msg);
|
|
21
|
-
await expect(msgPromise).resolves.toStrictEqual(msg.payload);
|
|
22
|
-
await testFinishesCleanly({
|
|
23
|
-
clientTransports: [clientTransport],
|
|
24
|
-
serverTransport,
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
test('sending respects to/from fields', async () => {
|
|
28
|
-
const makeDummyMessage = (from, to, message) => {
|
|
29
|
-
return msg(from, to, 'stream', {
|
|
30
|
-
msg: message,
|
|
31
|
-
}, 'service', 'proc');
|
|
32
|
-
};
|
|
33
|
-
const clientId1 = 'client1';
|
|
34
|
-
const clientId2 = 'client2';
|
|
35
|
-
const serverId = 'SERVER';
|
|
36
|
-
const serverTransport = new WebSocketServerTransport(wss, serverId);
|
|
37
|
-
const initClient = async (id) => {
|
|
38
|
-
const client = new WebSocketClientTransport(() => createLocalWebSocketClient(port), id, 'SERVER');
|
|
39
|
-
const initMsg = makeDummyMessage(id, serverId, 'hello server');
|
|
40
|
-
const initMsgPromise = waitForMessage(serverTransport, (recv) => recv.id === initMsg.id);
|
|
41
|
-
client.send(initMsg);
|
|
42
|
-
await expect(initMsgPromise).resolves.toStrictEqual(initMsg.payload);
|
|
43
|
-
return client;
|
|
44
|
-
};
|
|
45
|
-
const client1 = await initClient(clientId1);
|
|
46
|
-
const client2 = await initClient(clientId2);
|
|
47
|
-
// sending messages from server to client shouldn't leak between clients
|
|
48
|
-
const msg1 = makeDummyMessage('SERVER', 'client1', 'hello client1');
|
|
49
|
-
const msg2 = makeDummyMessage('SERVER', 'client2', 'hello client1');
|
|
50
|
-
const promises = Promise.all([
|
|
51
|
-
// true means reject if we receive any message that isn't the one we are expecting
|
|
52
|
-
waitForMessage(client2, (recv) => recv.id === msg2.id, true),
|
|
53
|
-
waitForMessage(client1, (recv) => recv.id === msg1.id, true),
|
|
54
|
-
]);
|
|
55
|
-
serverTransport.send(msg1);
|
|
56
|
-
serverTransport.send(msg2);
|
|
57
|
-
await expect(promises).resolves.toStrictEqual([msg1.payload, msg2.payload]);
|
|
58
|
-
await testFinishesCleanly({
|
|
59
|
-
clientTransports: [client1, client2],
|
|
60
|
-
serverTransport,
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
describe('retry logic', async () => {
|
|
65
|
-
const server = http.createServer();
|
|
66
|
-
const port = await onServerReady(server);
|
|
67
|
-
const wss = await createWebSocketServer(server);
|
|
68
|
-
afterAll(() => {
|
|
69
|
-
wss.close();
|
|
70
|
-
server.close();
|
|
71
|
-
});
|
|
72
|
-
// TODO: right now, we only test client-side disconnects, we probably
|
|
73
|
-
// need to also write tests for server-side crashes (but this involves clearing/restoring state)
|
|
74
|
-
// not going to worry about this rn but for future
|
|
75
|
-
test('ws connection is recreated after clean disconnect', async () => {
|
|
76
|
-
const [clientTransport, serverTransport] = createWsTransports(port, wss);
|
|
77
|
-
const msg1 = createDummyTransportMessage();
|
|
78
|
-
const msg2 = createDummyTransportMessage();
|
|
79
|
-
const msg1Promise = waitForMessage(serverTransport, (recv) => recv.id === msg1.id);
|
|
80
|
-
clientTransport.send(msg1);
|
|
81
|
-
await expect(msg1Promise).resolves.toStrictEqual(msg1.payload);
|
|
82
|
-
// clean disconnect
|
|
83
|
-
clientTransport.connections.forEach((conn) => conn.ws.close());
|
|
84
|
-
const msg2Promise = waitForMessage(serverTransport, (recv) => recv.id === msg2.id);
|
|
85
|
-
// by this point the client should have reconnected
|
|
86
|
-
clientTransport.send(msg2);
|
|
87
|
-
await expect(msg2Promise).resolves.toStrictEqual(msg2.payload);
|
|
88
|
-
await testFinishesCleanly({
|
|
89
|
-
clientTransports: [clientTransport],
|
|
90
|
-
serverTransport,
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
test('ws connection is recreated after unclean disconnect', async () => {
|
|
94
|
-
const [clientTransport, serverTransport] = createWsTransports(port, wss);
|
|
95
|
-
const msg1 = createDummyTransportMessage();
|
|
96
|
-
const msg2 = createDummyTransportMessage();
|
|
97
|
-
const msg1Promise = waitForMessage(serverTransport, (recv) => recv.id === msg1.id);
|
|
98
|
-
clientTransport.send(msg1);
|
|
99
|
-
await expect(msg1Promise).resolves.toStrictEqual(msg1.payload);
|
|
100
|
-
// unclean disconnect
|
|
101
|
-
clientTransport.connections.forEach((conn) => conn.ws.terminate());
|
|
102
|
-
const msg2Promise = waitForMessage(serverTransport, (recv) => recv.id === msg2.id);
|
|
103
|
-
// by this point the client should have reconnected
|
|
104
|
-
clientTransport.send(msg2);
|
|
105
|
-
await expect(msg2Promise).resolves.toStrictEqual(msg2.payload);
|
|
106
|
-
await testFinishesCleanly({
|
|
107
|
-
clientTransports: [clientTransport],
|
|
108
|
-
serverTransport,
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
test('both client and server transport gets connection and disconnection notifs', async () => {
|
|
112
|
-
const [clientTransport, serverTransport] = createWsTransports(port, wss);
|
|
113
|
-
const msg1 = createDummyTransportMessage();
|
|
114
|
-
const msg2 = createDummyTransportMessage();
|
|
115
|
-
const onClientConnect = vi.fn();
|
|
116
|
-
const onClientDisconnect = vi.fn();
|
|
117
|
-
const clientHandler = (evt) => {
|
|
118
|
-
if (evt.conn.connectedTo !== serverTransport.clientId)
|
|
119
|
-
return;
|
|
120
|
-
if (evt.status === 'connect')
|
|
121
|
-
return onClientConnect();
|
|
122
|
-
if (evt.status === 'disconnect')
|
|
123
|
-
return onClientDisconnect();
|
|
124
|
-
};
|
|
125
|
-
const onServerConnect = vi.fn();
|
|
126
|
-
const onServerDisconnect = vi.fn();
|
|
127
|
-
const serverHandler = (evt) => {
|
|
128
|
-
if (evt.status === 'connect' &&
|
|
129
|
-
evt.conn.connectedTo === clientTransport.clientId)
|
|
130
|
-
return onServerConnect();
|
|
131
|
-
if (evt.status === 'disconnect' &&
|
|
132
|
-
evt.conn.connectedTo === clientTransport.clientId)
|
|
133
|
-
return onServerDisconnect();
|
|
134
|
-
};
|
|
135
|
-
clientTransport.addEventListener('connectionStatus', clientHandler);
|
|
136
|
-
serverTransport.addEventListener('connectionStatus', serverHandler);
|
|
137
|
-
expect(onClientConnect).toHaveBeenCalledTimes(0);
|
|
138
|
-
expect(onClientDisconnect).toHaveBeenCalledTimes(0);
|
|
139
|
-
expect(onServerConnect).toHaveBeenCalledTimes(0);
|
|
140
|
-
expect(onServerDisconnect).toHaveBeenCalledTimes(0);
|
|
141
|
-
const msg1Promise = waitForMessage(serverTransport, (recv) => recv.id === msg1.id);
|
|
142
|
-
clientTransport.send(msg1);
|
|
143
|
-
await expect(msg1Promise).resolves.toStrictEqual(msg1.payload);
|
|
144
|
-
expect(onClientConnect).toHaveBeenCalledTimes(1);
|
|
145
|
-
expect(onClientDisconnect).toHaveBeenCalledTimes(0);
|
|
146
|
-
expect(onServerConnect).toHaveBeenCalledTimes(1);
|
|
147
|
-
expect(onServerDisconnect).toHaveBeenCalledTimes(0);
|
|
148
|
-
// clean disconnect
|
|
149
|
-
clientTransport.connections.forEach((conn) => conn.ws.close());
|
|
150
|
-
// wait for connection status to propagate to server
|
|
151
|
-
await waitFor(() => expect(onClientConnect).toHaveBeenCalledTimes(1));
|
|
152
|
-
await waitFor(() => expect(onClientDisconnect).toHaveBeenCalledTimes(1));
|
|
153
|
-
await waitFor(() => expect(onServerConnect).toHaveBeenCalledTimes(1));
|
|
154
|
-
await waitFor(() => expect(onServerDisconnect).toHaveBeenCalledTimes(1));
|
|
155
|
-
const msg2Promise = waitForMessage(serverTransport, (recv) => recv.id === msg2.id);
|
|
156
|
-
// by this point the client should have reconnected
|
|
157
|
-
clientTransport.send(msg2);
|
|
158
|
-
await expect(msg2Promise).resolves.toStrictEqual(msg2.payload);
|
|
159
|
-
expect(onClientConnect).toHaveBeenCalledTimes(2);
|
|
160
|
-
expect(onClientDisconnect).toHaveBeenCalledTimes(1);
|
|
161
|
-
expect(onServerConnect).toHaveBeenCalledTimes(2);
|
|
162
|
-
expect(onServerDisconnect).toHaveBeenCalledTimes(1);
|
|
163
|
-
// teardown
|
|
164
|
-
clientTransport.removeEventListener('connectionStatus', clientHandler);
|
|
165
|
-
serverTransport.removeEventListener('connectionStatus', serverHandler);
|
|
166
|
-
await testFinishesCleanly({
|
|
167
|
-
clientTransports: [clientTransport],
|
|
168
|
-
serverTransport,
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
test('ws connection is not recreated after destroy', async () => {
|
|
172
|
-
const [clientTransport, serverTransport] = createWsTransports(port, wss);
|
|
173
|
-
const msg1 = createDummyTransportMessage();
|
|
174
|
-
const msg2 = createDummyTransportMessage();
|
|
175
|
-
const promise1 = waitForMessage(serverTransport, (recv) => recv.id === msg1.id);
|
|
176
|
-
clientTransport.send(msg1);
|
|
177
|
-
await expect(promise1).resolves.toStrictEqual(msg1.payload);
|
|
178
|
-
clientTransport.destroy();
|
|
179
|
-
expect(() => clientTransport.send(msg2)).toThrow(new Error('transport is destroyed, cant send'));
|
|
180
|
-
// this is not expected to be clean because we destroyed the transport
|
|
181
|
-
expect(clientTransport.state).toEqual('destroyed');
|
|
182
|
-
await clientTransport.close();
|
|
183
|
-
await serverTransport.close();
|
|
184
|
-
});
|
|
185
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../transport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,GAAG,EACH,KAAK,GACN,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACZ,aAAa,GACd,MAAM,WAAW,CAAC"}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { TSchema } from '@sinclair/typebox';
|
|
2
|
-
/**
|
|
3
|
-
* Control flags for transport messages.
|
|
4
|
-
* An RPC message is coded with StreamOpenBit | StreamClosedBit.
|
|
5
|
-
* Streams are expected to start with StreamOpenBit sent and the client SHOULD send an empty
|
|
6
|
-
* message with StreamClosedBit to close the stream handler on the server, indicating that
|
|
7
|
-
* it will not be using the stream anymore.
|
|
8
|
-
*/
|
|
9
|
-
export declare const enum ControlFlags {
|
|
10
|
-
AckBit = 1,
|
|
11
|
-
StreamOpenBit = 2,
|
|
12
|
-
StreamClosedBit = 4
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Generic Typebox schema for a transport message.
|
|
16
|
-
* @template T The type of the payload.
|
|
17
|
-
* @param {T} t The payload schema.
|
|
18
|
-
* @returns The transport message schema.
|
|
19
|
-
*/
|
|
20
|
-
export declare const TransportMessageSchema: <T extends TSchema>(t: T) => import("@sinclair/typebox").TObject<{
|
|
21
|
-
id: import("@sinclair/typebox").TString;
|
|
22
|
-
from: import("@sinclair/typebox").TString;
|
|
23
|
-
to: import("@sinclair/typebox").TString;
|
|
24
|
-
serviceName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
25
|
-
procedureName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
26
|
-
streamId: import("@sinclair/typebox").TString;
|
|
27
|
-
controlFlags: import("@sinclair/typebox").TInteger;
|
|
28
|
-
payload: T;
|
|
29
|
-
}>;
|
|
30
|
-
/**
|
|
31
|
-
* Defines the schema for a transport acknowledgement message. This is never constructed manually
|
|
32
|
-
* and is only used internally by the library for tracking inflight messages.
|
|
33
|
-
* @returns The transport message schema.
|
|
34
|
-
*/
|
|
35
|
-
export declare const TransportAckSchema: import("@sinclair/typebox").TObject<{
|
|
36
|
-
id: import("@sinclair/typebox").TString;
|
|
37
|
-
from: import("@sinclair/typebox").TString;
|
|
38
|
-
to: import("@sinclair/typebox").TString;
|
|
39
|
-
serviceName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
40
|
-
procedureName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
41
|
-
streamId: import("@sinclair/typebox").TString;
|
|
42
|
-
controlFlags: import("@sinclair/typebox").TInteger;
|
|
43
|
-
payload: import("@sinclair/typebox").TObject<{
|
|
44
|
-
ack: import("@sinclair/typebox").TString;
|
|
45
|
-
}>;
|
|
46
|
-
}>;
|
|
47
|
-
export declare const ControlMessagePayloadSchema: import("@sinclair/typebox").TObject<{
|
|
48
|
-
type: import("@sinclair/typebox").TLiteral<"CLOSE">;
|
|
49
|
-
}>;
|
|
50
|
-
/**
|
|
51
|
-
* Defines the schema for an opaque transport message that is agnostic to any
|
|
52
|
-
* procedure/service.
|
|
53
|
-
* @returns The transport message schema.
|
|
54
|
-
*/
|
|
55
|
-
export declare const OpaqueTransportMessageSchema: import("@sinclair/typebox").TObject<{
|
|
56
|
-
id: import("@sinclair/typebox").TString;
|
|
57
|
-
from: import("@sinclair/typebox").TString;
|
|
58
|
-
to: import("@sinclair/typebox").TString;
|
|
59
|
-
serviceName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
60
|
-
procedureName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
61
|
-
streamId: import("@sinclair/typebox").TString;
|
|
62
|
-
controlFlags: import("@sinclair/typebox").TInteger;
|
|
63
|
-
payload: import("@sinclair/typebox").TUnknown;
|
|
64
|
-
}>;
|
|
65
|
-
/**
|
|
66
|
-
* Represents a transport message. This is the same type as {@link TransportMessageSchema} but
|
|
67
|
-
* we can't statically infer generics from generic Typebox schemas so we have to define it again here.
|
|
68
|
-
*
|
|
69
|
-
* TypeScript can't enforce types when a bitmask is involved, so these are the semantics of
|
|
70
|
-
* `controlFlags`:
|
|
71
|
-
* * If `controlFlags & StreamOpenBit == StreamOpenBit`, `streamId` must be set to a unique value
|
|
72
|
-
* (suggestion: use `nanoid`).
|
|
73
|
-
* * If `controlFlags & StreamOpenBit == StreamOpenBit`, `serviceName` and `procedureName` must be set.
|
|
74
|
-
* * If `controlFlags & StreamClosedBit == StreamClosedBit` and the kind is `stream` or `subscription`,
|
|
75
|
-
* `payload` should be discarded (usually contains a control message).
|
|
76
|
-
* @template Payload The type of the payload.
|
|
77
|
-
*/
|
|
78
|
-
export type TransportMessage<Payload extends Record<string, unknown> | unknown = Record<string, unknown>> = {
|
|
79
|
-
id: string;
|
|
80
|
-
from: string;
|
|
81
|
-
to: string;
|
|
82
|
-
serviceName?: string;
|
|
83
|
-
procedureName?: string;
|
|
84
|
-
streamId: string;
|
|
85
|
-
controlFlags: number;
|
|
86
|
-
payload: Payload;
|
|
87
|
-
};
|
|
88
|
-
export type MessageId = string;
|
|
89
|
-
/**
|
|
90
|
-
* A type alias for a transport message with an opaque payload.
|
|
91
|
-
* @template T - The type of the opaque payload.
|
|
92
|
-
*/
|
|
93
|
-
export type OpaqueTransportMessage = TransportMessage<unknown>;
|
|
94
|
-
export type TransportClientId = string;
|
|
95
|
-
/**
|
|
96
|
-
* Creates a transport message with the given parameters. You shouldn't need to call this manually unless
|
|
97
|
-
* you're writing a test.
|
|
98
|
-
* @param from The sender of the message.
|
|
99
|
-
* @param to The intended recipient of the message.
|
|
100
|
-
* @param service The name of the service the message is intended for.
|
|
101
|
-
* @param proc The name of the procedure the message is intended for.
|
|
102
|
-
* @param stream The ID of the stream the message is intended for.
|
|
103
|
-
* @param payload The payload of the message.
|
|
104
|
-
* @returns A TransportMessage object with the given parameters.
|
|
105
|
-
*/
|
|
106
|
-
export declare function msg<Payload extends object>(from: string, to: string, streamId: string, payload: Payload, serviceName?: string, procedureName?: string): TransportMessage<Payload>;
|
|
107
|
-
/**
|
|
108
|
-
* Creates a new transport message as a response to the given message.
|
|
109
|
-
* @param msg The original message to respond to.
|
|
110
|
-
* @param response The payload of the response message.
|
|
111
|
-
* @returns A new transport message with appropriate to, from, and payload fields
|
|
112
|
-
*/
|
|
113
|
-
export declare function reply<Payload extends object>(msg: OpaqueTransportMessage, response: Payload): TransportMessage<Payload>;
|
|
114
|
-
/**
|
|
115
|
-
* Create a request to close a stream
|
|
116
|
-
* @param from The ID of the client initiating the close.
|
|
117
|
-
* @param to The ID of the client being closed.
|
|
118
|
-
* @param respondTo The transport message to respond to.
|
|
119
|
-
* @returns The close message
|
|
120
|
-
*/
|
|
121
|
-
export declare function closeStream(from: TransportClientId, to: TransportClientId, stream: string): TransportMessage<{
|
|
122
|
-
type: "CLOSE";
|
|
123
|
-
}>;
|
|
124
|
-
/**
|
|
125
|
-
* Checks if the given control flag (usually found in msg.controlFlag) is an ack message.
|
|
126
|
-
* @param controlFlag - The control flag to check.
|
|
127
|
-
* @returns True if the control flag contains the AckBit, false otherwise.
|
|
128
|
-
*/
|
|
129
|
-
export declare function isAck(controlFlag: number): boolean;
|
|
130
|
-
/**
|
|
131
|
-
* Checks if the given control flag (usually found in msg.controlFlag) is a stream open message.
|
|
132
|
-
* @param controlFlag - The control flag to check.
|
|
133
|
-
* @returns True if the control flag contains the StreamOpenBit, false otherwise.
|
|
134
|
-
*/
|
|
135
|
-
export declare function isStreamOpen(controlFlag: number): boolean;
|
|
136
|
-
/**
|
|
137
|
-
* Checks if the given control flag (usually found in msg.controlFlag) is a stream close message.
|
|
138
|
-
* @param controlFlag - The control flag to check.
|
|
139
|
-
* @returns True if the control flag contains the StreamCloseBit, false otherwise.
|
|
140
|
-
*/
|
|
141
|
-
export declare function isStreamClose(controlFlag: number): boolean;
|
|
142
|
-
//# sourceMappingURL=message.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../transport/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,OAAO,EAAU,MAAM,mBAAmB,CAAC;AAG1D;;;;;;GAMG;AACH,0BAAkB,YAAY;IAC5B,MAAM,IAAS;IACf,aAAa,IAAS;IACtB,eAAe,IAAS;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;EAU/B,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;EAI9B,CAAC;AAEF,eAAO,MAAM,2BAA2B;;EAEtC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;EAExC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,CAC1B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IACzE;IACF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,OAAO,SAAS,MAAM,EACxC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,WAAW,CAAC,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,MAAM,GACrB,gBAAgB,CAAC,OAAO,CAAC,CAW3B;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,OAAO,SAAS,MAAM,EAC1C,GAAG,EAAE,sBAAsB,EAC3B,QAAQ,EAAE,OAAO,GAChB,gBAAgB,CAAC,OAAO,CAAC,CAS3B;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,iBAAiB,EACrB,MAAM,EAAE,MAAM;;GAOf;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAK1D"}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { Type } from '@sinclair/typebox';
|
|
2
|
-
import { nanoid } from 'nanoid';
|
|
3
|
-
/**
|
|
4
|
-
* Generic Typebox schema for a transport message.
|
|
5
|
-
* @template T The type of the payload.
|
|
6
|
-
* @param {T} t The payload schema.
|
|
7
|
-
* @returns The transport message schema.
|
|
8
|
-
*/
|
|
9
|
-
export const TransportMessageSchema = (t) => Type.Object({
|
|
10
|
-
id: Type.String(),
|
|
11
|
-
from: Type.String(),
|
|
12
|
-
to: Type.String(),
|
|
13
|
-
serviceName: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
14
|
-
procedureName: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
15
|
-
streamId: Type.String(),
|
|
16
|
-
controlFlags: Type.Integer(),
|
|
17
|
-
payload: t,
|
|
18
|
-
});
|
|
19
|
-
/**
|
|
20
|
-
* Defines the schema for a transport acknowledgement message. This is never constructed manually
|
|
21
|
-
* and is only used internally by the library for tracking inflight messages.
|
|
22
|
-
* @returns The transport message schema.
|
|
23
|
-
*/
|
|
24
|
-
export const TransportAckSchema = TransportMessageSchema(Type.Object({
|
|
25
|
-
ack: Type.String(),
|
|
26
|
-
}));
|
|
27
|
-
export const ControlMessagePayloadSchema = Type.Object({
|
|
28
|
-
type: Type.Literal('CLOSE'),
|
|
29
|
-
});
|
|
30
|
-
/**
|
|
31
|
-
* Defines the schema for an opaque transport message that is agnostic to any
|
|
32
|
-
* procedure/service.
|
|
33
|
-
* @returns The transport message schema.
|
|
34
|
-
*/
|
|
35
|
-
export const OpaqueTransportMessageSchema = TransportMessageSchema(Type.Unknown());
|
|
36
|
-
/**
|
|
37
|
-
* Creates a transport message with the given parameters. You shouldn't need to call this manually unless
|
|
38
|
-
* you're writing a test.
|
|
39
|
-
* @param from The sender of the message.
|
|
40
|
-
* @param to The intended recipient of the message.
|
|
41
|
-
* @param service The name of the service the message is intended for.
|
|
42
|
-
* @param proc The name of the procedure the message is intended for.
|
|
43
|
-
* @param stream The ID of the stream the message is intended for.
|
|
44
|
-
* @param payload The payload of the message.
|
|
45
|
-
* @returns A TransportMessage object with the given parameters.
|
|
46
|
-
*/
|
|
47
|
-
export function msg(from, to, streamId, payload, serviceName, procedureName) {
|
|
48
|
-
return {
|
|
49
|
-
id: nanoid(),
|
|
50
|
-
to,
|
|
51
|
-
from,
|
|
52
|
-
serviceName,
|
|
53
|
-
procedureName,
|
|
54
|
-
streamId,
|
|
55
|
-
controlFlags: 0,
|
|
56
|
-
payload,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Creates a new transport message as a response to the given message.
|
|
61
|
-
* @param msg The original message to respond to.
|
|
62
|
-
* @param response The payload of the response message.
|
|
63
|
-
* @returns A new transport message with appropriate to, from, and payload fields
|
|
64
|
-
*/
|
|
65
|
-
export function reply(msg, response) {
|
|
66
|
-
return {
|
|
67
|
-
id: nanoid(),
|
|
68
|
-
streamId: msg.streamId,
|
|
69
|
-
controlFlags: 0,
|
|
70
|
-
to: msg.from,
|
|
71
|
-
from: msg.to,
|
|
72
|
-
payload: response,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Create a request to close a stream
|
|
77
|
-
* @param from The ID of the client initiating the close.
|
|
78
|
-
* @param to The ID of the client being closed.
|
|
79
|
-
* @param respondTo The transport message to respond to.
|
|
80
|
-
* @returns The close message
|
|
81
|
-
*/
|
|
82
|
-
export function closeStream(from, to, stream) {
|
|
83
|
-
const closeMessage = msg(from, to, stream, {
|
|
84
|
-
type: 'CLOSE',
|
|
85
|
-
});
|
|
86
|
-
closeMessage.controlFlags |= 4 /* ControlFlags.StreamClosedBit */;
|
|
87
|
-
return closeMessage;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Checks if the given control flag (usually found in msg.controlFlag) is an ack message.
|
|
91
|
-
* @param controlFlag - The control flag to check.
|
|
92
|
-
* @returns True if the control flag contains the AckBit, false otherwise.
|
|
93
|
-
*/
|
|
94
|
-
export function isAck(controlFlag) {
|
|
95
|
-
return (controlFlag & 1 /* ControlFlags.AckBit */) === 1 /* ControlFlags.AckBit */;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Checks if the given control flag (usually found in msg.controlFlag) is a stream open message.
|
|
99
|
-
* @param controlFlag - The control flag to check.
|
|
100
|
-
* @returns True if the control flag contains the StreamOpenBit, false otherwise.
|
|
101
|
-
*/
|
|
102
|
-
export function isStreamOpen(controlFlag) {
|
|
103
|
-
return ((controlFlag & 2 /* ControlFlags.StreamOpenBit */) === 2 /* ControlFlags.StreamOpenBit */);
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Checks if the given control flag (usually found in msg.controlFlag) is a stream close message.
|
|
107
|
-
* @param controlFlag - The control flag to check.
|
|
108
|
-
* @returns True if the control flag contains the StreamCloseBit, false otherwise.
|
|
109
|
-
*/
|
|
110
|
-
export function isStreamClose(controlFlag) {
|
|
111
|
-
return ((controlFlag & 4 /* ControlFlags.StreamClosedBit */) ===
|
|
112
|
-
4 /* ControlFlags.StreamClosedBit */);
|
|
113
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message.test.d.ts","sourceRoot":"","sources":["../../transport/message.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { isAck, isStreamClose, isStreamOpen, msg, reply, } from './message';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
describe('message helpers', () => {
|
|
4
|
-
test('ack', () => {
|
|
5
|
-
const m = msg('a', 'b', 'stream', { test: 1 }, 'svc', 'proc');
|
|
6
|
-
m.controlFlags |= 1 /* ControlFlags.AckBit */;
|
|
7
|
-
expect(m).toHaveProperty('controlFlags');
|
|
8
|
-
expect(isAck(m.controlFlags)).toBe(true);
|
|
9
|
-
expect(isStreamOpen(m.controlFlags)).toBe(false);
|
|
10
|
-
expect(isStreamClose(m.controlFlags)).toBe(false);
|
|
11
|
-
});
|
|
12
|
-
test('streamOpen', () => {
|
|
13
|
-
const m = msg('a', 'b', 'stream', { test: 1 }, 'svc', 'proc');
|
|
14
|
-
m.controlFlags |= 2 /* ControlFlags.StreamOpenBit */;
|
|
15
|
-
expect(m).toHaveProperty('controlFlags');
|
|
16
|
-
expect(isAck(m.controlFlags)).toBe(false);
|
|
17
|
-
expect(isStreamOpen(m.controlFlags)).toBe(true);
|
|
18
|
-
expect(isStreamClose(m.controlFlags)).toBe(false);
|
|
19
|
-
});
|
|
20
|
-
test('streamClose', () => {
|
|
21
|
-
const m = msg('a', 'b', 'stream', { test: 1 }, 'svc', 'proc');
|
|
22
|
-
m.controlFlags |= 4 /* ControlFlags.StreamClosedBit */;
|
|
23
|
-
expect(m).toHaveProperty('controlFlags');
|
|
24
|
-
expect(isAck(m.controlFlags)).toBe(false);
|
|
25
|
-
expect(isStreamOpen(m.controlFlags)).toBe(false);
|
|
26
|
-
expect(isStreamClose(m.controlFlags)).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
test('reply', () => {
|
|
29
|
-
const m = msg('a', 'b', 'stream', { test: 1 }, 'svc', 'proc');
|
|
30
|
-
const payload = { cool: 2 };
|
|
31
|
-
const resp = reply(m, payload);
|
|
32
|
-
expect(resp.id).not.toBe(m.id);
|
|
33
|
-
expect(resp.payload).toEqual(payload);
|
|
34
|
-
expect(resp.from).toBe('b');
|
|
35
|
-
expect(resp.to).toBe('a');
|
|
36
|
-
});
|
|
37
|
-
test('default message has no control flags set', () => {
|
|
38
|
-
const m = msg('a', 'b', 'stream', { test: 1 }, 'svc', 'proc');
|
|
39
|
-
expect(isAck(m.controlFlags)).toBe(false);
|
|
40
|
-
expect(isStreamOpen(m.controlFlags)).toBe(false);
|
|
41
|
-
expect(isStreamClose(m.controlFlags)).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
test('combining control flags works', () => {
|
|
44
|
-
const m = msg('a', 'b', 'stream', { test: 1 }, 'svc', 'proc');
|
|
45
|
-
m.controlFlags |= 2 /* ControlFlags.StreamOpenBit */;
|
|
46
|
-
expect(isStreamOpen(m.controlFlags)).toBe(true);
|
|
47
|
-
expect(isStreamClose(m.controlFlags)).toBe(false);
|
|
48
|
-
m.controlFlags |= 4 /* ControlFlags.StreamClosedBit */;
|
|
49
|
-
expect(isStreamOpen(m.controlFlags)).toBe(true);
|
|
50
|
-
expect(isStreamClose(m.controlFlags)).toBe(true);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
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;IA8BlE;;;;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"}
|