@hedystia/ws 2.3.1 → 2.3.2
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/package.json +1 -1
- package/.turbo/turbo-build.log +0 -50
- package/src/client.ts +0 -161
- package/src/index.ts +0 -19
- package/src/runtime.ts +0 -66
- package/src/server.ts +0 -313
- package/src/types.ts +0 -226
- package/tsconfig.json +0 -3
- package/tsdown.config.ts +0 -12
package/package.json
CHANGED
package/.turbo/turbo-build.log
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
$ tsdown --config-loader unrun
|
|
2
|
-
[34mℹ[39m [34mtsdown v0.22.0[39m powered by [38;2;255;126;23mrolldown v1.0.0[39m
|
|
3
|
-
[34mℹ[39m config file: [4m/home/runner/actions-runner/_work/Hedystia/Hedystia/Packages/websocket/tsdown.config.ts[24m (unrun)
|
|
4
|
-
[34mℹ[39m entry: [34msrc/index.ts, src/client.ts, src/server.ts[39m
|
|
5
|
-
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
6
|
-
[34mℹ[39m Build start
|
|
7
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mserver.cjs[22m [2m 7.36 kB[22m [2m│ gzip: 2.69 kB[22m
|
|
8
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mclient.cjs[22m [2m 4.12 kB[22m [2m│ gzip: 1.53 kB[22m
|
|
9
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mindex.cjs[22m [2m 0.87 kB[22m [2m│ gzip: 0.34 kB[22m
|
|
10
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mserver.cjs.map [2m12.54 kB[22m [2m│ gzip: 4.06 kB[22m
|
|
11
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mclient.cjs.map [2m 5.86 kB[22m [2m│ gzip: 2.05 kB[22m
|
|
12
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mruntime.cjs.map [2m 2.06 kB[22m [2m│ gzip: 0.78 kB[22m
|
|
13
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mruntime.cjs [2m 1.36 kB[22m [2m│ gzip: 0.55 kB[22m
|
|
14
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mindex.cjs.map [2m 0.71 kB[22m [2m│ gzip: 0.33 kB[22m
|
|
15
|
-
[34mℹ[39m [33m[CJS][39m 8 files, total: 34.86 kB
|
|
16
|
-
[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugin `tsdown:report`. See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
17
|
-
|
|
18
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mserver.d.cts[22m[39m [2m4.05 kB[22m [2m│ gzip: 1.65 kB[22m
|
|
19
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mclient.d.cts[22m[39m [2m3.80 kB[22m [2m│ gzip: 1.40 kB[22m
|
|
20
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mindex.d.cts[22m[39m [2m0.73 kB[22m [2m│ gzip: 0.27 kB[22m
|
|
21
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mtypes.d.cts[39m [2m7.25 kB[22m [2m│ gzip: 2.64 kB[22m
|
|
22
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mruntime.d.cts[39m [2m1.13 kB[22m [2m│ gzip: 0.48 kB[22m
|
|
23
|
-
[34mℹ[39m [33m[CJS][39m 5 files, total: 16.96 kB
|
|
24
|
-
[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugins. Here is a breakdown:
|
|
25
|
-
- rolldown-plugin-dts:generate (63%)
|
|
26
|
-
- tsdown:deps (28%)
|
|
27
|
-
See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
28
|
-
|
|
29
|
-
[32m✔[39m Build complete in [32m4736ms[39m
|
|
30
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mserver.mjs[22m [2m 7.30 kB[22m [2m│ gzip: 2.64 kB[22m
|
|
31
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mclient.mjs[22m [2m 4.04 kB[22m [2m│ gzip: 1.50 kB[22m
|
|
32
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mindex.mjs[22m [2m 0.47 kB[22m [2m│ gzip: 0.23 kB[22m
|
|
33
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mserver.mjs.map [2m12.53 kB[22m [2m│ gzip: 4.05 kB[22m
|
|
34
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient.mjs.map [2m 5.86 kB[22m [2m│ gzip: 2.05 kB[22m
|
|
35
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mruntime.mjs.map [2m 2.06 kB[22m [2m│ gzip: 0.78 kB[22m
|
|
36
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mruntime.mjs [2m 1.27 kB[22m [2m│ gzip: 0.53 kB[22m
|
|
37
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mindex.mjs.map [2m 0.68 kB[22m [2m│ gzip: 0.32 kB[22m
|
|
38
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m_virtual/_rolldown/runtime.mjs [2m 0.18 kB[22m [2m│ gzip: 0.15 kB[22m
|
|
39
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mserver.d.mts[22m[39m [2m 4.05 kB[22m [2m│ gzip: 1.65 kB[22m
|
|
40
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mclient.d.mts[22m[39m [2m 3.80 kB[22m [2m│ gzip: 1.40 kB[22m
|
|
41
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 0.73 kB[22m [2m│ gzip: 0.27 kB[22m
|
|
42
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mtypes.d.mts[39m [2m 7.25 kB[22m [2m│ gzip: 2.64 kB[22m
|
|
43
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mruntime.d.mts[39m [2m 1.13 kB[22m [2m│ gzip: 0.48 kB[22m
|
|
44
|
-
[34mℹ[39m [34m[ESM][39m 14 files, total: 51.34 kB
|
|
45
|
-
[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugins. Here is a breakdown:
|
|
46
|
-
- tsdown:deps (51%)
|
|
47
|
-
- rolldown-plugin-dts:generate (39%)
|
|
48
|
-
See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
49
|
-
|
|
50
|
-
[32m✔[39m Build complete in [32m4846ms[39m
|
package/src/client.ts
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import type { ClientWebSocketOptions } from "./types";
|
|
2
|
-
|
|
3
|
-
export type { ClientWebSocketOptions } from "./types";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Resolve the best `WebSocket` constructor for the current runtime.
|
|
7
|
-
*
|
|
8
|
-
* @remarks
|
|
9
|
-
* - Bun, Deno, browsers and Node ≥ 22 expose `globalThis.WebSocket`.
|
|
10
|
-
* - Older Node falls back to the [`ws`](https://github.com/websockets/ws)
|
|
11
|
-
* package, which mirrors the WHATWG `WebSocket` API.
|
|
12
|
-
*
|
|
13
|
-
* @returns A `WebSocket` constructor compatible with the WHATWG interface.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* import { resolveWebSocket } from "@hedystia/ws/client";
|
|
18
|
-
*
|
|
19
|
-
* const WS = resolveWebSocket();
|
|
20
|
-
* const socket = new WS("ws://localhost:3000");
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export function resolveWebSocket(): typeof WebSocket {
|
|
24
|
-
if (typeof globalThis !== "undefined" && (globalThis as any).WebSocket) {
|
|
25
|
-
return (globalThis as any).WebSocket as typeof WebSocket;
|
|
26
|
-
}
|
|
27
|
-
const mod = require("ws");
|
|
28
|
-
return (mod.WebSocket ?? mod) as typeof WebSocket;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Create a `WebSocket` instance using the best available implementation
|
|
33
|
-
* for the current runtime.
|
|
34
|
-
*
|
|
35
|
-
* @remarks
|
|
36
|
-
* Custom request headers are honoured on Node via the `ws` package; on
|
|
37
|
-
* runtimes that ship a WHATWG-compliant global `WebSocket` (Bun, Deno,
|
|
38
|
-
* browsers, Node ≥ 22) headers are ignored — matching standard semantics.
|
|
39
|
-
*
|
|
40
|
-
* @param url - Absolute WebSocket URL (`ws://` or `wss://`)
|
|
41
|
-
* @param options - Optional protocols / headers
|
|
42
|
-
* @returns A connected (or connecting) `WebSocket` instance.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```ts
|
|
46
|
-
* import { createWebSocket } from "@hedystia/ws/client";
|
|
47
|
-
*
|
|
48
|
-
* const ws = createWebSocket("ws://localhost:3000", {
|
|
49
|
-
* protocols: "v1",
|
|
50
|
-
* headers: { authorization: "Bearer ..." },
|
|
51
|
-
* });
|
|
52
|
-
*
|
|
53
|
-
* ws.onopen = () => ws.send("hi");
|
|
54
|
-
* ws.onmessage = (event) => console.log(event.data);
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export function createWebSocket(url: string, options?: ClientWebSocketOptions): WebSocket {
|
|
58
|
-
const Ctor = resolveWebSocket();
|
|
59
|
-
const isWhatwg =
|
|
60
|
-
typeof globalThis !== "undefined" && (globalThis as any).WebSocket === (Ctor as any);
|
|
61
|
-
|
|
62
|
-
if (isWhatwg) {
|
|
63
|
-
return options?.protocols ? new Ctor(url, options.protocols as any) : new Ctor(url);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const init: any = {};
|
|
67
|
-
if (options?.headers) {
|
|
68
|
-
init.headers = options.headers;
|
|
69
|
-
}
|
|
70
|
-
return new (Ctor as any)(url, options?.protocols, init);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Lightweight runtime-agnostic wrapper that mirrors a small, predictable
|
|
75
|
-
* subset of the WHATWG WebSocket interface.
|
|
76
|
-
*
|
|
77
|
-
* @remarks
|
|
78
|
-
* Useful for higher-level code that wants to assign event handlers by
|
|
79
|
-
* property (`socket.onmessage = ...`) without caring whether the underlying
|
|
80
|
-
* implementation comes from `globalThis.WebSocket` or the `ws` package.
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* import { WebSocketClient } from "@hedystia/ws/client";
|
|
85
|
-
*
|
|
86
|
-
* const client = new WebSocketClient("ws://localhost:3000");
|
|
87
|
-
* client.onopen = () => client.send("hello");
|
|
88
|
-
* client.onmessage = (event) => console.log(event.data);
|
|
89
|
-
* ```
|
|
90
|
-
*/
|
|
91
|
-
export class WebSocketClient {
|
|
92
|
-
/**
|
|
93
|
-
* Underlying WebSocket instance produced by {@link createWebSocket}.
|
|
94
|
-
*
|
|
95
|
-
* @readonly
|
|
96
|
-
*/
|
|
97
|
-
readonly socket: WebSocket;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Create a new client and immediately initiate the connection.
|
|
101
|
-
*
|
|
102
|
-
* @param url - Absolute WebSocket URL (`ws://` or `wss://`)
|
|
103
|
-
* @param options - Optional protocols / headers, see {@link ClientWebSocketOptions}
|
|
104
|
-
*/
|
|
105
|
-
constructor(url: string, options?: ClientWebSocketOptions) {
|
|
106
|
-
this.socket = createWebSocket(url, options);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Current connection state, mirroring {@link WebSocket.readyState}.
|
|
111
|
-
*
|
|
112
|
-
* @returns `0` connecting, `1` open, `2` closing, `3` closed.
|
|
113
|
-
*/
|
|
114
|
-
get readyState(): number {
|
|
115
|
-
return this.socket.readyState;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Send a payload to the server.
|
|
120
|
-
*
|
|
121
|
-
* @param data - WHATWG-compatible payload
|
|
122
|
-
*/
|
|
123
|
-
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void {
|
|
124
|
-
this.socket.send(data as any);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Close the underlying socket.
|
|
129
|
-
*
|
|
130
|
-
* @param code - Close code (defaults to 1000)
|
|
131
|
-
* @param reason - Optional human-readable reason
|
|
132
|
-
*/
|
|
133
|
-
close(code?: number, reason?: string): void {
|
|
134
|
-
this.socket.close(code, reason);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Assign the open-event listener.
|
|
139
|
-
*/
|
|
140
|
-
set onopen(cb: ((ev: Event) => void) | null) {
|
|
141
|
-
(this.socket as any).onopen = cb;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Assign the message-event listener.
|
|
145
|
-
*/
|
|
146
|
-
set onmessage(cb: ((ev: MessageEvent) => void) | null) {
|
|
147
|
-
(this.socket as any).onmessage = cb;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Assign the close-event listener.
|
|
151
|
-
*/
|
|
152
|
-
set onclose(cb: ((ev: CloseEvent) => void) | null) {
|
|
153
|
-
(this.socket as any).onclose = cb;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Assign the error-event listener.
|
|
157
|
-
*/
|
|
158
|
-
set onerror(cb: ((ev: Event) => void) | null) {
|
|
159
|
-
(this.socket as any).onerror = cb;
|
|
160
|
-
}
|
|
161
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export type { ClientWebSocketOptions } from "./client";
|
|
2
|
-
export { createWebSocket, resolveWebSocket, WebSocketClient } from "./client";
|
|
3
|
-
export type { Runtime } from "./runtime";
|
|
4
|
-
export { detectRuntime, isBrowser, isBun, isDeno, isNode } from "./runtime";
|
|
5
|
-
export type {
|
|
6
|
-
ServerWebSocket,
|
|
7
|
-
UpgradeOptions,
|
|
8
|
-
UpgradeRequest,
|
|
9
|
-
WebSocketHandlers,
|
|
10
|
-
WebSocketServerOptions,
|
|
11
|
-
WSData,
|
|
12
|
-
WSMessage,
|
|
13
|
-
} from "./server";
|
|
14
|
-
|
|
15
|
-
import { WebSocketServer } from "./server";
|
|
16
|
-
|
|
17
|
-
export { WebSocketServer };
|
|
18
|
-
|
|
19
|
-
export default WebSocketServer;
|
package/src/runtime.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* String identifier of the JavaScript runtime hosting the current process.
|
|
3
|
-
*/
|
|
4
|
-
export type Runtime = "bun" | "node" | "deno" | "browser" | "unknown";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Detect the host runtime by probing well-known globals.
|
|
8
|
-
*
|
|
9
|
-
* @returns A {@link Runtime} discriminator for the active environment.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* import { detectRuntime } from "@hedystia/ws";
|
|
14
|
-
*
|
|
15
|
-
* if (detectRuntime() === "bun") {
|
|
16
|
-
* // ...use Bun-specific APIs
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export function detectRuntime(): Runtime {
|
|
21
|
-
if (typeof globalThis === "undefined") {
|
|
22
|
-
return "unknown";
|
|
23
|
-
}
|
|
24
|
-
const g = globalThis as any;
|
|
25
|
-
if (g.Bun?.serve) {
|
|
26
|
-
return "bun";
|
|
27
|
-
}
|
|
28
|
-
if (g.Deno) {
|
|
29
|
-
return "deno";
|
|
30
|
-
}
|
|
31
|
-
if (g.process?.versions?.node) {
|
|
32
|
-
return "node";
|
|
33
|
-
}
|
|
34
|
-
if (typeof g.window !== "undefined" && typeof g.document !== "undefined") {
|
|
35
|
-
return "browser";
|
|
36
|
-
}
|
|
37
|
-
return "unknown";
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Convenience predicate.
|
|
42
|
-
*
|
|
43
|
-
* @returns `true` when running on Bun.
|
|
44
|
-
*/
|
|
45
|
-
export const isBun = (): boolean => detectRuntime() === "bun";
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Convenience predicate.
|
|
49
|
-
*
|
|
50
|
-
* @returns `true` when running on Node.js.
|
|
51
|
-
*/
|
|
52
|
-
export const isNode = (): boolean => detectRuntime() === "node";
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Convenience predicate.
|
|
56
|
-
*
|
|
57
|
-
* @returns `true` when running on Deno.
|
|
58
|
-
*/
|
|
59
|
-
export const isDeno = (): boolean => detectRuntime() === "deno";
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Convenience predicate.
|
|
63
|
-
*
|
|
64
|
-
* @returns `true` when running inside a browser-like environment.
|
|
65
|
-
*/
|
|
66
|
-
export const isBrowser = (): boolean => detectRuntime() === "browser";
|
package/src/server.ts
DELETED
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
import { type WebSocket as NodeWebSocket, WebSocketServer as WSServer } from "ws";
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
ServerWebSocket,
|
|
5
|
-
UpgradeOptions,
|
|
6
|
-
UpgradeRequest,
|
|
7
|
-
WebSocketHandlers,
|
|
8
|
-
WebSocketServerOptions,
|
|
9
|
-
WSData,
|
|
10
|
-
WSMessage,
|
|
11
|
-
} from "./types";
|
|
12
|
-
|
|
13
|
-
export type {
|
|
14
|
-
ServerWebSocket,
|
|
15
|
-
UpgradeOptions,
|
|
16
|
-
UpgradeRequest,
|
|
17
|
-
WebSocketHandlers,
|
|
18
|
-
WebSocketServerOptions,
|
|
19
|
-
WSData,
|
|
20
|
-
WSMessage,
|
|
21
|
-
} from "./types";
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Runtime-agnostic WebSocket server.
|
|
25
|
-
*
|
|
26
|
-
* @remarks
|
|
27
|
-
* Internally backed by the [`ws`](https://github.com/websockets/ws) package
|
|
28
|
-
* which runs on Bun, Node.js and Deno (via `npm:` specifiers). The class
|
|
29
|
-
* does **not** create or own an HTTP server — callers feed it raw upgrade
|
|
30
|
-
* tuples coming from any HTTP runtime they prefer.
|
|
31
|
-
*
|
|
32
|
-
* It implements topic-based pub/sub on top of the per-connection
|
|
33
|
-
* `subscribe` / `unsubscribe` / `publish` API expected by Hedystia,
|
|
34
|
-
* matching the shape of `Bun.ServerWebSocket`.
|
|
35
|
-
*
|
|
36
|
-
* @typeParam Data - Shape of the user-attached `data` field
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* import { createServer } from "node:http";
|
|
41
|
-
* import { WebSocketServer } from "@hedystia/ws/server";
|
|
42
|
-
*
|
|
43
|
-
* const wss = new WebSocketServer({
|
|
44
|
-
* open: (ws) => ws.send("welcome"),
|
|
45
|
-
* message: (ws, msg) => ws.publish("room", msg),
|
|
46
|
-
* });
|
|
47
|
-
*
|
|
48
|
-
* const http = createServer((_req, res) => res.end("ok"));
|
|
49
|
-
* http.on("upgrade", (req, socket, head) => {
|
|
50
|
-
* wss.upgrade({ rawRequest: req, socket, head }, { data: { user: "anon" } });
|
|
51
|
-
* });
|
|
52
|
-
* http.listen(3000);
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
export class WebSocketServer<Data extends WSData = WSData> {
|
|
56
|
-
private readonly handlers: WebSocketHandlers<Data>;
|
|
57
|
-
private readonly wss: WSServer;
|
|
58
|
-
private readonly topics = new Map<string, Set<NodeWebSocket>>();
|
|
59
|
-
private readonly socketTopics = new WeakMap<NodeWebSocket, Set<string>>();
|
|
60
|
-
private readonly allSockets = new Set<NodeWebSocket>();
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Build a new WebSocket server.
|
|
64
|
-
*
|
|
65
|
-
* @param handlers - Lifecycle handlers ({@link WebSocketHandlers})
|
|
66
|
-
* @param options - Optional behavioural overrides ({@link WebSocketServerOptions})
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```ts
|
|
70
|
-
* const wss = new WebSocketServer(
|
|
71
|
-
* { message: (ws, msg) => ws.send(msg) },
|
|
72
|
-
* { maxPayload: 1024 * 1024 },
|
|
73
|
-
* );
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
constructor(handlers: WebSocketHandlers<Data>, options: WebSocketServerOptions = {}) {
|
|
77
|
-
this.handlers = handlers;
|
|
78
|
-
this.wss = new WSServer({
|
|
79
|
-
noServer: true,
|
|
80
|
-
maxPayload: options.maxPayload,
|
|
81
|
-
perMessageDeflate: (options.perMessageDeflate ?? false) as any,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Upgrade a raw HTTP upgrade tuple to a WebSocket connection.
|
|
87
|
-
*
|
|
88
|
-
* @remarks
|
|
89
|
-
* The returned promise resolves to the connected {@link ServerWebSocket}
|
|
90
|
-
* once the handshake completes; rejection means the handshake failed.
|
|
91
|
-
*
|
|
92
|
-
* @param req - Upgrade tuple emitted by `node:http`'s `'upgrade'` event
|
|
93
|
-
* @param options - Optional initial `data` for the new connection
|
|
94
|
-
* @returns Promise that resolves with the established socket wrapper
|
|
95
|
-
*
|
|
96
|
-
* @throws {Error} When the underlying handshake throws synchronously
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```ts
|
|
100
|
-
* http.on("upgrade", async (req, socket, head) => {
|
|
101
|
-
* try {
|
|
102
|
-
* await wss.upgrade({ rawRequest: req, socket, head });
|
|
103
|
-
* } catch (err) {
|
|
104
|
-
* console.error("Upgrade failed", err);
|
|
105
|
-
* socket.destroy();
|
|
106
|
-
* }
|
|
107
|
-
* });
|
|
108
|
-
* ```
|
|
109
|
-
*/
|
|
110
|
-
upgrade(req: UpgradeRequest, options?: UpgradeOptions<Data>): Promise<ServerWebSocket<Data>> {
|
|
111
|
-
return new Promise((resolve, reject) => {
|
|
112
|
-
try {
|
|
113
|
-
this.wss.handleUpgrade(req.rawRequest, req.socket, req.head as Buffer, (socket) => {
|
|
114
|
-
const data = (options?.data ?? ({} as Data)) as Data;
|
|
115
|
-
const wrapped = this.wrap(socket, data, req.rawRequest);
|
|
116
|
-
this.bind(socket, wrapped);
|
|
117
|
-
resolve(wrapped);
|
|
118
|
-
});
|
|
119
|
-
} catch (err) {
|
|
120
|
-
reject(err);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Publish a message to all sockets currently subscribed to `topic`.
|
|
127
|
-
*
|
|
128
|
-
* @param topic - Topic name
|
|
129
|
-
* @param message - Payload to broadcast
|
|
130
|
-
* @param _compress - Reserved for future use; ignored under the `ws` adapter
|
|
131
|
-
* @returns Number of sockets that received the message.
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* ```ts
|
|
135
|
-
* wss.publish("room", JSON.stringify({ kind: "ping" }));
|
|
136
|
-
* ```
|
|
137
|
-
*/
|
|
138
|
-
publish(topic: string, message: WSMessage, _compress?: boolean): number {
|
|
139
|
-
const set = this.topics.get(topic);
|
|
140
|
-
if (!set || set.size === 0) {
|
|
141
|
-
return 0;
|
|
142
|
-
}
|
|
143
|
-
const payload = toSendable(message);
|
|
144
|
-
let count = 0;
|
|
145
|
-
for (const socket of set) {
|
|
146
|
-
if (socket.readyState === 1) {
|
|
147
|
-
socket.send(payload);
|
|
148
|
-
count++;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return count;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Close the server and optionally terminate all live sockets.
|
|
156
|
-
*
|
|
157
|
-
* @param closeActiveConnections - When `true`, calls `socket.terminate()`
|
|
158
|
-
* on every live connection before shutting down.
|
|
159
|
-
*/
|
|
160
|
-
close(closeActiveConnections = false): void {
|
|
161
|
-
if (closeActiveConnections) {
|
|
162
|
-
for (const socket of this.allSockets) {
|
|
163
|
-
try {
|
|
164
|
-
socket.terminate();
|
|
165
|
-
} catch {
|
|
166
|
-
/* ignore */
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
this.allSockets.clear();
|
|
170
|
-
}
|
|
171
|
-
this.wss.close();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Attach the per-socket lifecycle listeners (`message`, `close`, `error`).
|
|
176
|
-
*
|
|
177
|
-
* @internal
|
|
178
|
-
*/
|
|
179
|
-
private bind(socket: NodeWebSocket, wrapped: ServerWebSocket<Data>): void {
|
|
180
|
-
this.allSockets.add(socket);
|
|
181
|
-
|
|
182
|
-
if (this.handlers.open) {
|
|
183
|
-
Promise.resolve(this.handlers.open(wrapped)).catch((err) =>
|
|
184
|
-
console.error("[ws] open handler error:", err),
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
socket.on("message", (raw, isBinary) => {
|
|
189
|
-
const message: WSMessage = isBinary
|
|
190
|
-
? raw instanceof ArrayBuffer
|
|
191
|
-
? new Uint8Array(raw)
|
|
192
|
-
: Array.isArray(raw)
|
|
193
|
-
? Buffer.concat(raw)
|
|
194
|
-
: (raw as Buffer)
|
|
195
|
-
: raw.toString();
|
|
196
|
-
Promise.resolve(this.handlers.message(wrapped, message)).catch((err) =>
|
|
197
|
-
console.error("[ws] message handler error:", err),
|
|
198
|
-
);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
socket.on("close", (code, reason) => {
|
|
202
|
-
const owned = this.socketTopics.get(socket);
|
|
203
|
-
if (owned) {
|
|
204
|
-
for (const topic of owned) {
|
|
205
|
-
this.topics.get(topic)?.delete(socket);
|
|
206
|
-
}
|
|
207
|
-
this.socketTopics.delete(socket);
|
|
208
|
-
}
|
|
209
|
-
this.allSockets.delete(socket);
|
|
210
|
-
if (this.handlers.close) {
|
|
211
|
-
Promise.resolve(this.handlers.close(wrapped, code, reason?.toString() ?? "")).catch((err) =>
|
|
212
|
-
console.error("[ws] close handler error:", err),
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
socket.on("error", (err) => {
|
|
218
|
-
if (this.handlers.error) {
|
|
219
|
-
Promise.resolve(this.handlers.error(wrapped, err)).catch((e) =>
|
|
220
|
-
console.error("[ws] error handler error:", e),
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Build the {@link ServerWebSocket} wrapper exposed to user handlers.
|
|
228
|
-
*
|
|
229
|
-
* @internal
|
|
230
|
-
*/
|
|
231
|
-
private wrap(socket: NodeWebSocket, data: Data, rawReq: any): ServerWebSocket<Data> {
|
|
232
|
-
const remoteAddress: string =
|
|
233
|
-
(rawReq?.socket?.remoteAddress as string) ||
|
|
234
|
-
(rawReq?.headers?.["x-forwarded-for"] as string) ||
|
|
235
|
-
"";
|
|
236
|
-
|
|
237
|
-
const subscribe = (topic: string) => {
|
|
238
|
-
let set = this.topics.get(topic);
|
|
239
|
-
if (!set) {
|
|
240
|
-
set = new Set();
|
|
241
|
-
this.topics.set(topic, set);
|
|
242
|
-
}
|
|
243
|
-
set.add(socket);
|
|
244
|
-
let owned = this.socketTopics.get(socket);
|
|
245
|
-
if (!owned) {
|
|
246
|
-
owned = new Set();
|
|
247
|
-
this.socketTopics.set(socket, owned);
|
|
248
|
-
}
|
|
249
|
-
owned.add(topic);
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const unsubscribe = (topic: string) => {
|
|
253
|
-
this.topics.get(topic)?.delete(socket);
|
|
254
|
-
this.socketTopics.get(socket)?.delete(topic);
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
const publishToPeers = (topic: string, message: WSMessage) => {
|
|
258
|
-
const set = this.topics.get(topic);
|
|
259
|
-
if (!set) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
const payload = toSendable(message);
|
|
263
|
-
for (const peer of set) {
|
|
264
|
-
if (peer !== socket && peer.readyState === 1) {
|
|
265
|
-
peer.send(payload);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const wrapper: ServerWebSocket<Data> = {
|
|
271
|
-
data,
|
|
272
|
-
get readyState() {
|
|
273
|
-
return socket.readyState;
|
|
274
|
-
},
|
|
275
|
-
remoteAddress,
|
|
276
|
-
send: (message, _compress) => {
|
|
277
|
-
const payload = toSendable(message);
|
|
278
|
-
socket.send(payload);
|
|
279
|
-
return typeof payload === "string"
|
|
280
|
-
? Buffer.byteLength(payload)
|
|
281
|
-
: (payload as Buffer | Uint8Array).byteLength;
|
|
282
|
-
},
|
|
283
|
-
close: (code, reason) => {
|
|
284
|
-
socket.close(code, reason);
|
|
285
|
-
},
|
|
286
|
-
subscribe,
|
|
287
|
-
unsubscribe,
|
|
288
|
-
publish: publishToPeers,
|
|
289
|
-
isSubscribed: (topic) => !!this.socketTopics.get(socket)?.has(topic),
|
|
290
|
-
cork: (cb) => cb(wrapper),
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
return wrapper;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Coerce a {@link WSMessage} into something the `ws` package can transmit.
|
|
299
|
-
*
|
|
300
|
-
* @param message - User-supplied payload
|
|
301
|
-
* @returns A `string`, `Buffer` or `Uint8Array` ready to be sent
|
|
302
|
-
*
|
|
303
|
-
* @internal
|
|
304
|
-
*/
|
|
305
|
-
function toSendable(message: WSMessage): string | Buffer | Uint8Array {
|
|
306
|
-
if (typeof message === "string") {
|
|
307
|
-
return message;
|
|
308
|
-
}
|
|
309
|
-
if (message instanceof ArrayBuffer) {
|
|
310
|
-
return Buffer.from(message);
|
|
311
|
-
}
|
|
312
|
-
return message;
|
|
313
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload accepted by every `send`/`publish` method.
|
|
3
|
-
*
|
|
4
|
-
* @remarks
|
|
5
|
-
* Matches the WHATWG `WebSocket.send` signature plus the `Uint8Array`
|
|
6
|
-
* convenience accepted by Bun and the `ws` package.
|
|
7
|
-
*/
|
|
8
|
-
export type WSMessage = string | ArrayBuffer | Uint8Array;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Bag of arbitrary, user-supplied state attached to a connection on
|
|
12
|
-
* upgrade and exposed to handlers as `ws.data`.
|
|
13
|
-
*
|
|
14
|
-
* @typeParam K - String key
|
|
15
|
-
* @typeParam V - Stored value
|
|
16
|
-
*/
|
|
17
|
-
export type WSData = Record<string, any>;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* The per-connection wrapper passed to every handler.
|
|
21
|
-
*
|
|
22
|
-
* @remarks
|
|
23
|
-
* The interface intentionally mirrors `Bun.ServerWebSocket` so that the
|
|
24
|
-
* same handler code works on Bun (native) and on Node.js (via
|
|
25
|
-
* {@link WebSocketServer}). Topic-based pub/sub is implemented in
|
|
26
|
-
* user-space when running outside Bun.
|
|
27
|
-
*
|
|
28
|
-
* @typeParam Data - Shape of the user-attached `data` field
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```ts
|
|
32
|
-
* const handlers: WebSocketHandlers<{ user: string }> = {
|
|
33
|
-
* open: (ws) => ws.subscribe(`user:${ws.data.user}`),
|
|
34
|
-
* message: (ws, msg) => ws.publish(`user:${ws.data.user}`, msg),
|
|
35
|
-
* };
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export interface ServerWebSocket<Data extends WSData = WSData> {
|
|
39
|
-
/** User-supplied state attached to the socket on upgrade. */
|
|
40
|
-
readonly data: Data;
|
|
41
|
-
/** Standard WHATWG ready-state (`0` connecting, `1` open, `2` closing, `3` closed). */
|
|
42
|
-
readonly readyState: number;
|
|
43
|
-
/** Remote IP, taken from `X-Forwarded-For` when present. */
|
|
44
|
-
readonly remoteAddress: string;
|
|
45
|
-
/**
|
|
46
|
-
* Send a message to this socket only.
|
|
47
|
-
*
|
|
48
|
-
* @param message - Payload to send
|
|
49
|
-
* @param compress - Whether to compress (honoured on Bun, ignored on Node)
|
|
50
|
-
* @returns Number of bytes written (best-effort on Node)
|
|
51
|
-
*/
|
|
52
|
-
send(message: WSMessage, compress?: boolean): number;
|
|
53
|
-
/**
|
|
54
|
-
* Close the connection.
|
|
55
|
-
*
|
|
56
|
-
* @param code - Close code (defaults to 1000)
|
|
57
|
-
* @param reason - Optional human-readable reason
|
|
58
|
-
*/
|
|
59
|
-
close(code?: number, reason?: string): void;
|
|
60
|
-
/**
|
|
61
|
-
* Subscribe this socket to a topic so it receives subsequent
|
|
62
|
-
* {@link ServerWebSocket.publish | publish} or
|
|
63
|
-
* {@link WebSocketServer.publish | server.publish} broadcasts.
|
|
64
|
-
*
|
|
65
|
-
* @param topic - Topic name
|
|
66
|
-
*/
|
|
67
|
-
subscribe(topic: string): void;
|
|
68
|
-
/**
|
|
69
|
-
* Unsubscribe this socket from a previously joined topic.
|
|
70
|
-
*
|
|
71
|
-
* @param topic - Topic name
|
|
72
|
-
*/
|
|
73
|
-
unsubscribe(topic: string): void;
|
|
74
|
-
/**
|
|
75
|
-
* Broadcast a message to every other socket subscribed to `topic`.
|
|
76
|
-
*
|
|
77
|
-
* @remarks
|
|
78
|
-
* The sender is excluded by default — matching Bun's default behaviour.
|
|
79
|
-
*
|
|
80
|
-
* @param topic - Topic name
|
|
81
|
-
* @param message - Payload to broadcast
|
|
82
|
-
* @param compress - Whether to compress (honoured on Bun, ignored on Node)
|
|
83
|
-
*/
|
|
84
|
-
publish(topic: string, message: WSMessage, compress?: boolean): void;
|
|
85
|
-
/**
|
|
86
|
-
* Check whether this socket is currently subscribed to `topic`.
|
|
87
|
-
*
|
|
88
|
-
* @param topic - Topic name
|
|
89
|
-
* @returns `true` when subscribed
|
|
90
|
-
*/
|
|
91
|
-
isSubscribed(topic: string): boolean;
|
|
92
|
-
/**
|
|
93
|
-
* Batch multiple writes inside `cb`.
|
|
94
|
-
*
|
|
95
|
-
* @remarks
|
|
96
|
-
* On Bun this corresponds to `corked()`; on Node it is a no-op alias
|
|
97
|
-
* that simply invokes `cb(this)` synchronously.
|
|
98
|
-
*
|
|
99
|
-
* @param cb - Function invoked with the same socket
|
|
100
|
-
*/
|
|
101
|
-
cork(cb: (ws: ServerWebSocket<Data>) => void): void;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Bun-style compression dictionary identifier.
|
|
106
|
-
*
|
|
107
|
-
* @remarks
|
|
108
|
-
* Used by Bun's `perMessageDeflate` configuration. The `@hedystia/ws`
|
|
109
|
-
* server forwards the value to the underlying implementation, which only
|
|
110
|
-
* Bun interprets natively; Node falls back to defaults when the value is
|
|
111
|
-
* not a recognised `ws` shape.
|
|
112
|
-
*/
|
|
113
|
-
export type Compressor =
|
|
114
|
-
| "disable"
|
|
115
|
-
| "shared"
|
|
116
|
-
| "dedicated"
|
|
117
|
-
| "3KB"
|
|
118
|
-
| "4KB"
|
|
119
|
-
| "8KB"
|
|
120
|
-
| "16KB"
|
|
121
|
-
| "32KB"
|
|
122
|
-
| "64KB"
|
|
123
|
-
| "128KB"
|
|
124
|
-
| "256KB";
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Per-message deflate configuration.
|
|
128
|
-
*
|
|
129
|
-
* @remarks
|
|
130
|
-
* Accepts either a boolean (`true` enables defaults, `false` disables it)
|
|
131
|
-
* or a free-form object whose shape is forwarded verbatim to the underlying
|
|
132
|
-
* implementation. Bun's {@link Compressor} strings (`"3KB"`, `"shared"`, …)
|
|
133
|
-
* and the [`ws`](https://github.com/websockets/ws) package's
|
|
134
|
-
* `PerMessageDeflateOptions` (`zlibDeflateOptions`, `threshold`, …) are
|
|
135
|
-
* both supported by simply matching whatever the runtime expects.
|
|
136
|
-
*/
|
|
137
|
-
export type PerMessageDeflate =
|
|
138
|
-
| boolean
|
|
139
|
-
| (Record<string, any> & {
|
|
140
|
-
compress?: boolean | Compressor;
|
|
141
|
-
decompress?: boolean | Compressor;
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Construction options for {@link WebSocketServer}.
|
|
146
|
-
*/
|
|
147
|
-
export interface WebSocketServerOptions {
|
|
148
|
-
/** Maximum allowed payload in bytes. Defaults to the underlying library's default. */
|
|
149
|
-
maxPayload?: number;
|
|
150
|
-
/** Per-message deflate configuration. */
|
|
151
|
-
perMessageDeflate?: PerMessageDeflate;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Lifecycle handlers passed to {@link WebSocketServer}.
|
|
156
|
-
*
|
|
157
|
-
* @typeParam Data - Shape of the user-attached `data` field
|
|
158
|
-
*/
|
|
159
|
-
export interface WebSocketHandlers<Data extends WSData = WSData> {
|
|
160
|
-
/** Called for every inbound message. */
|
|
161
|
-
message: (ws: ServerWebSocket<Data>, message: WSMessage) => void | Promise<void>;
|
|
162
|
-
/** Called once the handshake completes successfully. */
|
|
163
|
-
open?: (ws: ServerWebSocket<Data>) => void | Promise<void>;
|
|
164
|
-
/** Called after the connection closes (clean or otherwise). */
|
|
165
|
-
close?: (ws: ServerWebSocket<Data>, code: number, reason: string) => void | Promise<void>;
|
|
166
|
-
/** Called when the underlying transport raises an error. */
|
|
167
|
-
error?: (ws: ServerWebSocket<Data>, error: Error) => void | Promise<void>;
|
|
168
|
-
/**
|
|
169
|
-
* Called when back-pressure is relieved.
|
|
170
|
-
*
|
|
171
|
-
* @remarks
|
|
172
|
-
* Only fired by Bun; Node-backed servers never invoke it.
|
|
173
|
-
*/
|
|
174
|
-
drain?: (ws: ServerWebSocket<Data>) => void | Promise<void>;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Options accepted by {@link createWebSocket}.
|
|
179
|
-
*/
|
|
180
|
-
export interface ClientWebSocketOptions {
|
|
181
|
-
/** Sub-protocols negotiated during the handshake. */
|
|
182
|
-
protocols?: string | string[];
|
|
183
|
-
/**
|
|
184
|
-
* Custom request headers.
|
|
185
|
-
*
|
|
186
|
-
* @remarks
|
|
187
|
-
* Honoured on Node via the `ws` package; runtimes that ship a WHATWG
|
|
188
|
-
* `WebSocket` (Bun, Deno, browsers, Node ≥ 22) ignore them — matching
|
|
189
|
-
* standard WebSocket semantics.
|
|
190
|
-
*/
|
|
191
|
-
headers?: Record<string, string>;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Raw upgrade tuple consumed by {@link WebSocketServer.upgrade}.
|
|
196
|
-
*
|
|
197
|
-
* @remarks
|
|
198
|
-
* Mirrors what `node:http`'s `'upgrade'` event emits and what the `ws`
|
|
199
|
-
* package's `WebSocketServer.handleUpgrade` consumes.
|
|
200
|
-
*/
|
|
201
|
-
export interface UpgradeRequest {
|
|
202
|
-
/** Raw `IncomingMessage`-like object exposing `headers`, `method`, `url`. */
|
|
203
|
-
rawRequest: any;
|
|
204
|
-
/** Raw duplex socket (e.g. `node:net.Socket`). */
|
|
205
|
-
socket: any;
|
|
206
|
-
/** Initial buffer captured by the HTTP parser. */
|
|
207
|
-
head: Buffer | Uint8Array;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Options forwarded to {@link WebSocketServer.upgrade}.
|
|
212
|
-
*
|
|
213
|
-
* @typeParam Data - Shape of the user-attached `data` field
|
|
214
|
-
*/
|
|
215
|
-
export interface UpgradeOptions<Data extends WSData = WSData> {
|
|
216
|
-
/** Initial value of `ws.data` for the new connection. */
|
|
217
|
-
data?: Data;
|
|
218
|
-
/**
|
|
219
|
-
* Extra response headers.
|
|
220
|
-
*
|
|
221
|
-
* @remarks
|
|
222
|
-
* Forwarded to the underlying handshake when supported (Bun); ignored on
|
|
223
|
-
* Node-backed upgrades, which control headers via the `ws` package.
|
|
224
|
-
*/
|
|
225
|
-
headers?: Record<string, string> | Headers;
|
|
226
|
-
}
|
package/tsconfig.json
DELETED
package/tsdown.config.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "tsdown";
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
entry: ["src/index.ts", "src/client.ts", "src/server.ts"],
|
|
5
|
-
format: ["cjs", "esm"],
|
|
6
|
-
dts: true,
|
|
7
|
-
sourcemap: true,
|
|
8
|
-
treeshake: true,
|
|
9
|
-
clean: true,
|
|
10
|
-
unbundle: true,
|
|
11
|
-
outputOptions: { exports: "named" },
|
|
12
|
-
});
|