@replit/river 0.5.2 → 0.6.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 CHANGED
@@ -5,4 +5,13 @@ It's like tRPC but...
5
5
  - with JSON Schema Support
6
6
  - with full-duplex streaming
7
7
  - with support for service multiplexing
8
+ - with Result types and error handling
8
9
  - over WebSockets
10
+
11
+ ## Developing
12
+
13
+ - `npm i` -- install dependencies
14
+ - `npm check` -- lint
15
+ - `npm format` -- format
16
+ - `npm test` -- run tests
17
+ - `npm publish` -- cut a new release (should bump version in package.json first)
@@ -3,12 +3,14 @@ import { createWebSocketServer, createWsTransports, onServerReady, } from '../te
3
3
  import { createServer } from '../router/server';
4
4
  import { createClient } from '../router/client';
5
5
  import http from 'http';
6
- import { DIV_BY_ZERO, FallibleServiceConstructor, OrderingServiceConstructor, STREAM_ERROR, TestServiceConstructor, } from './fixtures';
6
+ import { BinaryFileServiceConstructor, DIV_BY_ZERO, FallibleServiceConstructor, OrderingServiceConstructor, STREAM_ERROR, TestServiceConstructor, } from './fixtures';
7
7
  import { UNCAUGHT_ERROR } from '../router/result';
