@replit/river 0.6.2 → 0.6.4

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.
@@ -29,7 +29,7 @@ export declare class WebSocketTransport extends Transport {
29
29
  * A flag indicating whether the transport has been destroyed.
30
30
  * A destroyed transport will not attempt to reconnect and cannot be used again.
31
31
  */
32
- destroyed: boolean;
32
+ state: 'open' | 'closed' | 'destroyed';
33
33
  /**
34
34
  * An ongoing reconnect attempt if it exists. When the attempt finishes, it contains a
35
35
  * {@link WebSocketResult} object when a connection is established or an error occurs.
@@ -59,9 +59,13 @@ export declare class WebSocketTransport extends Transport {
59
59
  */
60
60
  send(msg: OpaqueTransportMessage): MessageId;
61
61
  /**
62
- * Destroys the WebSocket transport and marks it as unusable.
62
+ * Closes the WebSocket transport. Any messages sent while the transport is closed will be silently discarded.
63
63
  */
64
64
  close(): Promise<void | undefined>;
65
+ /**
66
+ * Destroys the WebSocket transport. Any messages sent while the transport is closed will throw an error.
67
+ */
68
+ destroy(): Promise<void | undefined>;
65
69
  }
66
70
  export {};
67
71
  //# sourceMappingURL=ws.d.ts.map
