@replit/river 0.10.10 → 0.10.11
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 +19 -0
- package/dist/{chunk-FTVAZZ6B.js → chunk-KW5VFJRN.js} +26 -20
- package/dist/transport/impls/ws/client.cjs +26 -20
- package/dist/transport/impls/ws/client.d.cts +4 -3
- package/dist/transport/impls/ws/client.d.ts +4 -3
- package/dist/transport/impls/ws/client.js +1 -1
- package/dist/util/testHelpers.cjs +26 -20
- package/dist/util/testHelpers.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,7 @@ In another file for the client (to create a separate entrypoint),
|
|
|
89
89
|
import WebSocket from 'isomorphic-ws';
|
|
90
90
|
import { WebSocketClientTransport } from '@replit/river/transport/ws/client';
|
|
91
91
|
import { createClient } from '@replit/river';
|
|
92
|
+
import type ServiceSurface from './server';
|
|
92
93
|
|
|
93
94
|
const websocketUrl = `ws://localhost:3000`;
|
|
94
95
|
const transport = new WebSocketClientTransport(
|
|
@@ -118,6 +119,24 @@ bindLogger(console.log);
|
|
|
118
119
|
setLevel('info');
|
|
119
120
|
```
|
|
120
121
|
|
|
122
|
+
To listen for connection status changes,
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
transport.addEventListener('connectionStatus', (evt) => {
|
|
126
|
+
if (evt.status === 'connect') {
|
|
127
|
+
// do something
|
|
128
|
+
} else if (evt.status === 'disconnect') {
|
|
129
|
+
// do something else
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
> [!note] WebSocket connection behaviour
|
|
135
|
+
> WebSocket is an idle protocol. This means that when the underlying connection drops, the WebSocket
|
|
136
|
+
> may still think it is still connected (e.g. turning off the network via devtools).
|
|
137
|
+
> You can use `window.addEventListener('online', ...);` and `window.addEventListener('offline', ...);` to
|
|
138
|
+
> know if you need to recreate the transport.
|
|
139
|
+
|
|
121
140
|
### Further examples
|
|
122
141
|
|
|
123
142
|
We've also provided an end-to-end testing environment using Next.js, and a simple backend connected
|
|
@@ -27,14 +27,15 @@ var WebSocketClientTransport = class extends Transport {
|
|
|
27
27
|
reconnectPromises;
|
|
28
28
|
tryReconnecting = true;
|
|
29
29
|
/**
|
|
30
|
-
* Creates a new
|
|
30
|
+
* Creates a new WebSocketClientTransport instance.
|
|
31
31
|
* @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
|
|
32
|
-
* @param
|
|
32
|
+
* @param sessionId The ID of the client using the transport. This should be unique per session.
|
|
33
|
+
* @param serverId The ID of the server this transport is connecting to.
|
|
33
34
|
* @param providedOptions An optional object containing configuration options for the transport.
|
|
34
35
|
*/
|
|
35
|
-
constructor(wsGetter,
|
|
36
|
+
constructor(wsGetter, sessionId, serverId, providedOptions) {
|
|
36
37
|
const options = { ...defaultOptions, ...providedOptions };
|
|
37
|
-
super(options.codec,
|
|
38
|
+
super(options.codec, sessionId);
|
|
38
39
|
this.wsGetter = wsGetter;
|
|
39
40
|
this.serverId = serverId;
|
|
40
41
|
this.options = options;
|
|
@@ -55,23 +56,28 @@ var WebSocketClientTransport = class extends Transport {
|
|
|
55
56
|
}
|
|
56
57
|
reconnectPromise = new Promise(async (resolve) => {
|
|
57
58
|
log?.info(`${this.clientId} -- establishing a new websocket to ${to}`);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
try {
|
|
60
|
+
const ws = await this.wsGetter(to);
|
|
61
|
+
if (ws.readyState === ws.OPEN) {
|
|
62
|
+
return resolve({ ws });
|
|
63
|
+
}
|
|
64
|
+
if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
|
|
65
|
+
return resolve({ err: "ws is closing or closed" });
|
|
66
|
+
}
|
|
67
|
+
const onOpen = () => {
|
|
68
|
+
ws.removeEventListener("open", onOpen);
|
|
69
|
+
resolve({ ws });
|
|
70
|
+
};
|
|
71
|
+
const onClose = (evt) => {
|
|
72
|
+
ws.removeEventListener("close", onClose);
|
|
73
|
+
resolve({ err: evt.reason });
|
|
74
|
+
};
|
|
75
|
+
ws.addEventListener("open", onOpen);
|
|
76
|
+
ws.addEventListener("close", onClose);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
const reason = e instanceof Error ? e.message : "unknown reason";
|
|
79
|
+
return resolve({ err: `couldn't get a new websocket: ${reason}` });
|
|
61
80
|
}
|
|
62
|
-
if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
|
|
63
|
-
return resolve({ err: "ws is closing or closed" });
|
|
64
|
-
}
|
|
65
|
-
const onOpen = () => {
|
|
66
|
-
ws.removeEventListener("open", onOpen);
|
|
67
|
-
resolve({ ws });
|
|
68
|
-
};
|
|
69
|
-
const onClose = (evt) => {
|
|
70
|
-
ws.removeEventListener("close", onClose);
|
|
71
|
-
resolve({ err: evt.reason });
|
|
72
|
-
};
|
|
73
|
-
ws.addEventListener("open", onOpen);
|
|
74
|
-
ws.addEventListener("close", onClose);
|
|
75
81
|
});
|
|
76
82
|
this.reconnectPromises.set(to, reconnectPromise);
|
|
77
83
|
}
|
|
@@ -417,14 +417,15 @@ var WebSocketClientTransport = class extends Transport {
|
|
|
417
417
|
reconnectPromises;
|
|
418
418
|
tryReconnecting = true;
|
|
419
419
|
/**
|
|
420
|
-
* Creates a new
|
|
420
|
+
* Creates a new WebSocketClientTransport instance.
|
|
421
421
|
* @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
|
|
422
|
-
* @param
|
|
422
|
+
* @param sessionId The ID of the client using the transport. This should be unique per session.
|
|
423
|
+
* @param serverId The ID of the server this transport is connecting to.
|
|
423
424
|
* @param providedOptions An optional object containing configuration options for the transport.
|
|
424
425
|
*/
|
|
425
|
-
constructor(wsGetter,
|
|
426
|
+
constructor(wsGetter, sessionId, serverId, providedOptions) {
|
|
426
427
|
const options = { ...defaultOptions, ...providedOptions };
|
|
427
|
-
super(options.codec,
|
|
428
|
+
super(options.codec, sessionId);
|
|
428
429
|
this.wsGetter = wsGetter;
|
|
429
430
|
this.serverId = serverId;
|
|
430
431
|
this.options = options;
|
|
@@ -445,23 +446,28 @@ var WebSocketClientTransport = class extends Transport {
|
|
|
445
446
|
}
|
|
446
447
|
reconnectPromise = new Promise(async (resolve) => {
|
|
447
448
|
log?.info(`${this.clientId} -- establishing a new websocket to ${to}`);
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
449
|
+
try {
|
|
450
|
+
const ws = await this.wsGetter(to);
|
|
451
|
+
if (ws.readyState === ws.OPEN) {
|
|
452
|
+
return resolve({ ws });
|
|
453
|
+
}
|
|
454
|
+
if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
|
|
455
|
+
return resolve({ err: "ws is closing or closed" });
|
|
456
|
+
}
|
|
457
|
+
const onOpen = () => {
|
|
458
|
+
ws.removeEventListener("open", onOpen);
|
|
459
|
+
resolve({ ws });
|
|
460
|
+
};
|
|
461
|
+
const onClose = (evt) => {
|
|
462
|
+
ws.removeEventListener("close", onClose);
|
|
463
|
+
resolve({ err: evt.reason });
|
|
464
|
+
};
|
|
465
|
+
ws.addEventListener("open", onOpen);
|
|
466
|
+
ws.addEventListener("close", onClose);
|
|
467
|
+
} catch (e) {
|
|
468
|
+
const reason = e instanceof Error ? e.message : "unknown reason";
|
|
469
|
+
return resolve({ err: `couldn't get a new websocket: ${reason}` });
|
|
451
470
|
}
|
|
452
|
-
if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
|
|
453
|
-
return resolve({ err: "ws is closing or closed" });
|
|
454
|
-
}
|
|
455
|
-
const onOpen = () => {
|
|
456
|
-
ws.removeEventListener("open", onOpen);
|
|
457
|
-
resolve({ ws });
|
|
458
|
-
};
|
|
459
|
-
const onClose = (evt) => {
|
|
460
|
-
ws.removeEventListener("close", onClose);
|
|
461
|
-
resolve({ err: evt.reason });
|
|
462
|
-
};
|
|
463
|
-
ws.addEventListener("open", onOpen);
|
|
464
|
-
ws.addEventListener("close", onClose);
|
|
465
471
|
});
|
|
466
472
|
this.reconnectPromises.set(to, reconnectPromise);
|
|
467
473
|
}
|
|
@@ -29,12 +29,13 @@ declare class WebSocketClientTransport extends Transport<WebSocketConnection> {
|
|
|
29
29
|
reconnectPromises: Map<TransportClientId, Promise<WebSocketResult>>;
|
|
30
30
|
tryReconnecting: boolean;
|
|
31
31
|
/**
|
|
32
|
-
* Creates a new
|
|
32
|
+
* Creates a new WebSocketClientTransport instance.
|
|
33
33
|
* @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
|
|
34
|
-
* @param
|
|
34
|
+
* @param sessionId The ID of the client using the transport. This should be unique per session.
|
|
35
|
+
* @param serverId The ID of the server this transport is connecting to.
|
|
35
36
|
* @param providedOptions An optional object containing configuration options for the transport.
|
|
36
37
|
*/
|
|
37
|
-
constructor(wsGetter: () => Promise<WebSocket>,
|
|
38
|
+
constructor(wsGetter: () => Promise<WebSocket>, sessionId: TransportClientId, serverId: TransportClientId, providedOptions?: Partial<Options>);
|
|
38
39
|
createNewConnection(to: string, attempt?: number): Promise<void>;
|
|
39
40
|
close(): Promise<void>;
|
|
40
41
|
destroy(): Promise<void>;
|
|
@@ -29,12 +29,13 @@ declare class WebSocketClientTransport extends Transport<WebSocketConnection> {
|
|
|
29
29
|
reconnectPromises: Map<TransportClientId, Promise<WebSocketResult>>;
|
|
30
30
|
tryReconnecting: boolean;
|
|
31
31
|
/**
|
|
32
|
-
* Creates a new
|
|
32
|
+
* Creates a new WebSocketClientTransport instance.
|
|
33
33
|
* @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
|
|
34
|
-
* @param
|
|
34
|
+
* @param sessionId The ID of the client using the transport. This should be unique per session.
|
|
35
|
+
* @param serverId The ID of the server this transport is connecting to.
|
|
35
36
|
* @param providedOptions An optional object containing configuration options for the transport.
|
|
36
37
|
*/
|
|
37
|
-
constructor(wsGetter: () => Promise<WebSocket>,
|
|
38
|
+
constructor(wsGetter: () => Promise<WebSocket>, sessionId: TransportClientId, serverId: TransportClientId, providedOptions?: Partial<Options>);
|
|
38
39
|
createNewConnection(to: string, attempt?: number): Promise<void>;
|
|
39
40
|
close(): Promise<void>;
|
|
40
41
|
destroy(): Promise<void>;
|
|
@@ -454,14 +454,15 @@ var WebSocketClientTransport = class extends Transport {
|
|
|
454
454
|
reconnectPromises;
|
|
455
455
|
tryReconnecting = true;
|
|
456
456
|
/**
|
|
457
|
-
* Creates a new
|
|
457
|
+
* Creates a new WebSocketClientTransport instance.
|
|
458
458
|
* @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
|
|
459
|
-
* @param
|
|
459
|
+
* @param sessionId The ID of the client using the transport. This should be unique per session.
|
|
460
|
+
* @param serverId The ID of the server this transport is connecting to.
|
|
460
461
|
* @param providedOptions An optional object containing configuration options for the transport.
|
|
461
462
|
*/
|
|
462
|
-
constructor(wsGetter,
|
|
463
|
+
constructor(wsGetter, sessionId, serverId, providedOptions) {
|
|
463
464
|
const options = { ...defaultOptions, ...providedOptions };
|
|
464
|
-
super(options.codec,
|
|
465
|
+
super(options.codec, sessionId);
|
|
465
466
|
this.wsGetter = wsGetter;
|
|
466
467
|
this.serverId = serverId;
|
|
467
468
|
this.options = options;
|
|
@@ -482,23 +483,28 @@ var WebSocketClientTransport = class extends Transport {
|
|
|
482
483
|
}
|
|
483
484
|
reconnectPromise = new Promise(async (resolve) => {
|
|
484
485
|
log?.info(`${this.clientId} -- establishing a new websocket to ${to}`);
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
486
|
+
try {
|
|
487
|
+
const ws = await this.wsGetter(to);
|
|
488
|
+
if (ws.readyState === ws.OPEN) {
|
|
489
|
+
return resolve({ ws });
|
|
490
|
+
}
|
|
491
|
+
if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
|
|
492
|
+
return resolve({ err: "ws is closing or closed" });
|
|
493
|
+
}
|
|
494
|
+
const onOpen = () => {
|
|
495
|
+
ws.removeEventListener("open", onOpen);
|
|
496
|
+
resolve({ ws });
|
|
497
|
+
};
|
|
498
|
+
const onClose = (evt) => {
|
|
499
|
+
ws.removeEventListener("close", onClose);
|
|
500
|
+
resolve({ err: evt.reason });
|
|
501
|
+
};
|
|
502
|
+
ws.addEventListener("open", onOpen);
|
|
503
|
+
ws.addEventListener("close", onClose);
|
|
504
|
+
} catch (e) {
|
|
505
|
+
const reason = e instanceof Error ? e.message : "unknown reason";
|
|
506
|
+
return resolve({ err: `couldn't get a new websocket: ${reason}` });
|
|
491
507
|
}
|
|
492
|
-
const onOpen = () => {
|
|
493
|
-
ws.removeEventListener("open", onOpen);
|
|
494
|
-
resolve({ ws });
|
|
495
|
-
};
|
|
496
|
-
const onClose = (evt) => {
|
|
497
|
-
ws.removeEventListener("close", onClose);
|
|
498
|
-
resolve({ err: evt.reason });
|
|
499
|
-
};
|
|
500
|
-
ws.addEventListener("open", onOpen);
|
|
501
|
-
ws.addEventListener("close", onClose);
|
|
502
508
|
});
|
|
503
509
|
this.reconnectPromises.set(to, reconnectPromise);
|
|
504
510
|
}
|
package/dist/util/testHelpers.js
CHANGED
package/package.json
CHANGED