@firtoz/websocket-do 10.0.0 → 13.0.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.
- package/README.md +68 -61
- package/dist/BaseSession.d.ts +41 -0
- package/dist/BaseSession.js +5 -0
- package/dist/BaseSession.js.map +1 -0
- package/dist/BaseWebSocketDO.d.ts +42 -0
- package/dist/BaseWebSocketDO.js +4 -0
- package/dist/BaseWebSocketDO.js.map +1 -0
- package/dist/StandardSchemaSession.d.ts +41 -0
- package/dist/StandardSchemaSession.js +8 -0
- package/dist/StandardSchemaSession.js.map +1 -0
- package/dist/StandardSchemaWebSocketClient.d.ts +45 -0
- package/dist/StandardSchemaWebSocketClient.js +5 -0
- package/dist/StandardSchemaWebSocketClient.js.map +1 -0
- package/dist/StandardSchemaWebSocketDO.d.ts +28 -0
- package/dist/StandardSchemaWebSocketDO.js +5 -0
- package/dist/StandardSchemaWebSocketDO.js.map +1 -0
- package/dist/WebsocketWrapper.d.ts +9 -0
- package/dist/WebsocketWrapper.js +4 -0
- package/dist/WebsocketWrapper.js.map +1 -0
- package/dist/chunk-3C77OSOD.js +54 -0
- package/dist/chunk-3C77OSOD.js.map +1 -0
- package/dist/chunk-3LWVEY3R.js +130 -0
- package/dist/chunk-3LWVEY3R.js.map +1 -0
- package/dist/chunk-53MFRNQS.js +153 -0
- package/dist/chunk-53MFRNQS.js.map +1 -0
- package/dist/chunk-CAX4POIL.js +13 -0
- package/dist/chunk-CAX4POIL.js.map +1 -0
- package/dist/chunk-KCPOB32E.js +20 -0
- package/dist/chunk-KCPOB32E.js.map +1 -0
- package/dist/chunk-NOUFNU2O.js +10 -0
- package/dist/chunk-NOUFNU2O.js.map +1 -0
- package/dist/chunk-QMGIRIHJ.js +18 -0
- package/dist/chunk-QMGIRIHJ.js.map +1 -0
- package/dist/chunk-ULGH6X42.js +23 -0
- package/dist/chunk-ULGH6X42.js.map +1 -0
- package/dist/chunk-WJIQBI6I.js +35 -0
- package/dist/chunk-WJIQBI6I.js.map +1 -0
- package/dist/chunk-XFB6C3NZ.js +134 -0
- package/dist/chunk-XFB6C3NZ.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/parseStandardSchema.d.ts +9 -0
- package/dist/parseStandardSchema.js +4 -0
- package/dist/parseStandardSchema.js.map +1 -0
- package/dist/standardSchemaMsgpack.d.ts +8 -0
- package/dist/standardSchemaMsgpack.js +5 -0
- package/dist/standardSchemaMsgpack.js.map +1 -0
- package/dist/standardSchemaRpc.d.ts +30 -0
- package/dist/standardSchemaRpc.js +6 -0
- package/dist/standardSchemaRpc.js.map +1 -0
- package/dist/standardSchemaRpcReact.d.ts +27 -0
- package/dist/standardSchemaRpcReact.js +54 -0
- package/dist/standardSchemaRpcReact.js.map +1 -0
- package/package.json +36 -18
- package/src/BaseSession.ts +15 -5
- package/src/{ZodSession.ts → StandardSchemaSession.ts} +71 -70
- package/src/{ZodWebSocketClient.ts → StandardSchemaWebSocketClient.ts} +30 -50
- package/src/{ZodWebSocketDO.ts → StandardSchemaWebSocketDO.ts} +29 -22
- package/src/index.ts +15 -12
- package/src/parseStandardSchema.ts +17 -0
- package/src/standardSchemaMsgpack.ts +17 -0
- package/src/standardSchemaRpc.ts +83 -0
- package/src/standardSchemaRpcReact.ts +107 -0
- package/src/zodMsgpack.ts +0 -13
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type StandardSchemaWebSocketClientOptions,
|
|
3
|
+
StandardSchemaWebSocketClient,
|
|
4
|
+
} from "./StandardSchemaWebSocketClient";
|
|
5
|
+
|
|
6
|
+
export type StandardSchemaWebSocketRpcSessionConstructorOptions<
|
|
7
|
+
TClientMsg,
|
|
8
|
+
TServerMsg,
|
|
9
|
+
TPending extends { reject: (error: Error) => void },
|
|
10
|
+
> = Omit<
|
|
11
|
+
StandardSchemaWebSocketClientOptions<TClientMsg, TServerMsg>,
|
|
12
|
+
"onMessage"
|
|
13
|
+
> & {
|
|
14
|
+
onMessage: (
|
|
15
|
+
message: TServerMsg,
|
|
16
|
+
session: StandardSchemaWebSocketRpcSession<
|
|
17
|
+
TClientMsg,
|
|
18
|
+
TServerMsg,
|
|
19
|
+
TPending
|
|
20
|
+
>,
|
|
21
|
+
) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* WebSocket client session with a pending map for request/response RPC and a
|
|
26
|
+
* monotonic id helper. Wire formats stay in your Standard Schema schemas; you dispatch
|
|
27
|
+
* {@link TServerMsg} in `onMessage` (typically with `switch` + `exhaustiveGuard`)
|
|
28
|
+
* and resolve/reject entries in {@link pending}.
|
|
29
|
+
*/
|
|
30
|
+
export class StandardSchemaWebSocketRpcSession<
|
|
31
|
+
TClientMsg,
|
|
32
|
+
TServerMsg,
|
|
33
|
+
TPending extends { reject: (error: Error) => void },
|
|
34
|
+
> {
|
|
35
|
+
readonly pending = new Map<string, TPending>();
|
|
36
|
+
readonly client: StandardSchemaWebSocketClient<TClientMsg, TServerMsg>;
|
|
37
|
+
private idSeq = 0;
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
options: StandardSchemaWebSocketRpcSessionConstructorOptions<
|
|
41
|
+
TClientMsg,
|
|
42
|
+
TServerMsg,
|
|
43
|
+
TPending
|
|
44
|
+
>,
|
|
45
|
+
) {
|
|
46
|
+
const { onMessage, ...clientOptions } = options;
|
|
47
|
+
this.client = new StandardSchemaWebSocketClient({
|
|
48
|
+
...clientOptions,
|
|
49
|
+
onMessage: (message) => {
|
|
50
|
+
onMessage(message, this);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
nextId(prefix: string): string {
|
|
56
|
+
return `${prefix}-${++this.idSeq}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
rejectAllPending(reason: Error): void {
|
|
60
|
+
for (const [, pending] of this.pending) {
|
|
61
|
+
pending.reject(reason);
|
|
62
|
+
}
|
|
63
|
+
this.pending.clear();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
close(code?: number, reason?: string): void {
|
|
67
|
+
this.client.close(code, reason);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function createStandardSchemaWebSocketRpcSession<
|
|
72
|
+
TClientMsg,
|
|
73
|
+
TServerMsg,
|
|
74
|
+
TPending extends { reject: (error: Error) => void },
|
|
75
|
+
>(
|
|
76
|
+
options: StandardSchemaWebSocketRpcSessionConstructorOptions<
|
|
77
|
+
TClientMsg,
|
|
78
|
+
TServerMsg,
|
|
79
|
+
TPending
|
|
80
|
+
>,
|
|
81
|
+
): StandardSchemaWebSocketRpcSession<TClientMsg, TServerMsg, TPending> {
|
|
82
|
+
return new StandardSchemaWebSocketRpcSession(options);
|
|
83
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { DependencyList, RefObject } from "react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
type StandardSchemaWebSocketRpcSession,
|
|
5
|
+
type StandardSchemaWebSocketRpcSessionConstructorOptions,
|
|
6
|
+
createStandardSchemaWebSocketRpcSession,
|
|
7
|
+
} from "./standardSchemaRpc";
|
|
8
|
+
|
|
9
|
+
/** Options for {@link useStandardSchemaWebSocketRpc} (same as constructor options for {@link StandardSchemaWebSocketRpcSession}). */
|
|
10
|
+
export type UseStandardSchemaWebSocketRpcOptions<
|
|
11
|
+
TClientMsg,
|
|
12
|
+
TServerMsg,
|
|
13
|
+
TPending extends { reject: (error: Error) => void },
|
|
14
|
+
> = StandardSchemaWebSocketRpcSessionConstructorOptions<
|
|
15
|
+
TClientMsg,
|
|
16
|
+
TServerMsg,
|
|
17
|
+
TPending
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Connects a {@link StandardSchemaWebSocketRpcSession} in an effect: rejects all pending
|
|
22
|
+
* RPCs and closes the socket on cleanup or when `deps` change.
|
|
23
|
+
*
|
|
24
|
+
* Callback refs keep the latest `onMessage` / `onOpen` / `onClose` without
|
|
25
|
+
* listing them in `deps`, so inline handlers do not reconnect every render.
|
|
26
|
+
*
|
|
27
|
+
* Pass `deps` as the second argument; keep it aligned with values used to
|
|
28
|
+
* build `url` / `webSocket`.
|
|
29
|
+
*/
|
|
30
|
+
export function useStandardSchemaWebSocketRpc<
|
|
31
|
+
TClientMsg,
|
|
32
|
+
TServerMsg,
|
|
33
|
+
TPending extends { reject: (error: Error) => void },
|
|
34
|
+
>(
|
|
35
|
+
options: UseStandardSchemaWebSocketRpcOptions<
|
|
36
|
+
TClientMsg,
|
|
37
|
+
TServerMsg,
|
|
38
|
+
TPending
|
|
39
|
+
>,
|
|
40
|
+
deps: DependencyList,
|
|
41
|
+
): {
|
|
42
|
+
ready: boolean;
|
|
43
|
+
sessionRef: RefObject<StandardSchemaWebSocketRpcSession<
|
|
44
|
+
TClientMsg,
|
|
45
|
+
TServerMsg,
|
|
46
|
+
TPending
|
|
47
|
+
> | null>;
|
|
48
|
+
} {
|
|
49
|
+
const { onMessage, onOpen, onClose, ...clientOptions } = options;
|
|
50
|
+
|
|
51
|
+
const onMessageRef = useRef(onMessage);
|
|
52
|
+
onMessageRef.current = onMessage;
|
|
53
|
+
const onOpenRef = useRef(onOpen);
|
|
54
|
+
onOpenRef.current = onOpen;
|
|
55
|
+
const onCloseRef = useRef(onClose);
|
|
56
|
+
onCloseRef.current = onClose;
|
|
57
|
+
|
|
58
|
+
const [ready, setReady] = useState(false);
|
|
59
|
+
const sessionRef = useRef<StandardSchemaWebSocketRpcSession<
|
|
60
|
+
TClientMsg,
|
|
61
|
+
TServerMsg,
|
|
62
|
+
TPending
|
|
63
|
+
> | null>(null);
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
let cancelled = false;
|
|
67
|
+
setReady(false);
|
|
68
|
+
|
|
69
|
+
const session = createStandardSchemaWebSocketRpcSession<
|
|
70
|
+
TClientMsg,
|
|
71
|
+
TServerMsg,
|
|
72
|
+
TPending
|
|
73
|
+
>({
|
|
74
|
+
...clientOptions,
|
|
75
|
+
onMessage: (msg, s) => {
|
|
76
|
+
onMessageRef.current(msg, s);
|
|
77
|
+
},
|
|
78
|
+
onOpen: (event) => {
|
|
79
|
+
if (!cancelled) {
|
|
80
|
+
setReady(true);
|
|
81
|
+
}
|
|
82
|
+
onOpenRef.current?.(event);
|
|
83
|
+
},
|
|
84
|
+
onClose: (event) => {
|
|
85
|
+
if (!cancelled) {
|
|
86
|
+
setReady(false);
|
|
87
|
+
}
|
|
88
|
+
onCloseRef.current?.(event);
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
sessionRef.current = session;
|
|
93
|
+
if (session.client.socket.readyState === WebSocket.OPEN) {
|
|
94
|
+
setReady(true);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return () => {
|
|
98
|
+
cancelled = true;
|
|
99
|
+
sessionRef.current = null;
|
|
100
|
+
session.rejectAllPending(new Error("WebSocket closed"));
|
|
101
|
+
session.close();
|
|
102
|
+
};
|
|
103
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: deps is the explicit contract
|
|
104
|
+
}, deps);
|
|
105
|
+
|
|
106
|
+
return { ready, sessionRef };
|
|
107
|
+
}
|
package/src/zodMsgpack.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { pack, unpack } from "msgpackr";
|
|
2
|
-
import type { ZodType } from "zod";
|
|
3
|
-
|
|
4
|
-
export const zodMsgpack = <T>(schema: ZodType<T>) => ({
|
|
5
|
-
encode(value: T): Uint8Array {
|
|
6
|
-
const validated = schema.parse(value);
|
|
7
|
-
const packed = pack(validated);
|
|
8
|
-
return new Uint8Array(packed);
|
|
9
|
-
},
|
|
10
|
-
decode(bytes: Uint8Array): T {
|
|
11
|
-
return schema.parse(unpack(bytes));
|
|
12
|
-
},
|
|
13
|
-
});
|