@@ -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;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"}
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,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;IAEvC;;;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;IAuExB;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,sBAAsB,GAAG,SAAS;IA4B5C;;OAEG;IACG,KAAK;IAMX;;OAEG;IACG,OAAO;CAKd"}
@@ -22,7 +22,7 @@ export class WebSocketTransport extends Transport {
22
22
  * A flag indicating whether the transport has been destroyed.
23
23
  * A destroyed transport will not attempt to reconnect and cannot be used again.
24
24
  */
25
- destroyed;
25
+ state;
26
26
  /**
27
27
  * An ongoing reconnect attempt if it exists. When the attempt finishes, it contains a
28
28
  * {@link WebSocketResult} object when a connection is established or an error occurs.
@@ -42,7 +42,7 @@ export class WebSocketTransport extends Transport {
42
42
  constructor(wsGetter, clientId, providedOptions) {
43
43
  const options = { ...defaultOptions, ...providedOptions };
44
44
  super(options.codec, clientId);
45
- this.destroyed = false;
45
+ this.state = 'open';
46
46
  this.wsGetter = wsGetter;
47
47
  this.options = options;
48
48
  this.sendQueue = [];
@@ -52,6 +52,9 @@ export class WebSocketTransport extends Transport {
52
52
  * Begins a new attempt to establish a WebSocket connection.
53
53
  */
54
54
  async tryConnect() {
55
+ if (this.state !== 'open') {
56
+ return;
57
+ }
55
58
  // wait until it's ready or we get an error
56
59
  this.reconnectPromise ??= new Promise(async (resolve) => {
57
60
  log?.info(`${this.clientId} -- establishing a new websocket`);
@@ -113,11 +116,15 @@ export class WebSocketTransport extends Transport {
113
116
  */
114
117
  send(msg) {
115
118
  const id = msg.id;
116
- if (this.destroyed) {
119
+ if (this.state === 'destroyed') {
117
120
  const err = 'ws is destroyed, cant send';
118
- log?.error(err);
121
+ log?.error(err + `: ${JSON.stringify(msg)}`);
119
122
  throw new Error(err);
120
123
  }
124
+ else if (this.state === 'closed') {
125
+ log?.info(`ws is closed, discarding msg: ${JSON.stringify(msg)}`);
126
+ return msg.id;
127
+ }
121
128
  this.sendBuffer.set(id, msg);
122
129
  if (this.ws && this.ws.readyState === this.ws.OPEN) {
123
130
  log?.info(`${this.clientId} -- sending ${JSON.stringify(msg)}`);
@@ -131,11 +138,19 @@ export class WebSocketTransport extends Transport {
131
138
  return id;
132
139
  }
133
140
  /**
134
- * Destroys the WebSocket transport and marks it as unusable.
141
+ * Closes the WebSocket transport. Any messages sent while the transport is closed will be silently discarded.
135
142
  */
136
143
  async close() {
137
- log?.info('manually closed ws');
138
- this.destroyed = true;
144
+ log?.info('closed ws transport');
145
+ this.state = 'closed';
146
+ return this.ws?.close();
147
+ }
148
+ /**
149
+ * Destroys the WebSocket transport. Any messages sent while the transport is closed will throw an error.
150
+ */
151
+ async destroy() {
152
+ log?.info('destroyed ws transport');
153
+ this.state = 'destroyed';
139
154
  return this.ws?.close();
140
155
  }
141
156
  }
@@ -52,13 +52,13 @@ describe('retry logic', async () => {
52
52
  clientTransport.send(msg2);
53
53
  return expect(waitForMessage(serverTransport, (recv) => recv.id === msg2.id)).resolves.toStrictEqual(msg2.payload);
54
54
  });
55
- test('ws transport is not recreated after manually closing', async () => {
55
+ test('ws transport is not recreated after destroy', async () => {
56
56
  const [clientTransport, serverTransport] = createWsTransports(port, wss);
57
57
  const msg1 = createDummyTransportMessage();
58
58
  const msg2 = createDummyTransportMessage();
59
59
  clientTransport.send(msg1);
60
60
  await expect(waitForMessage(serverTransport, (recv) => recv.id === msg1.id)).resolves.toStrictEqual(msg1.payload);
61
- clientTransport.close();
61
+ clientTransport.destroy();
62
62
  return expect(() => clientTransport.send(msg2)).toThrow(new Error('ws is destroyed, cant send'));
63
63
  });
64
64
  });
@@ -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,UAAU;IA2CzB;;;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;IAoDzB;;;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"}
@@ -43,20 +43,24 @@ export class Transport {
43
43
  onMessage(msg) {
44
44
  const parsedMsg = this.codec.fromBuffer(msg);
45
45
  if (parsedMsg === null) {
46
- log?.warn(`${this.clientId} -- received malformed msg: ${msg.toString()}`);
46
+ log?.warn(`${this.clientId} -- received malformed msg: ${new TextDecoder().decode(msg)}`);
47
47
  return;
48
48
  }
49
+ let stringifiedMessage;
50
+ if (log) {
51
+ stringifiedMessage = JSON.stringify(parsedMsg);
52
+ }
49
53
  if (Value.Check(TransportAckSchema, parsedMsg) &&
50
54
  isAck(parsedMsg.controlFlags)) {
51
55
  // process ack
52
- log?.info(`${this.clientId} -- received ack: ${msg.toString()}`);
56
+ log?.info(`${this.clientId} -- received ack: ${stringifiedMessage}`);
53
57
  if (this.sendBuffer.has(parsedMsg.payload.ack)) {
54
58
  this.sendBuffer.delete(parsedMsg.payload.ack);
55
59
  }
56
60
  }
57
61
  else if (Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
58
62
  // regular river message
59
- log?.info(`${this.clientId} -- received msg: ${msg.toString()}`);
63
+ log?.info(`${this.clientId} -- received msg: ${stringifiedMessage}`);
60
64
  // ignore if not for us
61
65
  if (parsedMsg.to !== this.clientId && parsedMsg.to !== 'broadcast') {
62
66
  return;
@@ -71,7 +75,7 @@ export class Transport {
71
75
  this.send(ackMsg);
72
76
  }
73
77
  else {
74
- log?.warn(`${this.clientId} -- received invalid transport msg: ${msg.toString()}`);
78
+ log?.warn(`${this.clientId} -- received invalid transport msg: ${stringifiedMessage}`);
75
79
  }
76
80
  }
77
81
  /**
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.6.2",
5
+ "version": "0.6.4",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./dist/router/index.js",