8
- describe('client <-> server integration test', async () => {
8
+ import { codecs } from '../codec/codec.test';
9
+ describe.each(codecs)('client <-> server integration test ($name codec)', async ({ codec }) => {
9
10
  const server = http.createServer();
10
11
  const port = await onServerReady(server);
11
12
  const webSocketServer = await createWebSocketServer(server);
13
+ const getTransports = () => createWsTransports(port, webSocketServer, codec);
12
14
  afterAll(() => {
13
15
  webSocketServer.clients.forEach((socket) => {
14
16
  socket.close();
@@ -16,7 +18,7 @@ describe('client <-> server integration test', async () => {
16
18
  server.close();
17
19
  });
18
20
  test('rpc', async () => {
19
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
21
+ const [clientTransport, serverTransport] = getTransports();
20
22
  const serviceDefs = { test: TestServiceConstructor() };
21
23
  const server = await createServer(serverTransport, serviceDefs);
22
24
  const client = createClient(clientTransport);
@@ -25,7 +27,7 @@ describe('client <-> server integration test', async () => {
25
27
  expect(result.payload).toStrictEqual({ result: 3 });
26
28
  });
27
29
  test('fallible rpc', async () => {
28
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
30
+ const [clientTransport, serverTransport] = getTransports();
29
31
  const serviceDefs = { test: FallibleServiceConstructor() };
30
32
  const server = await createServer(serverTransport, serviceDefs);
31
33
  const client = createClient(clientTransport);
@@ -42,8 +44,18 @@ describe('client <-> server integration test', async () => {
42
44
  },
43
45
  });
44
46
  });
47
+ test('rpc with binary (uint8array)', async () => {
48
+ const [clientTransport, serverTransport] = getTransports();
49
+ const serviceDefs = { test: BinaryFileServiceConstructor() };
50
+ const server = await createServer(serverTransport, serviceDefs);
51
+ const client = createClient(clientTransport);
52
+ const result = await client.test.getFile({ file: 'test.py' });
53
+ assert(result.ok);
54
+ assert(result.payload.contents instanceof Uint8Array);
55
+ expect(new TextDecoder().decode(result.payload.contents)).toStrictEqual('contents for file test.py');
56
+ });
45
57
  test('stream', async () => {
46
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
58
+ const [clientTransport, serverTransport] = getTransports();
47
59
  const serviceDefs = { test: TestServiceConstructor() };
48
60
  const server = await createServer(serverTransport, serviceDefs);
49
61
  const client = createClient(clientTransport);
@@ -61,7 +73,7 @@ describe('client <-> server integration test', async () => {
61
73
  close();
62
74
  });
63
75
  test('fallible stream', async () => {
64
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
76
+ const [clientTransport, serverTransport] = getTransports();
65
77
  const serviceDefs = { test: FallibleServiceConstructor() };
66
78
  const server = await createServer(serverTransport, serviceDefs);
67
79
  const client = createClient(clientTransport);
@@ -84,7 +96,7 @@ describe('client <-> server integration test', async () => {
84
96
  close();
85
97
  });
86
98
  test('message order is preserved in the face of disconnects', async () => {
87
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
99
+ const [clientTransport, serverTransport] = getTransports();
88
100
  const serviceDefs = { test: OrderingServiceConstructor() };
89
101
  const server = await createServer(serverTransport, serviceDefs);
90
102
  const client = createClient(clientTransport);
@@ -107,7 +119,7 @@ describe('client <-> server integration test', async () => {
107
119
  });
108
120
  const CONCURRENCY = 10;
109
121
  test('concurrent rpcs', async () => {
110
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
122
+ const [clientTransport, serverTransport] = getTransports();
111
123
  const serviceDefs = { test: OrderingServiceConstructor() };
112
124
  const server = await createServer(serverTransport, serviceDefs);
113
125
  const client = createClient(clientTransport);
@@ -122,7 +134,7 @@ describe('client <-> server integration test', async () => {
122
134
  }
123
135
  });
124
136
  test('concurrent streams', async () => {
125
- const [clientTransport, serverTransport] = createWsTransports(port, webSocketServer);
137
+ const [clientTransport, serverTransport] = getTransports();
126
138
  const serviceDefs = { test: TestServiceConstructor() };
127
139
  const server = await createServer(serverTransport, serviceDefs);
128
140
  const client = createClient(clientTransport);
@@ -89,6 +89,27 @@ export declare const OrderingServiceConstructor: () => {
89
89
  };
90
90
  };
91
91
  };
92
+ export declare const BinaryFileServiceConstructor: () => {
93
+ name: "bin";
94
+ state: {};
95
+ procedures: {
96
+ getFile: {
97
+ input: import("@sinclair/typebox").TObject<{
98
+ file: import("@sinclair/typebox").TString;
99
+ }>;
100
+ output: import("@sinclair/typebox").TObject<{
101
+ contents: import("@sinclair/typebox").TUint8Array;
102
+ }>;
103
+ errors: import("@sinclair/typebox").TNever;
104
+ handler: (context: import("../router").ServiceContextWithState<{}>, input: import("../transport/message").TransportMessage<{
105
+ file: string;
106
+ }>) => Promise<import("../transport/message").TransportMessage<import("../router/result").Result<{
107
+ contents: Uint8Array;
108
+ }, never>>>;
109
+ type: "rpc";
110
+ };
111
+ };
112
+ };
92
113
  export declare const DIV_BY_ZERO = "DIV_BY_ZERO";
93
114
  export declare const STREAM_ERROR = "STREAM_ERROR";
94
115
  export declare const FallibleServiceConstructor: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../__tests__/fixtures.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW;;;EAGtB,CAAC;AACH,eAAO,MAAM,YAAY;;EAA2C,CAAC;AAErE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BpB,CAAC;AAEhB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBxB,CAAC;AAEhB,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiExB,CAAC"}
1
+ {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../__tests__/fixtures.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW;;;EAGtB,CAAC;AACH,eAAO,MAAM,YAAY;;EAA2C,CAAC;AAErE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BpB,CAAC;AAEhB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBxB,CAAC;AAEhB,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;CAc1B,CAAC;AAEhB,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiExB,CAAC"}
@@ -62,6 +62,18 @@ export const OrderingServiceConstructor = () => ServiceBuilder.create('test')
62
62
  },
63
63
  })
64
64
  .finalize();
65
+ export const BinaryFileServiceConstructor = () => ServiceBuilder.create('bin')
66
+ .defineProcedure('getFile', {
67
+ type: 'rpc',
68
+ input: Type.Object({ file: Type.String() }),
69
+ output: Type.Object({ contents: Type.Uint8Array() }),
70
+ errors: Type.Never(),
71
+ async handler(_ctx, msg) {
72
+ const bytes = new TextEncoder().encode(`contents for file ${msg.payload.file}`);
73
+ return reply(msg, Ok({ contents: bytes }));
74
+ },
75
+ })
76
+ .finalize();
65
77
  export const DIV_BY_ZERO = 'DIV_BY_ZERO';
66
78
  export const STREAM_ERROR = 'STREAM_ERROR';
67
79
  export const FallibleServiceConstructor = () => ServiceBuilder.create('fallible')
@@ -1,6 +1,6 @@
1
1
  import { expect, describe, test } from 'vitest';
2
2
  import { serializeService } from '../router/builder';
3
- import { FallibleServiceConstructor, TestServiceConstructor } from './fixtures';
3
+ import { BinaryFileServiceConstructor, FallibleServiceConstructor, TestServiceConstructor, } from './fixtures';
4
4
  describe('serialize service to jsonschema', () => {
5
5
  test('serialize basic service', () => {
6
6
  const service = TestServiceConstructor();
@@ -48,6 +48,39 @@ describe('serialize service to jsonschema', () => {
48
48
  },
49
49
  });
50
50
  });
51
+ test('serialize service with binary', () => {
52
+ const service = BinaryFileServiceConstructor();
53
+ expect(serializeService(service)).toStrictEqual({
54
+ name: 'bin',
55
+ procedures: {
56
+ getFile: {
57
+ errors: {
58
+ not: {},
59
+ },
60
+ input: {
61
+ properties: {
62
+ file: {
63
+ type: 'string',
64
+ },
65
+ },
66
+ required: ['file'],
67
+ type: 'object',
68
+ },
69
+ output: {
70
+ properties: {
71
+ contents: {
72
+ type: 'Uint8Array',
73
+ },
74
+ },
75
+ required: ['contents'],
76
+ type: 'object',
77
+ },
78
+ type: 'rpc',
79
+ },
80
+ },
81
+ state: {},
82
+ });
83
+ });
51
84
  test('serialize service with errors', () => {
52
85
  const service = FallibleServiceConstructor();
53
86
  expect(serializeService(service)).toStrictEqual({
@@ -0,0 +1,7 @@
1
+ import { Codec } from './types';
2
+ /**
3
+ * Binary codec, uses [msgpack](https://www.npmjs.com/package/@msgpack/msgpack) under the hood
4
+ * @type {Codec}
5
+ */
6
+ export declare const BinaryCodec: Codec;
7
+ //# sourceMappingURL=binary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../../codec/binary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { decode, encode } from '@msgpack/msgpack';
2
+ /**
3
+ * Binary codec, uses [msgpack](https://www.npmjs.com/package/@msgpack/msgpack) under the hood
4
+ * @type {Codec}
5
+ */
6
+ export const BinaryCodec = {
7
+ toBuffer: encode,
8
+ fromBuffer: (buff) => {
9
+ try {
10
+ const res = decode(buff);
11
+ if (typeof res !== 'object') {
12
+ return null;
13
+ }
14
+ return res;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ },
20
+ };
@@ -1,2 +1,5 @@
1
- export {};
1
+ export declare const codecs: {
2
+ name: string;
3
+ codec: import("./types").Codec;
4
+ }[];
2
5
  //# sourceMappingURL=codec.test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codec.test.d.ts","sourceRoot":"","sources":["../../codec/codec.test.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"codec.test.d.ts","sourceRoot":"","sources":["../../codec/codec.test.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM;;;GAGlB,CAAC"}
@@ -1,13 +1,18 @@
1
+ import { BinaryCodec } from './binary';
1
2
  import { NaiveJsonCodec } from './json';
2
3
  import { describe, test, expect } from 'vitest';
3
- describe('naive json codec', () => {
4
+ export const codecs = [
5
+ { name: 'naive', codec: NaiveJsonCodec },
6
+ { name: 'binary', codec: BinaryCodec },
7
+ ];
8
+ describe.each(codecs)('codec -- $name', ({ codec }) => {
4
9
  test('empty object', () => {
5
10
  const msg = {};
6
- expect(NaiveJsonCodec.fromStringBuf(NaiveJsonCodec.toStringBuf(msg))).toStrictEqual(msg);
11
+ expect(codec.fromBuffer(codec.toBuffer(msg))).toStrictEqual(msg);
7
12
  });
8
13
  test('simple test', () => {
9
14
  const msg = { abc: 123, def: 'cool' };
10
- expect(NaiveJsonCodec.fromStringBuf(NaiveJsonCodec.toStringBuf(msg))).toStrictEqual(msg);
15
+ expect(codec.fromBuffer(codec.toBuffer(msg))).toStrictEqual(msg);
11
16
  });
12
17
  test('deeply nested test', () => {
13
18
  const msg = {
@@ -18,12 +23,19 @@ describe('naive json codec', () => {
18
23
  },
19
24
  },
20
25
  };
21
- expect(NaiveJsonCodec.fromStringBuf(NaiveJsonCodec.toStringBuf(msg))).toStrictEqual(msg);
26
+ expect(codec.fromBuffer(codec.toBuffer(msg))).toStrictEqual(msg);
27
+ });
28
+ test('buffer test', () => {
29
+ const msg = {
30
+ buff: Uint8Array.from([0, 42, 100, 255]),
31
+ };
32
+ expect(codec.fromBuffer(codec.toBuffer(msg))).toStrictEqual(msg);
22
33
  });
23
34
  test('invalid json returns null', () => {
24
- expect(NaiveJsonCodec.fromStringBuf('')).toBeNull();
25
- expect(NaiveJsonCodec.fromStringBuf('[')).toBeNull();
26
- expect(NaiveJsonCodec.fromStringBuf('[{}')).toBeNull();
27
- expect(NaiveJsonCodec.fromStringBuf('{"a":1}[]')).toBeNull();
35
+ const encoder = new TextEncoder();
36
+ expect(codec.fromBuffer(encoder.encode(''))).toBeNull();
37
+ expect(codec.fromBuffer(encoder.encode('['))).toBeNull();
38
+ expect(codec.fromBuffer(encoder.encode('[{}'))).toBeNull();
39
+ expect(codec.fromBuffer(encoder.encode('{"a":1}[]'))).toBeNull();
28
40
  });
29
41
  });
@@ -1 +1 @@
1
- {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../codec/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,KAS5B,CAAC"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../codec/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAwBhC;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,KA0B5B,CAAC"}
@@ -1,12 +1,48 @@
1
+ const encoder = new TextEncoder();
2
+ const decoder = new TextDecoder();
3
+ // Convert Uint8Array to base64
4
+ function uint8ArrayToBase64(uint8Array) {
5
+ let binary = '';
6
+ uint8Array.forEach((byte) => {
7
+ binary += String.fromCharCode(byte);
8
+ });
9
+ return btoa(binary);
10
+ }
11
+ // Convert base64 to Uint8Array
12
+ function base64ToUint8Array(base64) {
13
+ const binaryString = atob(base64);
14
+ const uint8Array = new Uint8Array(binaryString.length);
15
+ for (let i = 0; i < binaryString.length; i++) {
16
+ uint8Array[i] = binaryString.charCodeAt(i);
17
+ }
18
+ return uint8Array;
19
+ }
1
20
  /**
2
21
  * Naive JSON codec implementation using JSON.stringify and JSON.parse.
3
22
  * @type {Codec}
4
23
  */
5
24
  export const NaiveJsonCodec = {
6
- toStringBuf: JSON.stringify,
7
- fromStringBuf: (s) => {
25
+ toBuffer: (obj) => {
26
+ return encoder.encode(JSON.stringify(obj, function replacer(key) {
27
+ let val = this[key];
28
+ if (val instanceof Uint8Array) {
29
+ return { $t: uint8ArrayToBase64(val) };
30
+ }
31
+ else {
32
+ return val;
33
+ }
34
+ }));
35
+ },
36
+ fromBuffer: (buff) => {
8
37
  try {
9
- return JSON.parse(s);
38
+ return JSON.parse(decoder.decode(buff), function reviver(_key, val) {
39
+ if (val?.$t) {
40
+ return base64ToUint8Array(val.$t);
41
+ }
42
+ else {
43
+ return val;
44
+ }
45
+ });
10
46
  }
11
47
  catch {
12
48
  return null;
@@ -1,19 +1,19 @@
1
1
  /**
2
- * Codec interface for encoding and decoding objects to and from string buffers.
2
+ * Codec interface for encoding and decoding objects to and from Uint8 buffers.
3
3
  * Used to prepare messages for use by the transport layer.
4
4
  */
5
5
  export interface Codec {
6
6
  /**
7
- * Encodes an object to a string buffer.
7
+ * Encodes an object to a Uint8 buffer.
8
8
  * @param obj - The object to encode.
9
- * @returns The encoded string buffer.
9
+ * @returns The encoded Uint8 buffer.
10
10
  */
11
- toStringBuf(obj: object): string;
11
+ toBuffer(obj: object): Uint8Array;
12
12
  /**
13
- * Decodes an object from a string buffer.
14
- * @param buf - The string buffer to decode.
13
+ * Decodes an object from a Uint8 buffer.
14
+ * @param buf - The Uint8 buffer to decode.
15
15
  * @returns The decoded object, or null if decoding failed.
16
16
  */
17
- fromStringBuf(buf: string): object | null;
17
+ fromBuffer(buf: Uint8Array): object | null;
18
18
  }
19
19
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../codec/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB;;;;OAIG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC3C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../codec/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;CAC5C"}
@@ -39,9 +39,9 @@ export const createClient = (transport) => _createRecursiveProxy(async (opts) =>
39
39
  const [input] = opts.args;
40
40
  const streamId = nanoid();
41
41
  function belongsToSameStream(msg) {
42
- return (msg.streamId === streamId &&
43
- msg.serviceName === serviceName &&
44
- msg.procedureName === procName);
42
+ return (msg.serviceName === serviceName &&
43
+ msg.procedureName === procName &&
44
+ (msg.streamId === streamId || msg.streamId === 'global'));
45
45
  }
46
46
  if (input === undefined) {
47
47
  // stream case (stream methods are called with zero arguments)
@@ -8,6 +8,7 @@ import { Procedure, ServiceContext } from './router';
8
8
  import { OpaqueTransportMessage, TransportMessage } from './transport';
9
9
  import { Pushable } from 'it-pushable';
10
10
  import { Result, RiverError, RiverUncaughtSchema } from './router/result';
11
+ import { Codec } from './codec';
11
12
  /**
12
13
  * Creates a WebSocket server instance using the provided HTTP server.
13
14
  * Only used as helper for testing.
@@ -36,7 +37,7 @@ export declare function createLocalWebSocketClient(port: number): Promise<WebSoc
36
37
  * @param wss - The WebSocketServer instance to use for the server transport.
37
38
  * @returns An array containing the client and server {@link WebSocketTransport} instances.
38
39
  */
39
- export declare function createWsTransports(port: number, wss: WebSocketServer): [WebSocketTransport, WebSocketTransport];
40
+ export declare function createWsTransports(port: number, wss: WebSocketServer, codec?: Codec): [WebSocketTransport, WebSocketTransport];
40
41
  /**
41
42
  * Transforms an RPC procedure definition into a normal function call.
42
43
  * This should only be used for testing.
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../testUtils.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAY,MAAM,aAAa,CAAC;AACjD,OAAO,EAEL,MAAM,EACN,UAAU,EACV,mBAAmB,EAEpB,MAAM,iBAAiB,CAAC;AAEzB;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,4EAE9D;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,MAAM,sBAE5D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,GACnB,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAc1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,KAAK,SAAS,MAAM,GAAG,OAAO,EAC9B,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,UAAU,EAEpB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACtC,eAAe,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,SAGxC,OAAO,CAAC,CAAC,KACb,QACD,OAAO,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,0BAA0B,CAAC,CAAC,CAClE,CAYF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,KAAK,SAAS,MAAM,GAAG,OAAO,EAC9B,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,UAAU,EAEpB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACzC,eAAe,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAC9C;IACD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC;CAC5E,CAuDA;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,SAAS,MAAM,EAC9D,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,6BAUlB;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,sBAAsB,CAKpE"}
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../testUtils.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAY,MAAM,aAAa,CAAC;AACjD,OAAO,EAEL,MAAM,EACN,UAAU,EACV,mBAAmB,EAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,4EAE9D;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,MAAM,sBAE5D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,KAAK,CAAC,EAAE,KAAK,GACZ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAuB1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,KAAK,SAAS,MAAM,GAAG,OAAO,EAC9B,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,UAAU,EAEpB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACtC,eAAe,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,SAGxC,OAAO,CAAC,CAAC,KACb,QACD,OAAO,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,0BAA0B,CAAC,CAAC,CAClE,CAYF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,KAAK,SAAS,MAAM,GAAG,OAAO,EAC9B,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,UAAU,EAEpB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACzC,eAAe,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAC9C;IACD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC;CAC5E,CAuDA;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,SAAS,MAAM,EAC9D,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,6BAUlB;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,sBAAsB,CAKpE"}
package/dist/testUtils.js CHANGED
@@ -48,11 +48,12 @@ export async function createLocalWebSocketClient(port) {
48
48
  * @param wss - The WebSocketServer instance to use for the server transport.
49
49
  * @returns An array containing the client and server {@link WebSocketTransport} instances.
50
50
  */
51
- export function createWsTransports(port, wss) {
51
+ export function createWsTransports(port, wss, codec) {
52
+ const options = codec ? { codec } : undefined;
52
53
  return [
53
54
  new WebSocketTransport(async () => {
54
55
  return createLocalWebSocketClient(port);
55
- }, 'client'),
56
+ }, 'client', options),
56
57
  new WebSocketTransport(async () => {
57
58
  return new Promise((resolve) => {
58
59
  wss.on('connection', async function onConnect(serverSock) {
@@ -60,7 +61,7 @@ export function createWsTransports(port, wss) {
60
61
  resolve(serverSock);
61
62
  });
62
63
  });
63
- }, 'SERVER'),
64
+ }, 'SERVER', options),
64
65
  ];
65
66
  }
66
67
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../transport/impls/stdio.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,UAAU,OAAO;IACf,KAAK,EAAE,KAAK,CAAC;CACd;AAMD;;;GAGG;AACH,qBAAa,cAAe,SAAQ,SAAS;IAC3C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAE9B;;;;;OAKG;gBAED,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,EAC9C,eAAe,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAapC;;;;OAIG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM;IAMzC;;OAEG;IACG,KAAK;CACZ"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../transport/impls/stdio.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,UAAU,OAAO;IACf,KAAK,EAAE,KAAK,CAAC;CACd;AAQD;;;GAGG;AACH,qBAAa,cAAe,SAAQ,SAAS;IAC3C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAE9B;;;;;OAKG;gBAED,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,EAC9C,eAAe,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAcpC;;;;OAIG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM;IAWzC;;OAEG;IACG,KAAK;CACZ"}
@@ -4,6 +4,7 @@ import readline from 'readline';
4
4
  const defaultOptions = {
5
5
  codec: NaiveJsonCodec,
6
6
  };
7
+ const newlineBuff = new TextEncoder().encode('\n');
7
8
  /**
8
9
  * A transport implementation that uses standard input and output streams.
9
10
  * @extends Transport
@@ -31,7 +32,8 @@ export class StdioTransport extends Transport {
31
32
  const rl = readline.createInterface({
32
33
  input: this.input,
33
34
  });
34
- rl.on('line', (msg) => this.onMessage(msg));
35
+ const encoder = new TextEncoder();
36
+ rl.on('line', (msg) => this.onMessage(encoder.encode(msg)));
35
37
  }
36
38
  /**
37
39
  * Sends a message over the transport.
@@ -40,7 +42,11 @@ export class StdioTransport extends Transport {
40
42
  */
41
43
  send(msg) {
42
44
  const id = msg.id;
43
- this.output.write(this.codec.toStringBuf(msg) + '\n');
45
+ const payload = this.codec.toBuffer(msg);
46
+ const out = new Uint8Array(payload.length + newlineBuff.length);
47
+ out.set(payload, 0);
48
+ out.set(newlineBuff, payload.length);
49
+ this.output.write(out);
44
50
  return id;
45
51
  }
46
52
  /**
@@ -6,6 +6,7 @@ import { type Codec } from '../../codec';
6
6
  interface Options {
7
7
  retryIntervalMs: number;
8
8
  codec: Codec;
9
+ binaryType: 'arraybuffer' | 'blob';
9
10
  }
10
11
  type WebSocketResult = {
11
12
  ws: WebSocket;
@@ -1 +1 @@
1
- {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../../transport/impls/ws.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,UAAU,OAAO;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;CACd;AAOD,KAAK,eAAe,GAAG;IAAE,EAAE,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C;;OAEG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAE5C;;;OAGG;IACH,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAE5B;;;;;OAKG;gBAED,QAAQ,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,EAClC,QAAQ,EAAE,iBAAiB,EAC3B,eAAe,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAWpC;;OAEG;YACW,UAAU;IAkExB;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IAyB5C;;OAEG;IACG,KAAK;CAKZ"}
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../../transport/impls/ws.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,UAAU,OAAO;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,aAAa,GAAG,MAAM,CAAC;CACpC;AAQD,KAAK,eAAe,GAAG;IAAE,EAAE,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C;;OAEG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAE5C;;;OAGG;IACH,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAE5B;;;;;OAKG;gBAED,QAAQ,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,EAClC,QAAQ,EAAE,iBAAiB,EAC3B,eAAe,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAWpC;;OAEG;YACW,UAAU;IAmExB;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IAyB5C;;OAEG;IACG,KAAK;CAKZ"}
@@ -4,6 +4,7 @@ import { log } from '../../logging';
4
4
  const defaultOptions = {
5
5
  retryIntervalMs: 250,
6
6
  codec: NaiveJsonCodec,
7
+ binaryType: 'arraybuffer',
7
8
  };
8
9
  /**
9
10
  * A transport implementation that uses a WebSocket connection with automatic reconnection.
@@ -79,7 +80,8 @@ export class WebSocketTransport extends Transport {
79
80
  if ('ws' in res && res.ws.readyState === res.ws.OPEN) {
80
81
  log?.info(`${this.clientId} -- websocket ok`);
81
82
  this.ws = res.ws;
82
- this.ws.onmessage = (msg) => this.onMessage(msg.data.toString());
83
+ this.ws.binaryType = 'arraybuffer';
84
+ this.ws.onmessage = (msg) => this.onMessage(msg.data);
83
85
  this.ws.onclose = () => {
84
86
  this.reconnectPromise = undefined;
85
87
  this.tryConnect().catch();
@@ -93,7 +95,7 @@ export class WebSocketTransport extends Transport {
93
95
  throw new Error(err);
94
96
  }
95
97
  log?.info(`${this.clientId} -- sending ${JSON.stringify(msg)}`);
96
- this.ws.send(this.codec.toStringBuf(msg));
98
+ this.ws.send(this.codec.toBuffer(msg));
97
99
  }
98
100
  this.sendQueue = [];
99
101
  return;
@@ -119,7 +121,7 @@ export class WebSocketTransport extends Transport {
119
121
  this.sendBuffer.set(id, msg);
120
122
  if (this.ws && this.ws.readyState === this.ws.OPEN) {
121
123
  log?.info(`${this.clientId} -- sending ${JSON.stringify(msg)}`);
122
- this.ws.send(this.codec.toStringBuf(msg));
124
+ this.ws.send(this.codec.toBuffer(msg));
123
125
  }
124
126
  else {
125
127
  log?.info(`${this.clientId} -- transport not ready, queuing ${JSON.stringify(msg)}`);
@@ -33,7 +33,7 @@ export declare abstract class Transport {
33
33
  * You generally shouldn't need to override this in downstream transport implementations.
34
34
  * @param msg The received message.
35
35
  */
36
- onMessage(msg: string): void;
36
+ onMessage(msg: Uint8Array): void;
37
37
  /**
38
38
  * Adds a message listener to this transport.
39
39
  * @param handler The message handler to add.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../transport/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAEL,SAAS,EACT,sBAAsB,EAGtB,iBAAiB,EAGlB,MAAM,WAAW,CAAC;AAGnB;;;;GAIG;AACH,8BAAsB,SAAS;IAC7B;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAE5B;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,CAAC,CAAC;IAGrD;;OAEG;IACH,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAEnD;;;;OAIG;gBACS,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,iBAAiB;IAOrD;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM;IAuCrB;;;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,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IACrD,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAChC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../transport/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAEL,SAAS,EACT,sBAAsB,EAGtB,iBAAiB,EAGlB,MAAM,WAAW,CAAC;AAGnB;;;;GAIG;AACH,8BAAsB,SAAS;IAC7B;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAE5B;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,CAAC,CAAC;IAGrD;;OAEG;IACH,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAEnD;;;;OAIG;gBACS,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,iBAAiB;IAOrD;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,UAAU;IAuCzB;;;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,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IACrD,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAChC"}
@@ -41,7 +41,7 @@ export class Transport {
41
41
  * @param msg The received message.
42
42
  */
43
43
  onMessage(msg) {
44
- const parsedMsg = this.codec.fromStringBuf(msg);
44
+ const parsedMsg = this.codec.fromBuffer(msg);
45
45
  if (parsedMsg === null) {
46
46
  log?.warn(`${this.clientId} -- received malformed msg: ${msg}`);
47
47
  return;
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.5.2",
5
+ "version": "0.6.1",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./dist/router/index.js",
@@ -17,6 +17,7 @@
17
17
  "dist"
18
18
  ],
19
19
  "dependencies": {
20
+ "@msgpack/msgpack": "^3.0.0-beta2",
20
21
  "@sinclair/typebox": "^0.31.8",
21
22
  "isomorphic-ws": "^5.0.0",
22
23
  "it-pushable": "^3.2.1",