@replit/river 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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"}
@@ -4,7 +4,7 @@ import type { Pushable } from 'it-pushable';
4
4
  import { Server } from './server';
5
5
  import { Static } from '@sinclair/typebox';
6
6
  import { Result } from './result';
7
- type AsyncIter<T> = AsyncGenerator<T, T, T>;
7
+ type AsyncIter<T> = AsyncGenerator<T, T, unknown>;
8
8
  /**
9
9
  * A helper type to transform an actual service type into a type
10
10
  * we can case to in the proxy.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../router/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,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;AAMlC,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,CAAC,CAAC,CAAC;AAE5C;;;;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,SAAS,sBAgFO,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../router/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,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;AAMlC,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,SAAS,sBAgFO,CAAC"}
@@ -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,6 +1,10 @@
1
1
  /// <reference types="node" />
2
+ import { Codec } from '../../codec';
2
3
  import { OpaqueTransportMessage, TransportClientId } from '../message';
3
4
  import { Transport } from '../types';
5
+ interface Options {
6
+ codec: Codec;
7
+ }
4
8
  /**
5
9
  * A transport implementation that uses standard input and output streams.
6
10
  * @extends Transport
@@ -20,7 +24,7 @@ export declare class StdioTransport extends Transport {
20
24
  * @param input - The readable stream to use as input. Defaults to process.stdin.
21
25
  * @param output - The writable stream to use as output. Defaults to process.stdout.
22
26
  */
23
- constructor(clientId: TransportClientId, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream);
27
+ constructor(clientId: TransportClientId, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream, providedOptions?: Partial<Options>);
24
28
  /**
25
29
  * Sends a message over the transport.
26
30
  * @param msg - The message to send.
@@ -32,4 +36,5 @@ export declare class StdioTransport extends Transport {
32
36
  */
33
37
  close(): Promise<void>;
34
38
  }
39
+ export {};
35
40
  //# sourceMappingURL=stdio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../transport/impls/stdio.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC;;;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;IAYhD;;;;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"}
@@ -1,6 +1,10 @@
1
1
  import { NaiveJsonCodec } from '../../codec/json';
2
2
  import { Transport } from '../types';
3
3
  import readline from 'readline';
4
+ const defaultOptions = {
5
+ codec: NaiveJsonCodec,
6
+ };
7
+ const newlineBuff = new TextEncoder().encode('\n');
4
8
  /**
5
9
  * A transport implementation that uses standard input and output streams.
6
10
  * @extends Transport
@@ -20,14 +24,16 @@ export class StdioTransport extends Transport {
20
24
  * @param input - The readable stream to use as input. Defaults to process.stdin.
21
25
  * @param output - The writable stream to use as output. Defaults to process.stdout.
22
26
  */
23
- constructor(clientId, input = process.stdin, output = process.stdout) {
24
- super(NaiveJsonCodec, clientId);
27
+ constructor(clientId, input = process.stdin, output = process.stdout, providedOptions) {
28
+ const options = { ...defaultOptions, ...providedOptions };
29
+ super(options.codec, clientId);
25
30
  this.input = input;
26
31
  this.output = output;
27
32
  const rl = readline.createInterface({
28
33
  input: this.input,
29
34
  });
30
- rl.on('line', (msg) => this.onMessage(msg));
35
+ const encoder = new TextEncoder();
36
+ rl.on('line', (msg) => this.onMessage(encoder.encode(msg)));
31
37
  }
32
38
  /**
33
39
  * Sends a message over the transport.
@@ -36,7 +42,11 @@ export class StdioTransport extends Transport {
36
42
  */
37
43
  send(msg) {
38
44
  const id = msg.id;
39
- 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);
40
50
  return id;
41
51
  }
