almostnode 0.1.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/LICENSE +21 -0
- package/README.md +731 -0
- package/dist/__sw__.js +394 -0
- package/dist/ai-chatbot-demo-entry.d.ts +6 -0
- package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
- package/dist/ai-chatbot-demo.d.ts +42 -0
- package/dist/ai-chatbot-demo.d.ts.map +1 -0
- package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
- package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
- package/dist/convex-app-demo-entry.d.ts +6 -0
- package/dist/convex-app-demo-entry.d.ts.map +1 -0
- package/dist/convex-app-demo.d.ts +68 -0
- package/dist/convex-app-demo.d.ts.map +1 -0
- package/dist/cors-proxy.d.ts +46 -0
- package/dist/cors-proxy.d.ts.map +1 -0
- package/dist/create-runtime.d.ts +42 -0
- package/dist/create-runtime.d.ts.map +1 -0
- package/dist/demo.d.ts +6 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/dev-server.d.ts +97 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/frameworks/next-dev-server.d.ts +202 -0
- package/dist/frameworks/next-dev-server.d.ts.map +1 -0
- package/dist/frameworks/vite-dev-server.d.ts +85 -0
- package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
- package/dist/index.cjs +14965 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +14867 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next-demo.d.ts +49 -0
- package/dist/next-demo.d.ts.map +1 -0
- package/dist/npm/index.d.ts +71 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/registry.d.ts +66 -0
- package/dist/npm/registry.d.ts.map +1 -0
- package/dist/npm/resolver.d.ts +52 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/tarball.d.ts +29 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/runtime-interface.d.ts +90 -0
- package/dist/runtime-interface.d.ts.map +1 -0
- package/dist/runtime.d.ts +103 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/sandbox-helpers.d.ts +43 -0
- package/dist/sandbox-helpers.d.ts.map +1 -0
- package/dist/sandbox-runtime.d.ts +65 -0
- package/dist/sandbox-runtime.d.ts.map +1 -0
- package/dist/server-bridge.d.ts +89 -0
- package/dist/server-bridge.d.ts.map +1 -0
- package/dist/shims/assert.d.ts +51 -0
- package/dist/shims/assert.d.ts.map +1 -0
- package/dist/shims/async_hooks.d.ts +37 -0
- package/dist/shims/async_hooks.d.ts.map +1 -0
- package/dist/shims/buffer.d.ts +20 -0
- package/dist/shims/buffer.d.ts.map +1 -0
- package/dist/shims/child_process-browser.d.ts +92 -0
- package/dist/shims/child_process-browser.d.ts.map +1 -0
- package/dist/shims/child_process.d.ts +93 -0
- package/dist/shims/child_process.d.ts.map +1 -0
- package/dist/shims/chokidar.d.ts +55 -0
- package/dist/shims/chokidar.d.ts.map +1 -0
- package/dist/shims/cluster.d.ts +52 -0
- package/dist/shims/cluster.d.ts.map +1 -0
- package/dist/shims/crypto.d.ts +122 -0
- package/dist/shims/crypto.d.ts.map +1 -0
- package/dist/shims/dgram.d.ts +34 -0
- package/dist/shims/dgram.d.ts.map +1 -0
- package/dist/shims/diagnostics_channel.d.ts +80 -0
- package/dist/shims/diagnostics_channel.d.ts.map +1 -0
- package/dist/shims/dns.d.ts +87 -0
- package/dist/shims/dns.d.ts.map +1 -0
- package/dist/shims/domain.d.ts +25 -0
- package/dist/shims/domain.d.ts.map +1 -0
- package/dist/shims/esbuild.d.ts +105 -0
- package/dist/shims/esbuild.d.ts.map +1 -0
- package/dist/shims/events.d.ts +37 -0
- package/dist/shims/events.d.ts.map +1 -0
- package/dist/shims/fs.d.ts +115 -0
- package/dist/shims/fs.d.ts.map +1 -0
- package/dist/shims/fsevents.d.ts +67 -0
- package/dist/shims/fsevents.d.ts.map +1 -0
- package/dist/shims/http.d.ts +217 -0
- package/dist/shims/http.d.ts.map +1 -0
- package/dist/shims/http2.d.ts +81 -0
- package/dist/shims/http2.d.ts.map +1 -0
- package/dist/shims/https.d.ts +36 -0
- package/dist/shims/https.d.ts.map +1 -0
- package/dist/shims/inspector.d.ts +25 -0
- package/dist/shims/inspector.d.ts.map +1 -0
- package/dist/shims/module.d.ts +22 -0
- package/dist/shims/module.d.ts.map +1 -0
- package/dist/shims/net.d.ts +100 -0
- package/dist/shims/net.d.ts.map +1 -0
- package/dist/shims/os.d.ts +159 -0
- package/dist/shims/os.d.ts.map +1 -0
- package/dist/shims/path.d.ts +72 -0
- package/dist/shims/path.d.ts.map +1 -0
- package/dist/shims/perf_hooks.d.ts +50 -0
- package/dist/shims/perf_hooks.d.ts.map +1 -0
- package/dist/shims/process.d.ts +93 -0
- package/dist/shims/process.d.ts.map +1 -0
- package/dist/shims/querystring.d.ts +23 -0
- package/dist/shims/querystring.d.ts.map +1 -0
- package/dist/shims/readdirp.d.ts +52 -0
- package/dist/shims/readdirp.d.ts.map +1 -0
- package/dist/shims/readline.d.ts +62 -0
- package/dist/shims/readline.d.ts.map +1 -0
- package/dist/shims/rollup.d.ts +34 -0
- package/dist/shims/rollup.d.ts.map +1 -0
- package/dist/shims/sentry.d.ts +163 -0
- package/dist/shims/sentry.d.ts.map +1 -0
- package/dist/shims/stream.d.ts +181 -0
- package/dist/shims/stream.d.ts.map +1 -0
- package/dist/shims/tls.d.ts +53 -0
- package/dist/shims/tls.d.ts.map +1 -0
- package/dist/shims/tty.d.ts +30 -0
- package/dist/shims/tty.d.ts.map +1 -0
- package/dist/shims/url.d.ts +64 -0
- package/dist/shims/url.d.ts.map +1 -0
- package/dist/shims/util.d.ts +106 -0
- package/dist/shims/util.d.ts.map +1 -0
- package/dist/shims/v8.d.ts +73 -0
- package/dist/shims/v8.d.ts.map +1 -0
- package/dist/shims/vfs-adapter.d.ts +126 -0
- package/dist/shims/vfs-adapter.d.ts.map +1 -0
- package/dist/shims/vm.d.ts +45 -0
- package/dist/shims/vm.d.ts.map +1 -0
- package/dist/shims/worker_threads.d.ts +66 -0
- package/dist/shims/worker_threads.d.ts.map +1 -0
- package/dist/shims/ws.d.ts +66 -0
- package/dist/shims/ws.d.ts.map +1 -0
- package/dist/shims/zlib.d.ts +161 -0
- package/dist/shims/zlib.d.ts.map +1 -0
- package/dist/transform.d.ts +24 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/virtual-fs.d.ts +226 -0
- package/dist/virtual-fs.d.ts.map +1 -0
- package/dist/vite-demo.d.ts +35 -0
- package/dist/vite-demo.d.ts.map +1 -0
- package/dist/vite-sw.js +132 -0
- package/dist/worker/runtime-worker.d.ts +8 -0
- package/dist/worker/runtime-worker.d.ts.map +1 -0
- package/dist/worker-runtime.d.ts +50 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/package.json +85 -0
- package/src/ai-chatbot-demo-entry.ts +244 -0
- package/src/ai-chatbot-demo.ts +509 -0
- package/src/convex-app-demo-entry.ts +1107 -0
- package/src/convex-app-demo.ts +1316 -0
- package/src/cors-proxy.ts +81 -0
- package/src/create-runtime.ts +147 -0
- package/src/demo.ts +304 -0
- package/src/dev-server.ts +274 -0
- package/src/frameworks/next-dev-server.ts +2224 -0
- package/src/frameworks/vite-dev-server.ts +702 -0
- package/src/index.ts +101 -0
- package/src/next-demo.ts +1784 -0
- package/src/npm/index.ts +347 -0
- package/src/npm/registry.ts +152 -0
- package/src/npm/resolver.ts +385 -0
- package/src/npm/tarball.ts +209 -0
- package/src/runtime-interface.ts +103 -0
- package/src/runtime.ts +1046 -0
- package/src/sandbox-helpers.ts +173 -0
- package/src/sandbox-runtime.ts +252 -0
- package/src/server-bridge.ts +426 -0
- package/src/shims/assert.ts +664 -0
- package/src/shims/async_hooks.ts +86 -0
- package/src/shims/buffer.ts +75 -0
- package/src/shims/child_process-browser.ts +217 -0
- package/src/shims/child_process.ts +463 -0
- package/src/shims/chokidar.ts +313 -0
- package/src/shims/cluster.ts +67 -0
- package/src/shims/crypto.ts +830 -0
- package/src/shims/dgram.ts +47 -0
- package/src/shims/diagnostics_channel.ts +196 -0
- package/src/shims/dns.ts +172 -0
- package/src/shims/domain.ts +58 -0
- package/src/shims/esbuild.ts +805 -0
- package/src/shims/events.ts +195 -0
- package/src/shims/fs.ts +803 -0
- package/src/shims/fsevents.ts +63 -0
- package/src/shims/http.ts +904 -0
- package/src/shims/http2.ts +96 -0
- package/src/shims/https.ts +86 -0
- package/src/shims/inspector.ts +30 -0
- package/src/shims/module.ts +82 -0
- package/src/shims/net.ts +359 -0
- package/src/shims/os.ts +195 -0
- package/src/shims/path.ts +199 -0
- package/src/shims/perf_hooks.ts +92 -0
- package/src/shims/process.ts +346 -0
- package/src/shims/querystring.ts +97 -0
- package/src/shims/readdirp.ts +228 -0
- package/src/shims/readline.ts +110 -0
- package/src/shims/rollup.ts +80 -0
- package/src/shims/sentry.ts +133 -0
- package/src/shims/stream.ts +1126 -0
- package/src/shims/tls.ts +95 -0
- package/src/shims/tty.ts +64 -0
- package/src/shims/url.ts +171 -0
- package/src/shims/util.ts +312 -0
- package/src/shims/v8.ts +113 -0
- package/src/shims/vfs-adapter.ts +402 -0
- package/src/shims/vm.ts +83 -0
- package/src/shims/worker_threads.ts +111 -0
- package/src/shims/ws.ts +382 -0
- package/src/shims/zlib.ts +289 -0
- package/src/transform.ts +313 -0
- package/src/types/external.d.ts +67 -0
- package/src/virtual-fs.ts +903 -0
- package/src/vite-demo.ts +577 -0
- package/src/worker/runtime-worker.ts +128 -0
- package/src/worker-runtime.ts +145 -0
package/src/shims/ws.ts
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ws (WebSocket) shim for browser environment
|
|
3
|
+
* Used by Vite for HMR (Hot Module Replacement)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from './events';
|
|
7
|
+
|
|
8
|
+
// Polyfill for CloseEvent (not available in Node.js)
|
|
9
|
+
const CloseEventPolyfill = typeof CloseEvent !== 'undefined' ? CloseEvent : class CloseEvent extends Event {
|
|
10
|
+
code: number;
|
|
11
|
+
reason: string;
|
|
12
|
+
wasClean: boolean;
|
|
13
|
+
constructor(type: string, init?: { code?: number; reason?: string; wasClean?: boolean }) {
|
|
14
|
+
super(type);
|
|
15
|
+
this.code = init?.code ?? 1000;
|
|
16
|
+
this.reason = init?.reason ?? '';
|
|
17
|
+
this.wasClean = init?.wasClean ?? true;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Polyfill for MessageEvent (not available in Node.js)
|
|
22
|
+
const MessageEventPolyfill = typeof MessageEvent !== 'undefined' ? MessageEvent : class MessageEvent extends Event {
|
|
23
|
+
data: unknown;
|
|
24
|
+
constructor(type: string, init?: { data?: unknown }) {
|
|
25
|
+
super(type);
|
|
26
|
+
this.data = init?.data;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Message channel for communication between WebSocket server and clients
|
|
31
|
+
let messageChannel: BroadcastChannel | null = null;
|
|
32
|
+
try {
|
|
33
|
+
messageChannel = new BroadcastChannel('vite-ws-channel');
|
|
34
|
+
} catch {
|
|
35
|
+
// BroadcastChannel not available in some environments
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Track all server instances
|
|
39
|
+
const servers = new Map<string, WebSocketServer>();
|
|
40
|
+
let clientIdCounter = 0;
|
|
41
|
+
|
|
42
|
+
export class WebSocket extends EventEmitter {
|
|
43
|
+
static readonly CONNECTING = 0;
|
|
44
|
+
static readonly OPEN = 1;
|
|
45
|
+
static readonly CLOSING = 2;
|
|
46
|
+
static readonly CLOSED = 3;
|
|
47
|
+
|
|
48
|
+
readonly CONNECTING = WebSocket.CONNECTING;
|
|
49
|
+
readonly OPEN = WebSocket.OPEN;
|
|
50
|
+
readonly CLOSING = WebSocket.CLOSING;
|
|
51
|
+
readonly CLOSED = WebSocket.CLOSED;
|
|
52
|
+
|
|
53
|
+
readyState: number = WebSocket.CONNECTING;
|
|
54
|
+
url: string;
|
|
55
|
+
protocol: string = '';
|
|
56
|
+
extensions: string = '';
|
|
57
|
+
bufferedAmount: number = 0;
|
|
58
|
+
binaryType: 'blob' | 'arraybuffer' = 'blob';
|
|
59
|
+
|
|
60
|
+
private _id: string;
|
|
61
|
+
private _server: WebSocketServer | null = null;
|
|
62
|
+
|
|
63
|
+
// Event handler properties
|
|
64
|
+
onopen: ((event: Event) => void) | null = null;
|
|
65
|
+
onclose: ((event: CloseEvent) => void) | null = null;
|
|
66
|
+
onerror: ((event: Event) => void) | null = null;
|
|
67
|
+
onmessage: ((event: MessageEvent) => void) | null = null;
|
|
68
|
+
|
|
69
|
+
constructor(url: string, protocols?: string | string[]) {
|
|
70
|
+
super();
|
|
71
|
+
this.url = url;
|
|
72
|
+
this._id = `client-${++clientIdCounter}`;
|
|
73
|
+
|
|
74
|
+
if (protocols) {
|
|
75
|
+
this.protocol = Array.isArray(protocols) ? protocols[0] : protocols;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Connect asynchronously
|
|
79
|
+
setTimeout(() => this._connect(), 0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private _connect(): void {
|
|
83
|
+
// For internal WebSocket connections (from server to client), connect immediately
|
|
84
|
+
if (this.url.startsWith('internal://')) {
|
|
85
|
+
this.readyState = WebSocket.OPEN;
|
|
86
|
+
this.emit('open');
|
|
87
|
+
if (this.onopen) this.onopen(new Event('open'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// If no BroadcastChannel, act as if connected
|
|
92
|
+
if (!messageChannel) {
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
this.readyState = WebSocket.OPEN;
|
|
95
|
+
this.emit('open');
|
|
96
|
+
if (this.onopen) this.onopen(new Event('open'));
|
|
97
|
+
}, 0);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Try to connect to a server via BroadcastChannel
|
|
102
|
+
messageChannel.postMessage({
|
|
103
|
+
type: 'connect',
|
|
104
|
+
clientId: this._id,
|
|
105
|
+
url: this.url,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Listen for responses
|
|
109
|
+
const channel = messageChannel;
|
|
110
|
+
const handler = (event: MessageEvent) => {
|
|
111
|
+
const data = event.data;
|
|
112
|
+
|
|
113
|
+
if (data.targetClient !== this._id) return;
|
|
114
|
+
|
|
115
|
+
switch (data.type) {
|
|
116
|
+
case 'connected':
|
|
117
|
+
this.readyState = WebSocket.OPEN;
|
|
118
|
+
this.emit('open');
|
|
119
|
+
if (this.onopen) this.onopen(new Event('open'));
|
|
120
|
+
break;
|
|
121
|
+
|
|
122
|
+
case 'message':
|
|
123
|
+
const msgEvent = new MessageEventPolyfill('message', { data: data.payload });
|
|
124
|
+
this.emit('message', msgEvent);
|
|
125
|
+
if (this.onmessage) this.onmessage(msgEvent as unknown as MessageEvent);
|
|
126
|
+
break;
|
|
127
|
+
|
|
128
|
+
case 'close':
|
|
129
|
+
this.readyState = WebSocket.CLOSED;
|
|
130
|
+
const closeEvent = new CloseEventPolyfill('close', {
|
|
131
|
+
code: data.code || 1000,
|
|
132
|
+
reason: data.reason || '',
|
|
133
|
+
wasClean: true,
|
|
134
|
+
});
|
|
135
|
+
this.emit('close', closeEvent);
|
|
136
|
+
if (this.onclose) this.onclose(closeEvent as unknown as CloseEvent);
|
|
137
|
+
channel.removeEventListener('message', handler);
|
|
138
|
+
break;
|
|
139
|
+
|
|
140
|
+
case 'error':
|
|
141
|
+
const errorEvent = new Event('error');
|
|
142
|
+
this.emit('error', errorEvent);
|
|
143
|
+
if (this.onerror) this.onerror(errorEvent);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
channel.addEventListener('message', handler);
|
|
149
|
+
|
|
150
|
+
// Connection timeout
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
if (this.readyState === WebSocket.CONNECTING) {
|
|
153
|
+
// No server responded, act as if connected (for standalone client use)
|
|
154
|
+
this.readyState = WebSocket.OPEN;
|
|
155
|
+
this.emit('open');
|
|
156
|
+
if (this.onopen) this.onopen(new Event('open'));
|
|
157
|
+
}
|
|
158
|
+
}, 100);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
send(data: string | ArrayBuffer | Uint8Array): void {
|
|
162
|
+
if (this.readyState !== WebSocket.OPEN) {
|
|
163
|
+
throw new Error('WebSocket is not open');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// If connected to internal server
|
|
167
|
+
if (this._server) {
|
|
168
|
+
this._server._handleClientMessage(this, data);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Send via BroadcastChannel
|
|
173
|
+
if (messageChannel) {
|
|
174
|
+
messageChannel.postMessage({
|
|
175
|
+
type: 'message',
|
|
176
|
+
clientId: this._id,
|
|
177
|
+
url: this.url,
|
|
178
|
+
payload: data,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
close(code?: number, reason?: string): void {
|
|
184
|
+
if (this.readyState === WebSocket.CLOSED || this.readyState === WebSocket.CLOSING) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this.readyState = WebSocket.CLOSING;
|
|
189
|
+
|
|
190
|
+
if (messageChannel) {
|
|
191
|
+
messageChannel.postMessage({
|
|
192
|
+
type: 'disconnect',
|
|
193
|
+
clientId: this._id,
|
|
194
|
+
url: this.url,
|
|
195
|
+
code,
|
|
196
|
+
reason,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
this.readyState = WebSocket.CLOSED;
|
|
202
|
+
const closeEvent = new CloseEventPolyfill('close', {
|
|
203
|
+
code: code || 1000,
|
|
204
|
+
reason: reason || '',
|
|
205
|
+
wasClean: true,
|
|
206
|
+
});
|
|
207
|
+
this.emit('close', closeEvent);
|
|
208
|
+
if (this.onclose) this.onclose(closeEvent as unknown as CloseEvent);
|
|
209
|
+
}, 0);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
ping(): void {
|
|
213
|
+
// No-op in browser
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
pong(): void {
|
|
217
|
+
// No-op in browser
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
terminate(): void {
|
|
221
|
+
this.close(1006, 'Connection terminated');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// For internal server use
|
|
225
|
+
_setServer(server: WebSocketServer): void {
|
|
226
|
+
this._server = server;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
_receiveMessage(data: unknown): void {
|
|
230
|
+
const msgEvent = new MessageEventPolyfill('message', { data });
|
|
231
|
+
this.emit('message', msgEvent);
|
|
232
|
+
if (this.onmessage) this.onmessage(msgEvent as unknown as MessageEvent);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface ServerOptions {
|
|
237
|
+
host?: string;
|
|
238
|
+
port?: number;
|
|
239
|
+
server?: unknown; // HTTP server
|
|
240
|
+
noServer?: boolean;
|
|
241
|
+
path?: string;
|
|
242
|
+
clientTracking?: boolean;
|
|
243
|
+
perMessageDeflate?: boolean | object;
|
|
244
|
+
maxPayload?: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export class WebSocketServer extends EventEmitter {
|
|
248
|
+
clients: Set<WebSocket> = new Set();
|
|
249
|
+
options: ServerOptions;
|
|
250
|
+
private _path: string;
|
|
251
|
+
private _channelHandler: ((event: MessageEvent) => void) | null = null;
|
|
252
|
+
|
|
253
|
+
constructor(options: ServerOptions = {}) {
|
|
254
|
+
super();
|
|
255
|
+
this.options = options;
|
|
256
|
+
this._path = options.path || '/';
|
|
257
|
+
|
|
258
|
+
// If not noServer, set up listening
|
|
259
|
+
if (!options.noServer) {
|
|
260
|
+
this._setupListener();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Register server
|
|
264
|
+
servers.set(this._path, this);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private _setupListener(): void {
|
|
268
|
+
if (!messageChannel) return;
|
|
269
|
+
|
|
270
|
+
const channel = messageChannel;
|
|
271
|
+
this._channelHandler = (event: MessageEvent) => {
|
|
272
|
+
const data = event.data;
|
|
273
|
+
|
|
274
|
+
if (data.type === 'connect') {
|
|
275
|
+
// Create a new WebSocket for this client
|
|
276
|
+
const ws = new WebSocket('internal://' + this._path);
|
|
277
|
+
ws._setServer(this);
|
|
278
|
+
(ws as unknown as { _clientId: string })._clientId = data.clientId;
|
|
279
|
+
this.clients.add(ws);
|
|
280
|
+
|
|
281
|
+
// Notify client of connection
|
|
282
|
+
channel.postMessage({
|
|
283
|
+
type: 'connected',
|
|
284
|
+
targetClient: data.clientId,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Emit connection event
|
|
288
|
+
this.emit('connection', ws, { url: data.url });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (data.type === 'message') {
|
|
292
|
+
// Find the client and deliver the message
|
|
293
|
+
for (const client of this.clients) {
|
|
294
|
+
if ((client as unknown as { _clientId: string })._clientId === data.clientId) {
|
|
295
|
+
client._receiveMessage(data.payload);
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (data.type === 'disconnect') {
|
|
302
|
+
for (const client of this.clients) {
|
|
303
|
+
if ((client as unknown as { _clientId: string })._clientId === data.clientId) {
|
|
304
|
+
client.close(data.code, data.reason);
|
|
305
|
+
this.clients.delete(client);
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
channel.addEventListener('message', this._channelHandler);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
_handleClientMessage(client: WebSocket, data: unknown): void {
|
|
316
|
+
// Broadcast to server-side handlers
|
|
317
|
+
const msgEvent = new MessageEventPolyfill('message', { data });
|
|
318
|
+
client.emit('message', msgEvent);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
handleUpgrade(
|
|
322
|
+
request: unknown,
|
|
323
|
+
socket: unknown,
|
|
324
|
+
head: unknown,
|
|
325
|
+
callback: (ws: WebSocket, request: unknown) => void
|
|
326
|
+
): void {
|
|
327
|
+
// Create WebSocket for this upgrade
|
|
328
|
+
const ws = new WebSocket('internal://' + this._path);
|
|
329
|
+
ws._setServer(this);
|
|
330
|
+
|
|
331
|
+
if (this.options.clientTracking !== false) {
|
|
332
|
+
this.clients.add(ws);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Async callback
|
|
336
|
+
setTimeout(() => {
|
|
337
|
+
callback(ws, request);
|
|
338
|
+
this.emit('connection', ws, request);
|
|
339
|
+
}, 0);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
close(callback?: () => void): void {
|
|
343
|
+
// Close all clients
|
|
344
|
+
for (const client of this.clients) {
|
|
345
|
+
client.close(1001, 'Server shutting down');
|
|
346
|
+
}
|
|
347
|
+
this.clients.clear();
|
|
348
|
+
|
|
349
|
+
// Remove from registry
|
|
350
|
+
servers.delete(this._path);
|
|
351
|
+
|
|
352
|
+
// Remove channel listener
|
|
353
|
+
if (this._channelHandler && messageChannel) {
|
|
354
|
+
messageChannel.removeEventListener('message', this._channelHandler);
|
|
355
|
+
this._channelHandler = null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
this.emit('close');
|
|
359
|
+
|
|
360
|
+
if (callback) {
|
|
361
|
+
setTimeout(callback, 0);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
address(): { port: number; family: string; address: string } | null {
|
|
366
|
+
return {
|
|
367
|
+
port: this.options.port || 0,
|
|
368
|
+
family: 'IPv4',
|
|
369
|
+
address: this.options.host || '0.0.0.0',
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Export WebSocket and Server
|
|
376
|
+
export default WebSocket;
|
|
377
|
+
export const Server = WebSocketServer;
|
|
378
|
+
|
|
379
|
+
// Additional exports for compatibility
|
|
380
|
+
export const createWebSocketStream = () => {
|
|
381
|
+
throw new Error('createWebSocketStream is not supported in browser');
|
|
382
|
+
};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js zlib module shim
|
|
3
|
+
* Provides basic compression utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Buffer } from './stream';
|
|
7
|
+
import pako from 'pako';
|
|
8
|
+
|
|
9
|
+
// Brotli WASM instance - loaded lazily
|
|
10
|
+
type BrotliModule = { compress: (data: Uint8Array) => Uint8Array; decompress: (data: Uint8Array) => Uint8Array };
|
|
11
|
+
let brotliModule: BrotliModule | null = null;
|
|
12
|
+
let brotliLoadPromise: Promise<BrotliModule | null> | null = null;
|
|
13
|
+
|
|
14
|
+
async function loadBrotli(): Promise<BrotliModule | null> {
|
|
15
|
+
if (brotliModule) return brotliModule;
|
|
16
|
+
if (!brotliLoadPromise) {
|
|
17
|
+
brotliLoadPromise = (async () => {
|
|
18
|
+
try {
|
|
19
|
+
// Dynamic import - brotli-wasm handles environment detection automatically
|
|
20
|
+
// In Node.js: returns sync module
|
|
21
|
+
// In browser: returns promise that resolves after WASM init
|
|
22
|
+
const brotliWasmModule = await import('brotli-wasm');
|
|
23
|
+
// The default export is a promise that resolves to the module
|
|
24
|
+
brotliModule = await brotliWasmModule.default;
|
|
25
|
+
console.log('[zlib] brotli-wasm loaded successfully');
|
|
26
|
+
return brotliModule;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error('[zlib] Failed to load brotli-wasm:', error);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
})();
|
|
32
|
+
}
|
|
33
|
+
return brotliLoadPromise;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function gzip(
|
|
37
|
+
buffer: Buffer | string,
|
|
38
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
39
|
+
): void {
|
|
40
|
+
try {
|
|
41
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
42
|
+
const result = pako.gzip(input);
|
|
43
|
+
callback(null, Buffer.from(result));
|
|
44
|
+
} catch (error) {
|
|
45
|
+
callback(error as Error, Buffer.alloc(0));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function gunzip(
|
|
50
|
+
buffer: Buffer,
|
|
51
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
52
|
+
): void {
|
|
53
|
+
try {
|
|
54
|
+
const result = pako.ungzip(buffer);
|
|
55
|
+
callback(null, Buffer.from(result));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
callback(error as Error, Buffer.alloc(0));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function deflate(
|
|
62
|
+
buffer: Buffer | string,
|
|
63
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
64
|
+
): void {
|
|
65
|
+
try {
|
|
66
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
67
|
+
const result = pako.deflate(input);
|
|
68
|
+
callback(null, Buffer.from(result));
|
|
69
|
+
} catch (error) {
|
|
70
|
+
callback(error as Error, Buffer.alloc(0));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function inflate(
|
|
75
|
+
buffer: Buffer,
|
|
76
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
77
|
+
): void {
|
|
78
|
+
try {
|
|
79
|
+
const result = pako.inflate(buffer);
|
|
80
|
+
callback(null, Buffer.from(result));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
callback(error as Error, Buffer.alloc(0));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function deflateRaw(
|
|
87
|
+
buffer: Buffer | string,
|
|
88
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
89
|
+
): void {
|
|
90
|
+
try {
|
|
91
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
92
|
+
const result = pako.deflateRaw(input);
|
|
93
|
+
callback(null, Buffer.from(result));
|
|
94
|
+
} catch (error) {
|
|
95
|
+
callback(error as Error, Buffer.alloc(0));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function inflateRaw(
|
|
100
|
+
buffer: Buffer,
|
|
101
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
102
|
+
): void {
|
|
103
|
+
try {
|
|
104
|
+
const result = pako.inflateRaw(buffer);
|
|
105
|
+
callback(null, Buffer.from(result));
|
|
106
|
+
} catch (error) {
|
|
107
|
+
callback(error as Error, Buffer.alloc(0));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Brotli compression using brotli-wasm
|
|
112
|
+
export function brotliCompress(
|
|
113
|
+
buffer: Buffer | string,
|
|
114
|
+
options: unknown,
|
|
115
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
116
|
+
): void {
|
|
117
|
+
// Handle overload where options is the callback
|
|
118
|
+
if (typeof options === 'function') {
|
|
119
|
+
callback = options as (error: Error | null, result: Buffer) => void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
loadBrotli().then(brotli => {
|
|
123
|
+
if (!brotli) {
|
|
124
|
+
callback(new Error('Brotli WASM failed to load'), Buffer.alloc(0));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
129
|
+
const result = brotli.compress(new Uint8Array(input));
|
|
130
|
+
callback(null, Buffer.from(result));
|
|
131
|
+
} catch (error) {
|
|
132
|
+
callback(error as Error, Buffer.alloc(0));
|
|
133
|
+
}
|
|
134
|
+
}).catch(error => {
|
|
135
|
+
callback(error as Error, Buffer.alloc(0));
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function brotliDecompress(
|
|
140
|
+
buffer: Buffer,
|
|
141
|
+
options: unknown,
|
|
142
|
+
callback: (error: Error | null, result: Buffer) => void
|
|
143
|
+
): void {
|
|
144
|
+
// Handle overload where options is the callback
|
|
145
|
+
if (typeof options === 'function') {
|
|
146
|
+
callback = options as (error: Error | null, result: Buffer) => void;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
loadBrotli().then(brotli => {
|
|
150
|
+
if (!brotli) {
|
|
151
|
+
callback(new Error('Brotli WASM failed to load'), Buffer.alloc(0));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const result = brotli.decompress(new Uint8Array(buffer));
|
|
156
|
+
callback(null, Buffer.from(result));
|
|
157
|
+
} catch (error) {
|
|
158
|
+
callback(error as Error, Buffer.alloc(0));
|
|
159
|
+
}
|
|
160
|
+
}).catch(error => {
|
|
161
|
+
callback(error as Error, Buffer.alloc(0));
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function brotliCompressSync(buffer: Buffer | string, _options?: unknown): Buffer {
|
|
166
|
+
if (!brotliModule) {
|
|
167
|
+
throw new Error('Brotli WASM not loaded. Call brotliCompress first to initialize.');
|
|
168
|
+
}
|
|
169
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
170
|
+
return Buffer.from(brotliModule.compress(new Uint8Array(input)));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function brotliDecompressSync(buffer: Buffer, _options?: unknown): Buffer {
|
|
174
|
+
if (!brotliModule) {
|
|
175
|
+
throw new Error('Brotli WASM not loaded. Call brotliDecompress first to initialize.');
|
|
176
|
+
}
|
|
177
|
+
return Buffer.from(brotliModule.decompress(new Uint8Array(buffer)));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Sync versions
|
|
181
|
+
export function gzipSync(buffer: Buffer | string): Buffer {
|
|
182
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
183
|
+
return Buffer.from(pako.gzip(input));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function gunzipSync(buffer: Buffer): Buffer {
|
|
187
|
+
return Buffer.from(pako.ungzip(buffer));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function deflateSync(buffer: Buffer | string): Buffer {
|
|
191
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
192
|
+
return Buffer.from(pako.deflate(input));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function inflateSync(buffer: Buffer): Buffer {
|
|
196
|
+
return Buffer.from(pako.inflate(buffer));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function deflateRawSync(buffer: Buffer | string): Buffer {
|
|
200
|
+
const input = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
201
|
+
return Buffer.from(pako.deflateRaw(input));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function inflateRawSync(buffer: Buffer): Buffer {
|
|
205
|
+
return Buffer.from(pako.inflateRaw(buffer));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Constants
|
|
209
|
+
export const constants = {
|
|
210
|
+
Z_NO_FLUSH: 0,
|
|
211
|
+
Z_PARTIAL_FLUSH: 1,
|
|
212
|
+
Z_SYNC_FLUSH: 2,
|
|
213
|
+
Z_FULL_FLUSH: 3,
|
|
214
|
+
Z_FINISH: 4,
|
|
215
|
+
Z_BLOCK: 5,
|
|
216
|
+
Z_OK: 0,
|
|
217
|
+
Z_STREAM_END: 1,
|
|
218
|
+
Z_NEED_DICT: 2,
|
|
219
|
+
Z_ERRNO: -1,
|
|
220
|
+
Z_STREAM_ERROR: -2,
|
|
221
|
+
Z_DATA_ERROR: -3,
|
|
222
|
+
Z_MEM_ERROR: -4,
|
|
223
|
+
Z_BUF_ERROR: -5,
|
|
224
|
+
Z_VERSION_ERROR: -6,
|
|
225
|
+
Z_NO_COMPRESSION: 0,
|
|
226
|
+
Z_BEST_SPEED: 1,
|
|
227
|
+
Z_BEST_COMPRESSION: 9,
|
|
228
|
+
Z_DEFAULT_COMPRESSION: -1,
|
|
229
|
+
Z_FILTERED: 1,
|
|
230
|
+
Z_HUFFMAN_ONLY: 2,
|
|
231
|
+
Z_RLE: 3,
|
|
232
|
+
Z_FIXED: 4,
|
|
233
|
+
Z_DEFAULT_STRATEGY: 0,
|
|
234
|
+
ZLIB_VERNUM: 4784,
|
|
235
|
+
Z_MIN_WINDOWBITS: 8,
|
|
236
|
+
Z_MAX_WINDOWBITS: 15,
|
|
237
|
+
Z_DEFAULT_WINDOWBITS: 15,
|
|
238
|
+
Z_MIN_CHUNK: 64,
|
|
239
|
+
Z_MAX_CHUNK: Infinity,
|
|
240
|
+
Z_DEFAULT_CHUNK: 16384,
|
|
241
|
+
Z_MIN_MEMLEVEL: 1,
|
|
242
|
+
Z_MAX_MEMLEVEL: 9,
|
|
243
|
+
Z_DEFAULT_MEMLEVEL: 8,
|
|
244
|
+
Z_MIN_LEVEL: -1,
|
|
245
|
+
Z_MAX_LEVEL: 9,
|
|
246
|
+
Z_DEFAULT_LEVEL: -1,
|
|
247
|
+
// Brotli constants
|
|
248
|
+
BROTLI_DECODE: 0,
|
|
249
|
+
BROTLI_ENCODE: 1,
|
|
250
|
+
BROTLI_OPERATION_PROCESS: 0,
|
|
251
|
+
BROTLI_OPERATION_FLUSH: 1,
|
|
252
|
+
BROTLI_OPERATION_FINISH: 2,
|
|
253
|
+
BROTLI_OPERATION_EMIT_METADATA: 3,
|
|
254
|
+
BROTLI_PARAM_MODE: 0,
|
|
255
|
+
BROTLI_MODE_GENERIC: 0,
|
|
256
|
+
BROTLI_MODE_TEXT: 1,
|
|
257
|
+
BROTLI_MODE_FONT: 2,
|
|
258
|
+
BROTLI_PARAM_QUALITY: 1,
|
|
259
|
+
BROTLI_MIN_QUALITY: 0,
|
|
260
|
+
BROTLI_MAX_QUALITY: 11,
|
|
261
|
+
BROTLI_DEFAULT_QUALITY: 11,
|
|
262
|
+
BROTLI_PARAM_LGWIN: 2,
|
|
263
|
+
BROTLI_MIN_WINDOW_BITS: 10,
|
|
264
|
+
BROTLI_MAX_WINDOW_BITS: 24,
|
|
265
|
+
BROTLI_DEFAULT_WINDOW: 22,
|
|
266
|
+
BROTLI_PARAM_LGBLOCK: 3,
|
|
267
|
+
BROTLI_MIN_INPUT_BLOCK_BITS: 16,
|
|
268
|
+
BROTLI_MAX_INPUT_BLOCK_BITS: 24,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
export default {
|
|
272
|
+
gzip,
|
|
273
|
+
gunzip,
|
|
274
|
+
deflate,
|
|
275
|
+
inflate,
|
|
276
|
+
deflateRaw,
|
|
277
|
+
inflateRaw,
|
|
278
|
+
gzipSync,
|
|
279
|
+
gunzipSync,
|
|
280
|
+
deflateSync,
|
|
281
|
+
inflateSync,
|
|
282
|
+
deflateRawSync,
|
|
283
|
+
inflateRawSync,
|
|
284
|
+
brotliCompress,
|
|
285
|
+
brotliDecompress,
|
|
286
|
+
brotliCompressSync,
|
|
287
|
+
brotliDecompressSync,
|
|
288
|
+
constants,
|
|
289
|
+
};
|