orez 0.2.26 → 0.2.29
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/dist/cf-do/worker.d.ts.map +1 -1
- package/dist/cf-do/worker.js +9 -1
- package/dist/cf-do/worker.js.map +1 -1
- package/dist/pg-proxy-do-backend.d.ts +2 -0
- package/dist/pg-proxy-do-backend.d.ts.map +1 -1
- package/dist/pg-proxy-do-backend.js +49 -7
- package/dist/pg-proxy-do-backend.js.map +1 -1
- package/dist/pg-sqlite-compiler/catalog/seed.d.ts +67 -0
- package/dist/pg-sqlite-compiler/catalog/seed.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/catalog/seed.js +436 -0
- package/dist/pg-sqlite-compiler/catalog/seed.js.map +1 -0
- package/dist/pg-sqlite-compiler/index.d.ts +12 -0
- package/dist/pg-sqlite-compiler/index.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/index.js +59 -0
- package/dist/pg-sqlite-compiler/index.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts +48 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.js +93 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/catalog.d.ts +34 -0
- package/dist/pg-sqlite-compiler/passes/catalog.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/catalog.js +30 -0
- package/dist/pg-sqlite-compiler/passes/catalog.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/datetime.d.ts +21 -0
- package/dist/pg-sqlite-compiler/passes/datetime.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/datetime.js +53 -0
- package/dist/pg-sqlite-compiler/passes/datetime.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/index.d.ts +21 -0
- package/dist/pg-sqlite-compiler/passes/index.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/index.js +39 -0
- package/dist/pg-sqlite-compiler/passes/index.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/types.d.ts +41 -0
- package/dist/pg-sqlite-compiler/passes/types.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/types.js +103 -0
- package/dist/pg-sqlite-compiler/passes/types.js.map +1 -0
- package/dist/pg-sqlite-compiler/test/oracle.d.ts +34 -0
- package/dist/pg-sqlite-compiler/test/oracle.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/test/oracle.js +204 -0
- package/dist/pg-sqlite-compiler/test/oracle.js.map +1 -0
- package/dist/pg-sqlite-compiler/types.d.ts +55 -0
- package/dist/pg-sqlite-compiler/types.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/types.js +2 -0
- package/dist/pg-sqlite-compiler/types.js.map +1 -0
- package/package.json +8 -4
- package/src/admin/admin-data.test.ts +0 -348
- package/src/admin/http-proxy.ts +0 -252
- package/src/admin/log-store.ts +0 -192
- package/src/admin/server.ts +0 -471
- package/src/admin/ui.ts +0 -1322
- package/src/bench/proxy-throughput.bench.ts +0 -343
- package/src/bench/serial-mutations.bench.ts +0 -270
- package/src/browser.ts +0 -203
- package/src/cf-do/.wrangler/cache/cf.json +0 -1
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0f0f3bdf0abda097eb6f1246db4657d9fc622081362d894d82c1a1ce067b05b6.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/1ddd3a4a48a11b51658444f5458a1fb175194b1d5b6a5bda20ef3fe3205b900c.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/204a39120310d37e972c5914cfd71ad55c151bdb9e8ed289a5f8c5b052dd60e4.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/3835f242df9728adba3d127a238793fd054ed3e51df3f60749ee744c469bf2a2.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/4aa9c80eb716cf55b8995ccf7afab0b36c683e6da07d7c37a3f9c570136036df.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/533e2fd1d6ea46e7a9a0017916ef341802d438d72583462755f2c1f8225e9bf2.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/5ffa1aced1225ecaeac6366f7586aa3de92761cdff8711d81fbd81f248076abd.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/686c3a9f0d7e59ed2ab607efd4b76d779c97cafeb3818380033bf7c7eb86c819.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/6e8214e8dcfadd0deb52d64e5e9ca85c6b329ace11193909845995396914c473.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/78d9ec9ff873d3fe3507ff53c2a6f6dfc408b4268eb0db3f2a146c0678965366.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/7eff9f0ed7e27ad0d3f9d923de0682fab1928591172c1ba336c5f79a134a5d85.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/836cda5b995b25867d722ed4f4c2292167e80351a3c6038db626648eb247dd8b.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/91ef63b112209ab30172763acd8a0935106c248f7f1bcae5545ce37a9f201551.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/a66ea4293a5f5938bc6d116edfa2522bb85bc37aea3541fbc09c3b613b9b32c0.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/ceb2ab26b80590840b65651deb6e948d3bf81565c6751f3a58752cf4bf4aecae.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
- package/src/cf-do/ARCHITECTURE.md +0 -83
- package/src/cf-do/watermark.test.ts +0 -103
- package/src/cf-do/watermark.ts +0 -118
- package/src/cf-do/worker.ts +0 -1033
- package/src/cf-do/wrangler.toml +0 -11
- package/src/cf-pglite/README.md +0 -19
- package/src/change-tracking.ts +0 -25
- package/src/child-process.test.ts +0 -147
- package/src/child-process.ts +0 -90
- package/src/cli-entry.ts +0 -72
- package/src/cli.test.ts +0 -38
- package/src/cli.ts +0 -1214
- package/src/config.ts +0 -150
- package/src/do-sql-tracking.test.ts +0 -19
- package/src/do-sql-tracking.ts +0 -19
- package/src/index.ts +0 -1215
- package/src/integration/integration.test.ts +0 -517
- package/src/integration/native-binary.guard.test.ts +0 -13
- package/src/integration/native-startup.test.ts +0 -44
- package/src/integration/replication-latency.test.ts +0 -428
- package/src/integration/restore-live-stress.test.ts +0 -433
- package/src/integration/restore-reset.test.ts +0 -400
- package/src/integration/restore.test.ts +0 -274
- package/src/integration/test-permissions.ts +0 -147
- package/src/load-config.ts +0 -46
- package/src/log.ts +0 -96
- package/src/mutex.ts +0 -47
- package/src/pg-proxy-browser.singledb.test.ts +0 -233
- package/src/pg-proxy-browser.ts +0 -2022
- package/src/pg-proxy-do-backend.test.ts +0 -3890
- package/src/pg-proxy-do-backend.ts +0 -7157
- package/src/pg-proxy.ts +0 -1087
- package/src/pglite-ipc.test.ts +0 -116
- package/src/pglite-ipc.ts +0 -266
- package/src/pglite-manager.ts +0 -557
- package/src/pglite-web-proxy.test.ts +0 -57
- package/src/pglite-web-proxy.ts +0 -221
- package/src/pglite-web-worker.ts +0 -152
- package/src/pglite-worker-thread.ts +0 -253
- package/src/port.ts +0 -25
- package/src/process-title.ts +0 -9
- package/src/recovery.ts +0 -155
- package/src/replication/change-tracker.test.ts +0 -357
- package/src/replication/change-tracker.ts +0 -279
- package/src/replication/handler.test.ts +0 -511
- package/src/replication/handler.ts +0 -1190
- package/src/replication/pgoutput-encoder.test.ts +0 -697
- package/src/replication/pgoutput-encoder.ts +0 -373
- package/src/replication/tcp-replication.test.ts +0 -876
- package/src/replication/zero-compat.test.ts +0 -1150
- package/src/restore-stress.test.ts +0 -188
- package/src/s3-local.ts +0 -203
- package/src/shim/hooks.mjs +0 -120
- package/src/shim/register.mjs +0 -4
- package/src/sqlite-mode/apply-mode.ts +0 -224
- package/src/sqlite-mode/index.ts +0 -15
- package/src/sqlite-mode/native-binary.ts +0 -89
- package/src/sqlite-mode/package-resolve.ts +0 -17
- package/src/sqlite-mode/resolve-mode.ts +0 -80
- package/src/sqlite-mode/shim-template.ts +0 -159
- package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
- package/src/sqlite-mode/types.ts +0 -30
- package/src/vite-plugin.ts +0 -67
- package/src/wasm-sqlite.test.ts +0 -537
- package/src/worker/browser-admin.ts +0 -52
- package/src/worker/browser-build-config.test.ts +0 -71
- package/src/worker/browser-build-config.ts +0 -109
- package/src/worker/browser-embed-admin.test.ts +0 -75
- package/src/worker/browser-embed.ts +0 -345
- package/src/worker/cf-patches.ts +0 -384
- package/src/worker/embed-integration.test.ts +0 -321
- package/src/worker/index.ts +0 -138
- package/src/worker/shims/fastify.test.ts +0 -255
- package/src/worker/shims/fastify.ts +0 -306
- package/src/worker/shims/http-service.test.ts +0 -355
- package/src/worker/shims/http-service.ts +0 -293
- package/src/worker/shims/node-stub.ts +0 -290
- package/src/worker/shims/oxfmt.ts +0 -3
- package/src/worker/shims/postgres-browser.ts +0 -59
- package/src/worker/shims/postgres-socket.test.ts +0 -576
- package/src/worker/shims/postgres-socket.ts +0 -310
- package/src/worker/shims/postgres.test.ts +0 -364
- package/src/worker/shims/postgres.ts +0 -1454
- package/src/worker/shims/sqlite-browser.test.ts +0 -233
- package/src/worker/shims/sqlite-browser.ts +0 -175
- package/src/worker/shims/sqlite.test.ts +0 -786
- package/src/worker/shims/sqlite.ts +0 -978
- package/src/worker/shims/stream-browser.ts +0 -15
- package/src/worker/shims/ws-browser.test.ts +0 -205
- package/src/worker/shims/ws-browser.ts +0 -248
- package/src/worker/shims/ws.test.ts +0 -288
- package/src/worker/shims/ws.ts +0 -467
- package/src/worker/shims/zero-process-env.ts +0 -11
- package/src/worker/types.ts +0 -75
- package/src/worker/worker-integration.test.ts +0 -223
- package/src/worker/worker.test.ts +0 -136
- package/src/worker/zero-cache-embed-cf.ts +0 -463
- package/src/worker/zero-cache-embed.ts +0 -277
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* stream shim — re-exports readable-stream with missing Node.js stream functions.
|
|
3
|
-
*
|
|
4
|
-
* readable-stream/stream-browserify don't include getDefaultHighWaterMark
|
|
5
|
-
* which zero-cache uses (added in Node.js 18+).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// @ts-expect-error — readable-stream is CJS
|
|
9
|
-
export * from 'readable-stream'
|
|
10
|
-
// @ts-expect-error — readable-stream is CJS
|
|
11
|
-
export { default } from 'readable-stream'
|
|
12
|
-
|
|
13
|
-
export function getDefaultHighWaterMark(objectMode: boolean): number {
|
|
14
|
-
return objectMode ? 16 : 16 * 1024
|
|
15
|
-
}
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { messagePortToWs, browserWsToWs, createInProcessPair } from './ws-browser.js'
|
|
4
|
-
|
|
5
|
-
describe('messagePortToWs', () => {
|
|
6
|
-
// create a mock MessagePort pair
|
|
7
|
-
function createMockPorts() {
|
|
8
|
-
type Handler = (event: MessageEvent) => void
|
|
9
|
-
let handler1: Handler | null = null
|
|
10
|
-
let handler2: Handler | null = null
|
|
11
|
-
let closed1 = false
|
|
12
|
-
let closed2 = false
|
|
13
|
-
|
|
14
|
-
const port1 = {
|
|
15
|
-
set onmessage(h: Handler | null) {
|
|
16
|
-
handler1 = h
|
|
17
|
-
},
|
|
18
|
-
get onmessage() {
|
|
19
|
-
return handler1
|
|
20
|
-
},
|
|
21
|
-
onmessageerror: null as Handler | null,
|
|
22
|
-
postMessage(data: unknown) {
|
|
23
|
-
if (closed2) return
|
|
24
|
-
// deliver to port2's handler
|
|
25
|
-
handler2?.({ data } as MessageEvent)
|
|
26
|
-
},
|
|
27
|
-
close() {
|
|
28
|
-
closed1 = true
|
|
29
|
-
},
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const port2 = {
|
|
33
|
-
set onmessage(h: Handler | null) {
|
|
34
|
-
handler2 = h
|
|
35
|
-
},
|
|
36
|
-
get onmessage() {
|
|
37
|
-
return handler2
|
|
38
|
-
},
|
|
39
|
-
onmessageerror: null as Handler | null,
|
|
40
|
-
postMessage(data: unknown) {
|
|
41
|
-
if (closed1) return
|
|
42
|
-
handler1?.({ data } as MessageEvent)
|
|
43
|
-
},
|
|
44
|
-
close() {
|
|
45
|
-
closed2 = true
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return [port1, port2] as [typeof port1, typeof port2]
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
it('wraps a MessagePort as WebSocket-like', () => {
|
|
53
|
-
const [port1] = createMockPorts()
|
|
54
|
-
const ws = messagePortToWs(port1 as any)
|
|
55
|
-
expect(ws.readyState).toBe(1) // OPEN
|
|
56
|
-
expect(ws.send).toBeInstanceOf(Function)
|
|
57
|
-
expect(ws.close).toBeInstanceOf(Function)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('send() calls port.postMessage', () => {
|
|
61
|
-
const [port1] = createMockPorts()
|
|
62
|
-
const spy = vi.spyOn(port1, 'postMessage')
|
|
63
|
-
const ws = messagePortToWs(port1 as any)
|
|
64
|
-
|
|
65
|
-
ws.send('hello')
|
|
66
|
-
expect(spy).toHaveBeenCalledWith('hello')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('send() invokes the ws callback after posting', () => {
|
|
70
|
-
const [port1] = createMockPorts()
|
|
71
|
-
const ws = messagePortToWs(port1 as any)
|
|
72
|
-
const callback = vi.fn()
|
|
73
|
-
|
|
74
|
-
ws.send('hello', callback)
|
|
75
|
-
|
|
76
|
-
expect(callback).toHaveBeenCalledWith()
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('send() reports an error to the callback after close', () => {
|
|
80
|
-
const [port1] = createMockPorts()
|
|
81
|
-
const ws = messagePortToWs(port1 as any)
|
|
82
|
-
const callback = vi.fn()
|
|
83
|
-
|
|
84
|
-
ws.close()
|
|
85
|
-
ws.send('ignored', callback)
|
|
86
|
-
|
|
87
|
-
expect(callback).toHaveBeenCalledWith(expect.any(Error))
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('forwards port messages as ws message events', () => {
|
|
91
|
-
const [port1, port2] = createMockPorts()
|
|
92
|
-
const ws1 = messagePortToWs(port1 as any)
|
|
93
|
-
|
|
94
|
-
const handler = vi.fn()
|
|
95
|
-
ws1.addEventListener('message', handler)
|
|
96
|
-
|
|
97
|
-
// send from port2 → should arrive at ws1
|
|
98
|
-
port2.postMessage('world')
|
|
99
|
-
expect(handler).toHaveBeenCalledWith({ data: 'world' })
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('close() sets readyState to CLOSED and fires event', () => {
|
|
103
|
-
const [port1] = createMockPorts()
|
|
104
|
-
const ws = messagePortToWs(port1 as any)
|
|
105
|
-
|
|
106
|
-
const closeHandler = vi.fn()
|
|
107
|
-
ws.addEventListener('close', closeHandler)
|
|
108
|
-
|
|
109
|
-
ws.close(1000)
|
|
110
|
-
expect(ws.readyState).toBe(3) // CLOSED
|
|
111
|
-
expect(closeHandler).toHaveBeenCalledWith(
|
|
112
|
-
expect.objectContaining({ code: 1000, wasClean: true })
|
|
113
|
-
)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('send() is no-op after close', () => {
|
|
117
|
-
const [port1] = createMockPorts()
|
|
118
|
-
const spy = vi.spyOn(port1, 'postMessage')
|
|
119
|
-
const ws = messagePortToWs(port1 as any)
|
|
120
|
-
|
|
121
|
-
ws.close()
|
|
122
|
-
ws.send('ignored')
|
|
123
|
-
// postMessage should not be called after close
|
|
124
|
-
expect(spy).not.toHaveBeenCalled()
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('removeEventListener works', () => {
|
|
128
|
-
const [port1] = createMockPorts()
|
|
129
|
-
const ws = messagePortToWs(port1 as any)
|
|
130
|
-
|
|
131
|
-
const handler = vi.fn()
|
|
132
|
-
ws.addEventListener('message', handler)
|
|
133
|
-
ws.removeEventListener('message', handler)
|
|
134
|
-
|
|
135
|
-
// simulate message — handler should not be called
|
|
136
|
-
;(port1 as any).onmessage?.({ data: 'test' })
|
|
137
|
-
// the handler was removed from ws listeners but port.onmessage still fires
|
|
138
|
-
// however ws.addEventListener wraps the handler, so the original shouldn't fire
|
|
139
|
-
// ... actually the port.onmessage fires the ws internal handler which checks listeners
|
|
140
|
-
// this is an implementation detail. just verify no error is thrown.
|
|
141
|
-
})
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
describe('browserWsToWs', () => {
|
|
145
|
-
it('wraps a browser WebSocket', () => {
|
|
146
|
-
const mockWs = {
|
|
147
|
-
readyState: 1,
|
|
148
|
-
send: vi.fn(),
|
|
149
|
-
close: vi.fn(),
|
|
150
|
-
addEventListener: vi.fn(),
|
|
151
|
-
removeEventListener: vi.fn(),
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const ws = browserWsToWs(mockWs as any)
|
|
155
|
-
expect(ws.readyState).toBe(1)
|
|
156
|
-
|
|
157
|
-
ws.send('test')
|
|
158
|
-
expect(mockWs.send).toHaveBeenCalledWith('test')
|
|
159
|
-
|
|
160
|
-
ws.close(1000, 'bye')
|
|
161
|
-
expect(mockWs.close).toHaveBeenCalledWith(1000, 'bye')
|
|
162
|
-
})
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
describe('createInProcessPair', () => {
|
|
166
|
-
it('creates a connected pair', () => {
|
|
167
|
-
const [client, server] = createInProcessPair()
|
|
168
|
-
expect(client.readyState).toBe(1)
|
|
169
|
-
expect(server.readyState).toBe(1)
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
it('messages flow between client and server', async () => {
|
|
173
|
-
const [client, server] = createInProcessPair()
|
|
174
|
-
|
|
175
|
-
// MessageChannel delivers messages asynchronously in Node.js
|
|
176
|
-
const serverReceived = new Promise<string>((resolve) => {
|
|
177
|
-
server.addEventListener('message', (event: any) => {
|
|
178
|
-
resolve(event.data)
|
|
179
|
-
})
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
client.send('hello from client')
|
|
183
|
-
expect(await serverReceived).toBe('hello from client')
|
|
184
|
-
|
|
185
|
-
const clientReceived = new Promise<string>((resolve) => {
|
|
186
|
-
client.addEventListener('message', (event: any) => {
|
|
187
|
-
resolve(event.data)
|
|
188
|
-
})
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
server.send('hello from server')
|
|
192
|
-
expect(await clientReceived).toBe('hello from server')
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
it('close sets readyState', () => {
|
|
196
|
-
const [client] = createInProcessPair()
|
|
197
|
-
|
|
198
|
-
const closeHandler = vi.fn()
|
|
199
|
-
client.addEventListener('close', closeHandler)
|
|
200
|
-
|
|
201
|
-
client.close(1000)
|
|
202
|
-
expect(client.readyState).toBe(3)
|
|
203
|
-
expect(closeHandler).toHaveBeenCalled()
|
|
204
|
-
})
|
|
205
|
-
})
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* browser WebSocket/MessagePort adapter for the ws shim.
|
|
3
|
-
*
|
|
4
|
-
* wraps a browser WebSocket or MessagePort to match the interface
|
|
5
|
-
* that the existing ws shim (orez/worker/shims/ws) expects. this lets
|
|
6
|
-
* zero-cache handle WebSocket connections in browser Web Workers.
|
|
7
|
-
*
|
|
8
|
-
* usage:
|
|
9
|
-
* import { messagePortToWs, browserWsToWs } from 'orez/worker/shims/ws-browser'
|
|
10
|
-
*
|
|
11
|
-
* // from a MessageChannel (worker ↔ main thread)
|
|
12
|
-
* const channel = new MessageChannel()
|
|
13
|
-
* const serverWs = messagePortToWs(channel.port2)
|
|
14
|
-
*
|
|
15
|
-
* // from a browser WebSocket
|
|
16
|
-
* const ws = new WebSocket('ws://...')
|
|
17
|
-
* const shimWs = browserWsToWs(ws)
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
// the interface that the ws shim expects (same as CF WebSocket)
|
|
21
|
-
// on/off are needed because createWebSocketStream uses ws.on('message')
|
|
22
|
-
interface WsCompatible {
|
|
23
|
-
// ws constants — zero-cache uses ws.OPEN / ws.CONNECTING in switch statements
|
|
24
|
-
CONNECTING: number
|
|
25
|
-
OPEN: number
|
|
26
|
-
CLOSING: number
|
|
27
|
-
CLOSED: number
|
|
28
|
-
readyState: number
|
|
29
|
-
send(
|
|
30
|
-
data: string | ArrayBuffer | ArrayBufferView,
|
|
31
|
-
callback?: (err?: Error) => void
|
|
32
|
-
): void
|
|
33
|
-
close(code?: number, reason?: string): void
|
|
34
|
-
addEventListener(type: string, handler: (event: any) => void): void
|
|
35
|
-
removeEventListener(type: string, handler: (event: any) => void): void
|
|
36
|
-
on(type: string, handler: (event: any) => void): void
|
|
37
|
-
off(type: string, handler: (event: any) => void): void
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* wrap a MessagePort to look like a WebSocket.
|
|
42
|
-
*
|
|
43
|
-
* MessagePort uses postMessage/onmessage, while the ws shim expects
|
|
44
|
-
* send/addEventListener('message'). this bridges the two.
|
|
45
|
-
*
|
|
46
|
-
* messages that arrive before any listener is registered are buffered
|
|
47
|
-
* and replayed when the first 'message' listener is added. this prevents
|
|
48
|
-
* a race where the port starts receiving data before the connection
|
|
49
|
-
* handler (e.g. createWebSocketStream / proxyInbound) has set up its
|
|
50
|
-
* listener — which would silently drop messages.
|
|
51
|
-
*/
|
|
52
|
-
export function messagePortToWs(port: MessagePort): WsCompatible {
|
|
53
|
-
// separate listener sets for on() vs addEventListener() to match real ws behavior.
|
|
54
|
-
// in the ws package, on() is EventEmitter-style and addEventListener() is DOM-style.
|
|
55
|
-
// createWebSocketStream uses ws.on('message') exclusively for inbound data.
|
|
56
|
-
// streamOut uses ws.addEventListener('message') for ack handling.
|
|
57
|
-
// if they share the same set, ack messages reach both handlers and
|
|
58
|
-
// handleMessage tries to parse acks as protocol messages, closing the connection.
|
|
59
|
-
const onListeners = new Map<string, Set<(event: any) => void>>()
|
|
60
|
-
const domListeners = new Map<string, Set<(event: any) => void>>()
|
|
61
|
-
let closed = false
|
|
62
|
-
|
|
63
|
-
// buffer messages until a 'message' listener is registered (either kind)
|
|
64
|
-
const pendingMessages: any[] = []
|
|
65
|
-
|
|
66
|
-
function addOnListener(type: string, handler: (event: any) => void) {
|
|
67
|
-
if (!onListeners.has(type)) onListeners.set(type, new Set())
|
|
68
|
-
onListeners.get(type)!.add(handler)
|
|
69
|
-
if (type === 'message' && pendingMessages.length > 0) {
|
|
70
|
-
const queued = pendingMessages.splice(0)
|
|
71
|
-
for (const event of queued) handler(event)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function removeOnListener(type: string, handler: (event: any) => void) {
|
|
76
|
-
onListeners.get(type)?.delete(handler)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function addDomListener(type: string, handler: (event: any) => void) {
|
|
80
|
-
if (!domListeners.has(type)) domListeners.set(type, new Set())
|
|
81
|
-
domListeners.get(type)!.add(handler)
|
|
82
|
-
if (type === 'message' && pendingMessages.length > 0) {
|
|
83
|
-
const queued = pendingMessages.splice(0)
|
|
84
|
-
for (const event of queued) handler(event)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function removeDomListener(type: string, handler: (event: any) => void) {
|
|
89
|
-
domListeners.get(type)?.delete(handler)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function emit(type: string, event: any) {
|
|
93
|
-
const onHandlers = onListeners.get(type)
|
|
94
|
-
const domHandlers = domListeners.get(type)
|
|
95
|
-
const hasAny =
|
|
96
|
-
(onHandlers && onHandlers.size > 0) || (domHandlers && domHandlers.size > 0)
|
|
97
|
-
if (!hasAny) {
|
|
98
|
-
if (type === 'message') pendingMessages.push(event)
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
if (onHandlers) for (const h of onHandlers) h(event)
|
|
102
|
-
if (domHandlers) for (const h of domHandlers) h(event)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// forward port messages → ws 'message' events
|
|
106
|
-
// filter out control messages from sync-ws-patch.js (__close, __open)
|
|
107
|
-
port.onmessage = (event: MessageEvent) => {
|
|
108
|
-
const data = event.data
|
|
109
|
-
// control messages from sync-ws-patch.js — handle as close/open events
|
|
110
|
-
if (
|
|
111
|
-
data &&
|
|
112
|
-
typeof data === 'object' &&
|
|
113
|
-
!ArrayBuffer.isView(data) &&
|
|
114
|
-
!(data instanceof ArrayBuffer)
|
|
115
|
-
) {
|
|
116
|
-
if (data.__close) {
|
|
117
|
-
closed = true
|
|
118
|
-
port.close()
|
|
119
|
-
emit('close', {
|
|
120
|
-
code: data.code ?? 1000,
|
|
121
|
-
reason: data.reason ?? '',
|
|
122
|
-
wasClean: true,
|
|
123
|
-
})
|
|
124
|
-
return
|
|
125
|
-
}
|
|
126
|
-
if (data.__open) {
|
|
127
|
-
// already open, ignore
|
|
128
|
-
return
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
emit('message', { data })
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
port.onmessageerror = (event: MessageEvent) => {
|
|
135
|
-
emit('error', { message: 'MessagePort error', error: event })
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
// ws constants — zero-cache uses ws.OPEN / ws.CONNECTING in switch statements
|
|
140
|
-
CONNECTING: 0,
|
|
141
|
-
OPEN: 1,
|
|
142
|
-
CLOSING: 2,
|
|
143
|
-
CLOSED: 3,
|
|
144
|
-
|
|
145
|
-
get readyState() {
|
|
146
|
-
return closed ? 3 : 1 // CLOSED or OPEN
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
send(data: string | ArrayBuffer | ArrayBufferView, callback?: (err?: Error) => void) {
|
|
150
|
-
if (closed) {
|
|
151
|
-
callback?.(new Error('WebSocket is closed'))
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
port.postMessage(data)
|
|
157
|
-
} catch (error) {
|
|
158
|
-
const err = error instanceof Error ? error : new Error(String(error))
|
|
159
|
-
if (callback) {
|
|
160
|
-
callback(err)
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
throw err
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
callback?.()
|
|
167
|
-
},
|
|
168
|
-
|
|
169
|
-
close(code?: number, _reason?: string) {
|
|
170
|
-
if (closed) return
|
|
171
|
-
closed = true
|
|
172
|
-
port.close()
|
|
173
|
-
emit('close', { code: code ?? 1000, reason: '', wasClean: true })
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
addEventListener: addDomListener,
|
|
177
|
-
removeEventListener: removeDomListener,
|
|
178
|
-
on: addOnListener,
|
|
179
|
-
off: removeOnListener,
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* wrap a browser WebSocket to match the ws shim's expected interface.
|
|
185
|
-
*
|
|
186
|
-
* browser WebSocket and the ws shim's CFWebSocket interface are very
|
|
187
|
-
* similar but have subtle differences. this normalizes them.
|
|
188
|
-
*/
|
|
189
|
-
export function browserWsToWs(ws: WebSocket): WsCompatible {
|
|
190
|
-
return {
|
|
191
|
-
CONNECTING: 0,
|
|
192
|
-
OPEN: 1,
|
|
193
|
-
CLOSING: 2,
|
|
194
|
-
CLOSED: 3,
|
|
195
|
-
|
|
196
|
-
get readyState() {
|
|
197
|
-
return ws.readyState
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
send(data: string | ArrayBuffer | ArrayBufferView, callback?: (err?: Error) => void) {
|
|
201
|
-
try {
|
|
202
|
-
ws.send(data)
|
|
203
|
-
} catch (error) {
|
|
204
|
-
const err = error instanceof Error ? error : new Error(String(error))
|
|
205
|
-
if (callback) {
|
|
206
|
-
callback(err)
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
throw err
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
callback?.()
|
|
213
|
-
},
|
|
214
|
-
|
|
215
|
-
close(code?: number, reason?: string) {
|
|
216
|
-
ws.close(code, reason)
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
addEventListener(type: string, handler: (event: any) => void) {
|
|
220
|
-
ws.addEventListener(type, handler)
|
|
221
|
-
},
|
|
222
|
-
|
|
223
|
-
removeEventListener(type: string, handler: (event: any) => void) {
|
|
224
|
-
ws.removeEventListener(type, handler)
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
on(type: string, handler: (event: any) => void) {
|
|
228
|
-
ws.addEventListener(type, handler)
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
off(type: string, handler: (event: any) => void) {
|
|
232
|
-
ws.removeEventListener(type, handler)
|
|
233
|
-
},
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* create a connected pair of WebSocket-like objects for in-process
|
|
239
|
-
* communication (e.g., when zero-cache and Zero client are in the
|
|
240
|
-
* same browser context). uses MessageChannel internally.
|
|
241
|
-
*
|
|
242
|
-
* returns [client, server] — client goes to Zero client, server
|
|
243
|
-
* goes to the browser embed's handleWebSocket().
|
|
244
|
-
*/
|
|
245
|
-
export function createInProcessPair(): [WsCompatible, WsCompatible] {
|
|
246
|
-
const channel = new MessageChannel()
|
|
247
|
-
return [messagePortToWs(channel.port1), messagePortToWs(channel.port2)]
|
|
248
|
-
}
|