42
52
  /**
@@ -2,8 +2,11 @@
2
2
  import WebSocket from 'isomorphic-ws';
3
3
  import { Transport } from '../types';
4
4
  import { MessageId, OpaqueTransportMessage, TransportClientId } from '../message';
5
+ import { type Codec } from '../../codec';
5
6
  interface Options {
6
7
  retryIntervalMs: number;
8
+ codec: Codec;
9
+ binaryType: 'arraybuffer' | 'blob';
7
10
  }
8
11
  type WebSocketResult = {
9
12
  ws: WebSocket;
@@ -41,9 +44,9 @@ export declare class WebSocketTransport extends Transport {
41
44
  * Creates a new WebSocketTransport instance.
42
45
  * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
43
46
  * @param clientId The ID of the client using the transport.
44
- * @param options An optional object containing configuration options for the transport.
47
+ * @param providedOptions An optional object containing configuration options for the transport.
45
48
  */
46
- constructor(wsGetter: () => Promise<WebSocket>, clientId: TransportClientId, options?: Partial<Options>);
49
+ constructor(wsGetter: () => Promise<WebSocket>, clientId: TransportClientId, providedOptions?: Partial<Options>);
47
50
  /**
48
51
  * Begins a new attempt to establish a WebSocket connection.
49
52
  */
@@ -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;AAGpB,UAAU,OAAO;IACf,eAAe,EAAE,MAAM,CAAC;CACzB;AAMD,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,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAU5B;;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"}
@@ -3,6 +3,8 @@ import { NaiveJsonCodec } from '../../codec/json';
3
3
  import { log } from '../../logging';
4
4
  const defaultOptions = {
5
5
  retryIntervalMs: 250,
6
+ codec: NaiveJsonCodec,
7
+ binaryType: 'arraybuffer',
6
8
  };
7
9
  /**
8
10
  * A transport implementation that uses a WebSocket connection with automatic reconnection.
@@ -35,13 +37,14 @@ export class WebSocketTransport extends Transport {
35
37
  * Creates a new WebSocketTransport instance.
36
38
  * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
37
39
  * @param clientId The ID of the client using the transport.
38
- * @param options An optional object containing configuration options for the transport.
40
+ * @param providedOptions An optional object containing configuration options for the transport.
39
41
  */
40
- constructor(wsGetter, clientId, options) {
41
- super(NaiveJsonCodec, clientId);
42
+ constructor(wsGetter, clientId, providedOptions) {
43
+ const options = { ...defaultOptions, ...providedOptions };
44
+ super(options.codec, clientId);
42
45
  this.destroyed = false;
43
46
  this.wsGetter = wsGetter;
44
- this.options = { ...defaultOptions, ...options };
47
+ this.options = options;
45
48
  this.sendQueue = [];
46
49
  this.tryConnect();
47
50
  }
@@ -77,7 +80,8 @@ export class WebSocketTransport extends Transport {
77
80
  if ('ws' in res && res.ws.readyState === res.ws.OPEN) {
78
81
  log?.info(`${this.clientId} -- websocket ok`);
79
82
  this.ws = res.ws;
80
- this.ws.onmessage = (msg) => this.onMessage(msg.data.toString());
83
+ this.ws.binaryType = 'arraybuffer';
84
+ this.ws.onmessage = (msg) => this.onMessage(msg.data);
81
85
  this.ws.onclose = () => {
82
86
  this.reconnectPromise = undefined;
83
87
  this.tryConnect().catch();
@@ -91,7 +95,7 @@ export class WebSocketTransport extends Transport {
91
95
  throw new Error(err);
92
96
  }
93
97
  log?.info(`${this.clientId} -- sending ${JSON.stringify(msg)}`);
94
- this.ws.send(this.codec.toStringBuf(msg));
98
+ this.ws.send(this.codec.toBuffer(msg));
95
99
  }
96
100
  this.sendQueue = [];
97
101
  return;
@@ -117,7 +121,7 @@ export class WebSocketTransport extends Transport {
117
121
  this.sendBuffer.set(id, msg);
118
122
  if (this.ws && this.ws.readyState === this.ws.OPEN) {
119
123
  log?.info(`${this.clientId} -- sending ${JSON.stringify(msg)}`);
120
- this.ws.send(this.codec.toStringBuf(msg));
124
+ this.ws.send(this.codec.toBuffer(msg));
121
125
  }
122
126
  else {
123
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.1",
5
+ "version": "0.6.0",
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",