orez 0.2.27 → 0.2.30

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.
Files changed (157) hide show
  1. package/dist/cf-do/worker.d.ts +3 -0
  2. package/dist/cf-do/worker.d.ts.map +1 -1
  3. package/dist/cf-do/worker.js +37 -15
  4. package/dist/cf-do/worker.js.map +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +8 -0
  7. package/dist/index.js.map +1 -1
  8. package/package.json +3 -4
  9. package/src/admin/admin-data.test.ts +0 -348
  10. package/src/admin/http-proxy.ts +0 -252
  11. package/src/admin/log-store.ts +0 -192
  12. package/src/admin/server.ts +0 -471
  13. package/src/admin/ui.ts +0 -1322
  14. package/src/bench/proxy-throughput.bench.ts +0 -343
  15. package/src/bench/serial-mutations.bench.ts +0 -270
  16. package/src/browser.ts +0 -203
  17. package/src/cf-do/.wrangler/cache/cf.json +0 -1
  18. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  19. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  20. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  21. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0ffaabee41a60e04dd0eb7db3073f0a40139e6a97ccd26823967acb652b89a7b.sqlite +0 -0
  22. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
  23. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
  24. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
  25. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-insertion-facade.js +0 -11
  26. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-loader.entry.ts +0 -134
  27. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-insertion-facade.js +0 -11
  28. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-loader.entry.ts +0 -134
  29. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js +0 -1059
  30. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js.map +0 -8
  31. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js +0 -1059
  32. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js.map +0 -8
  33. package/src/cf-do/ARCHITECTURE.md +0 -93
  34. package/src/cf-do/CHAT_E2E.md +0 -213
  35. package/src/cf-do/watermark.test.ts +0 -103
  36. package/src/cf-do/watermark.ts +0 -118
  37. package/src/cf-do/worker.ts +0 -1041
  38. package/src/cf-do/wrangler.toml +0 -11
  39. package/src/cf-pglite/README.md +0 -19
  40. package/src/change-tracking.ts +0 -25
  41. package/src/child-process.test.ts +0 -147
  42. package/src/child-process.ts +0 -90
  43. package/src/cli-entry.ts +0 -72
  44. package/src/cli.test.ts +0 -40
  45. package/src/cli.ts +0 -1214
  46. package/src/config.ts +0 -150
  47. package/src/do-sql-tracking.test.ts +0 -19
  48. package/src/do-sql-tracking.ts +0 -19
  49. package/src/index.ts +0 -1215
  50. package/src/integration/integration.test.ts +0 -517
  51. package/src/integration/native-binary.guard.test.ts +0 -13
  52. package/src/integration/native-startup.test.ts +0 -44
  53. package/src/integration/replication-latency.test.ts +0 -428
  54. package/src/integration/restore-live-stress.test.ts +0 -433
  55. package/src/integration/restore-reset.test.ts +0 -400
  56. package/src/integration/restore.test.ts +0 -274
  57. package/src/integration/test-permissions.ts +0 -147
  58. package/src/load-config.ts +0 -46
  59. package/src/log.ts +0 -96
  60. package/src/mutex.ts +0 -47
  61. package/src/pg-proxy-browser.singledb.test.ts +0 -233
  62. package/src/pg-proxy-browser.ts +0 -2022
  63. package/src/pg-proxy-do-backend.test.ts +0 -3890
  64. package/src/pg-proxy-do-backend.ts +0 -7191
  65. package/src/pg-proxy.ts +0 -1087
  66. package/src/pg-sqlite-compiler/README.md +0 -53
  67. package/src/pg-sqlite-compiler/catalog/seed.ts +0 -524
  68. package/src/pg-sqlite-compiler/fixtures/pgsqlite/arithmetic.json +0 -307
  69. package/src/pg-sqlite-compiler/fixtures/pgsqlite/array.json +0 -377
  70. package/src/pg-sqlite-compiler/fixtures/pgsqlite/cast.json +0 -12
  71. package/src/pg-sqlite-compiler/fixtures/pgsqlite/catalog.json +0 -447
  72. package/src/pg-sqlite-compiler/fixtures/pgsqlite/create-table.json +0 -32
  73. package/src/pg-sqlite-compiler/fixtures/pgsqlite/datetime.json +0 -397
  74. package/src/pg-sqlite-compiler/fixtures/pgsqlite/enum.json +0 -337
  75. package/src/pg-sqlite-compiler/fixtures/pgsqlite/insert.json +0 -337
  76. package/src/pg-sqlite-compiler/fixtures/pgsqlite/json.json +0 -537
  77. package/src/pg-sqlite-compiler/fixtures/pgsqlite/misc.json +0 -1837
  78. package/src/pg-sqlite-compiler/index.ts +0 -73
  79. package/src/pg-sqlite-compiler/integration.test.ts +0 -136
  80. package/src/pg-sqlite-compiler/passes/ast-utils.ts +0 -113
  81. package/src/pg-sqlite-compiler/passes/catalog.ts +0 -65
  82. package/src/pg-sqlite-compiler/passes/datetime.ts +0 -74
  83. package/src/pg-sqlite-compiler/passes/index.ts +0 -49
  84. package/src/pg-sqlite-compiler/passes/types.ts +0 -156
  85. package/src/pg-sqlite-compiler/smoke.test.ts +0 -69
  86. package/src/pg-sqlite-compiler/test/catalog.test.ts +0 -171
  87. package/src/pg-sqlite-compiler/test/corpus.test.ts +0 -161
  88. package/src/pg-sqlite-compiler/test/datetime.oracle.test.ts +0 -102
  89. package/src/pg-sqlite-compiler/test/oracle.ts +0 -237
  90. package/src/pg-sqlite-compiler/test/types.test.ts +0 -109
  91. package/src/pg-sqlite-compiler/types.ts +0 -63
  92. package/src/pglite-ipc.test.ts +0 -116
  93. package/src/pglite-ipc.ts +0 -266
  94. package/src/pglite-manager.ts +0 -557
  95. package/src/pglite-web-proxy.test.ts +0 -57
  96. package/src/pglite-web-proxy.ts +0 -221
  97. package/src/pglite-web-worker.ts +0 -152
  98. package/src/pglite-worker-thread.ts +0 -253
  99. package/src/port.ts +0 -25
  100. package/src/process-title.ts +0 -9
  101. package/src/recovery.ts +0 -155
  102. package/src/replication/change-tracker.test.ts +0 -357
  103. package/src/replication/change-tracker.ts +0 -279
  104. package/src/replication/handler.test.ts +0 -511
  105. package/src/replication/handler.ts +0 -1190
  106. package/src/replication/pgoutput-encoder.test.ts +0 -697
  107. package/src/replication/pgoutput-encoder.ts +0 -373
  108. package/src/replication/tcp-replication.test.ts +0 -876
  109. package/src/replication/zero-compat.test.ts +0 -1150
  110. package/src/restore-stress.test.ts +0 -188
  111. package/src/s3-local.ts +0 -203
  112. package/src/shim/hooks.mjs +0 -120
  113. package/src/shim/register.mjs +0 -4
  114. package/src/sqlite-mode/apply-mode.ts +0 -224
  115. package/src/sqlite-mode/index.ts +0 -15
  116. package/src/sqlite-mode/native-binary.ts +0 -89
  117. package/src/sqlite-mode/package-resolve.ts +0 -17
  118. package/src/sqlite-mode/resolve-mode.ts +0 -80
  119. package/src/sqlite-mode/shim-template.ts +0 -159
  120. package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
  121. package/src/sqlite-mode/types.ts +0 -30
  122. package/src/vite-plugin.ts +0 -67
  123. package/src/wasm-sqlite.test.ts +0 -537
  124. package/src/worker/browser-admin.ts +0 -52
  125. package/src/worker/browser-build-config.test.ts +0 -71
  126. package/src/worker/browser-build-config.ts +0 -109
  127. package/src/worker/browser-embed-admin.test.ts +0 -75
  128. package/src/worker/browser-embed.ts +0 -345
  129. package/src/worker/cf-patches.ts +0 -384
  130. package/src/worker/embed-integration.test.ts +0 -321
  131. package/src/worker/index.ts +0 -138
  132. package/src/worker/shims/fastify.test.ts +0 -255
  133. package/src/worker/shims/fastify.ts +0 -306
  134. package/src/worker/shims/http-service.test.ts +0 -355
  135. package/src/worker/shims/http-service.ts +0 -293
  136. package/src/worker/shims/node-stub.ts +0 -290
  137. package/src/worker/shims/oxfmt.ts +0 -3
  138. package/src/worker/shims/postgres-browser.ts +0 -59
  139. package/src/worker/shims/postgres-socket.test.ts +0 -576
  140. package/src/worker/shims/postgres-socket.ts +0 -310
  141. package/src/worker/shims/postgres.test.ts +0 -364
  142. package/src/worker/shims/postgres.ts +0 -1454
  143. package/src/worker/shims/sqlite-browser.test.ts +0 -233
  144. package/src/worker/shims/sqlite-browser.ts +0 -175
  145. package/src/worker/shims/sqlite.test.ts +0 -786
  146. package/src/worker/shims/sqlite.ts +0 -978
  147. package/src/worker/shims/stream-browser.ts +0 -15
  148. package/src/worker/shims/ws-browser.test.ts +0 -205
  149. package/src/worker/shims/ws-browser.ts +0 -248
  150. package/src/worker/shims/ws.test.ts +0 -288
  151. package/src/worker/shims/ws.ts +0 -467
  152. package/src/worker/shims/zero-process-env.ts +0 -11
  153. package/src/worker/types.ts +0 -75
  154. package/src/worker/worker-integration.test.ts +0 -223
  155. package/src/worker/worker.test.ts +0 -136
  156. package/src/worker/zero-cache-embed-cf.ts +0 -463
  157. package/src/worker/zero-cache-embed.ts +0 -277
@@ -1,467 +0,0 @@
1
- // NOTE THIS IS NOT OREZ NODE THIS IS NOT A GOOD REFERENCE BECAUSE ITS OUR EARLY GUESS AT WHAT COULD WORK
2
- // DO NOT STUDY THIS, THE OTHER STUFF IN SRC IS WHERE YOU EANT TO LOOK
3
-
4
- /**
5
- * ws (websocket) shim for cloudflare workers.
6
- *
7
- * wraps CF Workers WebSocket (from WebSocketPair) to implement the
8
- * ws npm package API that zero-cache uses. enables bundler aliasing
9
- * so zero-cache's WebSocket handling works with CF durable WebSockets.
10
- *
11
- * usage with bundler alias:
12
- * alias: { 'ws': './src/worker/shims/ws.js' }
13
- */
14
-
15
- import EventEmitter from 'node:events'
16
- import { Duplex } from 'node:stream'
17
-
18
- // -- readyState constants --
19
- const CONNECTING = 0
20
- const OPEN = 1
21
- const CLOSING = 2
22
- const CLOSED = 3
23
-
24
- // -- CF WebSocket interface (minimal) --
25
- interface CFWebSocket {
26
- send(data: string | ArrayBuffer | ArrayBufferView): void
27
- close(code?: number, reason?: string): void
28
- addEventListener(type: string, handler: (event: any) => void): void
29
- removeEventListener(type: string, handler: (event: any) => void): void
30
- readyState: number
31
- accept?(): void
32
- }
33
-
34
- function debugWS(event: Record<string, unknown>): void {
35
- try {
36
- const log = (globalThis as any).__orez_ws_debug_log
37
- if (typeof log === 'function') log(event)
38
- } catch {
39
- // debug logging must never affect websocket behavior
40
- }
41
- }
42
-
43
- function summarizeWSData(data: unknown): Record<string, unknown> {
44
- if (typeof data === 'string') {
45
- return {
46
- dataType: 'string',
47
- bytes: data.length,
48
- text: data.length > 300 ? `${data.slice(0, 300)}...` : data,
49
- }
50
- }
51
- if (typeof Buffer !== 'undefined' && Buffer.isBuffer(data)) {
52
- return { dataType: 'buffer', bytes: data.byteLength }
53
- }
54
- if (data instanceof ArrayBuffer) {
55
- return { dataType: 'arraybuffer', bytes: data.byteLength }
56
- }
57
- if (ArrayBuffer.isView(data)) {
58
- return { dataType: data.constructor.name, bytes: data.byteLength }
59
- }
60
- return { dataType: typeof data }
61
- }
62
-
63
- // -- WebSocket shim --
64
- // wraps a CF WebSocket to match the ws package WebSocket API
65
-
66
- class WebSocket extends EventEmitter {
67
- static readonly CONNECTING = CONNECTING
68
- static readonly OPEN = OPEN
69
- static readonly CLOSING = CLOSING
70
- static readonly CLOSED = CLOSED
71
-
72
- readonly CONNECTING = CONNECTING
73
- readonly OPEN = OPEN
74
- readonly CLOSING = CLOSING
75
- readonly CLOSED = CLOSED
76
-
77
- #ws!: CFWebSocket
78
- #url: string
79
- #listeners = new Map<string, (event: any) => void>()
80
-
81
- constructor(urlOrSocket: string | CFWebSocket, _protocols?: unknown, _opts?: unknown) {
82
- super()
83
-
84
- if (typeof urlOrSocket === 'string') {
85
- this.#url = urlOrSocket
86
- // check for in-process connections (fastify shim uses port 0 or 1)
87
- const parsedUrl = new URL(urlOrSocket, 'http://localhost')
88
- const isInProcess =
89
- parsedUrl.port === '0' ||
90
- parsedUrl.port === '1' ||
91
- parsedUrl.hostname === 'localhost'
92
-
93
- if (isInProcess) {
94
- // in-process: connect via fastify server's handoff mechanism
95
- // try all registered fastify instances via tryHandoff, stop at first match
96
- const instances: any[] = (globalThis as any).__orez_fastify_instances || []
97
- const fallbackInstance = (globalThis as any).__orez_fastify_instance
98
- if (instances.length > 0 || fallbackInstance?.server) {
99
- // create paired message channels for bidirectional communication
100
- // the client-side WS (this) and serverWs are cross-linked so
101
- // ping/pong, messages, and close propagate between them
102
- const clientSide = this
103
- const serverWs: any = {
104
- readyState: 1,
105
- _listeners: {} as Record<string, Function[]>,
106
- send: (data: string | ArrayBuffer) => {
107
- // deliver to client side
108
- // wrap in event object — zero-cache handleMessage reads event.data
109
- queueMicrotask(() => clientSide.emit('message', { data }))
110
- },
111
- close: (code?: number, reason?: string) => {
112
- serverWs.readyState = 3
113
- queueMicrotask(() => clientSide.emit('close', code || 1000, reason || ''))
114
- },
115
- ping: () => {
116
- // ping from server → deliver 'ping' event to client
117
- // (expectPingsForLiveness listens for 'ping', not 'pong')
118
- queueMicrotask(() => clientSide.emit('ping'))
119
- },
120
- addEventListener: (type: string, handler: Function) => {
121
- if (!serverWs._listeners[type]) serverWs._listeners[type] = []
122
- serverWs._listeners[type].push(handler)
123
- },
124
- removeEventListener: (type: string, handler: Function) => {
125
- const arr = serverWs._listeners[type]
126
- if (arr) {
127
- const idx = arr.indexOf(handler)
128
- if (idx >= 0) arr.splice(idx, 1)
129
- }
130
- },
131
- }
132
-
133
- // client-side internal ws — forwards send() to server,
134
- // receives messages from server via addEventListener.
135
- // addEventListener MUST work because WebSocket#setupListeners registers here.
136
- const clientWsListeners: Record<string, Function[]> = {}
137
- this.#ws = {
138
- accept: () => {},
139
- send: (data: string | ArrayBuffer) => {
140
- const handlers = serverWs._listeners['message'] || []
141
- for (const h of handlers) h({ data })
142
- },
143
- close: (code?: number, reason?: string) => {
144
- const handlers = serverWs._listeners['close'] || []
145
- for (const h of handlers) h({ code, reason })
146
- },
147
- addEventListener: (type: string, handler: Function) => {
148
- if (!clientWsListeners[type]) clientWsListeners[type] = []
149
- clientWsListeners[type].push(handler)
150
- },
151
- removeEventListener: (type: string, handler: Function) => {
152
- const arr = clientWsListeners[type]
153
- if (arr) {
154
- const idx = arr.indexOf(handler)
155
- if (idx >= 0) arr.splice(idx, 1)
156
- }
157
- },
158
- get readyState() {
159
- return 1
160
- },
161
- } as CFWebSocket
162
-
163
- // wire server → client: when server sends data, deliver to client's
164
- // addEventListener handlers AND emit on the WebSocket instance
165
- const origServerSend = serverWs.send
166
- serverWs.send = (data: string | ArrayBuffer) => {
167
- const handlers = clientWsListeners['message'] || []
168
- for (const h of handlers) h({ data })
169
- queueMicrotask(() => clientSide.emit('message', { data }))
170
- }
171
-
172
- // try handoff against all fastify instances, stop at first match
173
- const path = parsedUrl.pathname + parsedUrl.search
174
- const handoffMsg = {
175
- message: { url: path, headers: {}, method: 'GET' },
176
- head: new Uint8Array(0),
177
- }
178
- queueMicrotask(() => {
179
- let handled = false
180
- for (const inst of instances) {
181
- if (inst?.tryHandoff?.(handoffMsg, serverWs)) {
182
- handled = true
183
- break
184
- }
185
- }
186
- // fallback: if no instance handled it and we have a fallback, emit directly
187
- if (!handled && fallbackInstance?.server) {
188
- fallbackInstance.server.emit('message', ['handoff', handoffMsg], serverWs)
189
- }
190
- this.emit('open')
191
- })
192
- } else {
193
- // no fastify instance — emit close immediately
194
- queueMicrotask(() => this.emit('close', 1006, 'no fastify server'))
195
- }
196
- } else if (typeof globalThis.WebSocket === 'function') {
197
- // real outbound WebSocket for external connections
198
- const nativeWs = new globalThis.WebSocket(urlOrSocket) as any
199
- this.#ws = {
200
- accept: () => {},
201
- send: (data: string | ArrayBuffer) => nativeWs.send(data),
202
- close: (code?: number, reason?: string) => nativeWs.close(code, reason),
203
- addEventListener: (type: string, handler: (event: any) => void) =>
204
- nativeWs.addEventListener(type, handler),
205
- removeEventListener: (type: string, handler: (event: any) => void) =>
206
- nativeWs.removeEventListener(type, handler),
207
- get readyState() {
208
- return nativeWs.readyState
209
- },
210
- } as CFWebSocket
211
- nativeWs.addEventListener('open', () => this.emit('open'))
212
- nativeWs.addEventListener('message', (ev: MessageEvent) =>
213
- this.emit('message', ev.data)
214
- )
215
- nativeWs.addEventListener('close', (ev: CloseEvent) =>
216
- this.emit('close', ev.code, ev.reason)
217
- )
218
- nativeWs.addEventListener('error', (ev: Event) =>
219
- this.emit('error', new Error('WebSocket error'))
220
- )
221
- } else {
222
- throw new Error(
223
- 'ws shim: outbound WebSocket connections not yet supported. ' +
224
- 'use the CF Workers fetch API for outbound WebSocket.'
225
- )
226
- }
227
- } else {
228
- this.#ws = urlOrSocket
229
- this.#url = ''
230
- debugWS({ event: 'wrap-cf-socket', readyState: this.#ws.readyState })
231
- this.#setupListeners()
232
- }
233
- }
234
-
235
- get url(): string {
236
- return this.#url
237
- }
238
-
239
- get readyState(): number {
240
- return this.#ws.readyState
241
- }
242
-
243
- send(
244
- data: string | Buffer | ArrayBuffer | ArrayBufferView,
245
- cb?: (err?: Error) => void
246
- ): void {
247
- try {
248
- debugWS({ event: 'send', url: this.#url, ...summarizeWSData(data) })
249
- if (typeof data === 'string') {
250
- this.#ws.send(data)
251
- } else if (Buffer.isBuffer(data)) {
252
- this.#ws.send(new Uint8Array(data.buffer, data.byteOffset, data.byteLength))
253
- } else if (data instanceof ArrayBuffer) {
254
- this.#ws.send(data)
255
- } else if (ArrayBuffer.isView(data)) {
256
- this.#ws.send(new Uint8Array(data.buffer, data.byteOffset, data.byteLength))
257
- } else {
258
- this.#ws.send(String(data))
259
- }
260
- cb?.()
261
- } catch (err) {
262
- cb?.(err as Error)
263
- }
264
- }
265
-
266
- close(code?: number, reason?: string): void {
267
- try {
268
- this.#ws.close(code, reason)
269
- } catch {
270
- // socket may already be closed
271
- }
272
- }
273
-
274
- terminate(): void {
275
- // real ws.terminate() destroys the socket without a close frame.
276
- // CF Workers don't expose raw socket destroy, so close with 1000.
277
- this.close(1000)
278
- }
279
-
280
- ping(_data?: unknown, _mask?: boolean, _cb?: () => void): void {
281
- // forward ping to underlying socket if it supports it (in-process pairs)
282
- if (typeof (this.#ws as any).ping === 'function') {
283
- ;(this.#ws as any).ping()
284
- }
285
- // also emit pong locally (CF WebSockets handle ping/pong at platform level)
286
- this.emit('pong')
287
- }
288
-
289
- // standard EventTarget-style addEventListener (used by Connection)
290
- // for 'message' events, wrap the handler so EventEmitter-style (data, isBinary)
291
- // args get converted to DOM-style { data } events. streamOut uses
292
- // addEventListener('message', ({data}) => ...) which needs DOM-style events.
293
- #adapterMap = new WeakMap<Function, Function>()
294
-
295
- addEventListener(type: string, handler: (event: any) => void): void {
296
- if (type === 'message') {
297
- const wrapper = (data: any, isBinary?: boolean) => {
298
- // if already a DOM-style event object with .data, pass through
299
- if (data && typeof data === 'object' && 'data' in data) {
300
- handler(data)
301
- } else {
302
- handler({ data, isBinary })
303
- }
304
- }
305
- this.#adapterMap.set(handler, wrapper)
306
- this.on(type, wrapper)
307
- } else {
308
- this.on(type, handler)
309
- }
310
- }
311
-
312
- removeEventListener(type: string, handler: (event: any) => void): void {
313
- if (type === 'message') {
314
- const wrapper = this.#adapterMap.get(handler)
315
- if (wrapper) {
316
- this.off(type, wrapper as any)
317
- this.#adapterMap.delete(handler)
318
- } else {
319
- this.off(type, handler)
320
- }
321
- } else {
322
- this.off(type, handler)
323
- }
324
- }
325
-
326
- #setupListeners(): void {
327
- // match ws npm package event signatures:
328
- // message: (data: Buffer|string, isBinary: boolean)
329
- // close: (code: number, reason: string)
330
- // error: (err: Error)
331
- const onMessage = (event: any) => {
332
- const data = event.data
333
- debugWS({ event: 'message', url: this.#url, ...summarizeWSData(data) })
334
- this.emit('message', data, typeof data !== 'string')
335
- }
336
- const onClose = (event: any) => {
337
- debugWS({
338
- event: 'close',
339
- url: this.#url,
340
- code: event.code ?? 1000,
341
- reason: event.reason ?? '',
342
- })
343
- this.emit('close', event.code ?? 1000, event.reason ?? '')
344
- }
345
- const onError = (event: any) => {
346
- debugWS({
347
- event: 'error',
348
- url: this.#url,
349
- message: event?.message ?? event?.error?.message ?? 'WebSocket error',
350
- })
351
- this.emit('error', event.error ?? new Error(event.message ?? 'WebSocket error'))
352
- }
353
- const onOpen = () => {
354
- debugWS({ event: 'open', url: this.#url })
355
- this.emit('open')
356
- }
357
-
358
- this.#ws.addEventListener('message', onMessage)
359
- this.#ws.addEventListener('close', onClose)
360
- this.#ws.addEventListener('error', onError)
361
- this.#ws.addEventListener('open', onOpen)
362
-
363
- this.#listeners.set('message', onMessage)
364
- this.#listeners.set('close', onClose)
365
- this.#listeners.set('error', onError)
366
- this.#listeners.set('open', onOpen)
367
- }
368
- }
369
-
370
- // -- WebSocketServer shim --
371
- // zero-cache uses WebSocketServer with { noServer: true } for handleUpgrade
372
-
373
- class WebSocketServer extends EventEmitter {
374
- constructor(_opts?: { noServer?: boolean }) {
375
- super()
376
- }
377
-
378
- close(cb?: (err?: Error) => void): void {
379
- // no-op — browser embed has no real server to close
380
- cb?.()
381
- }
382
-
383
- /**
384
- * handle a WebSocket upgrade. on CF Workers the upgrade is already done
385
- * (WebSocketPair), so this just wraps the CF WebSocket in our shim.
386
- *
387
- * @param message - the HTTP request (IncomingMessage-like object)
388
- * @param socket - the underlying socket (CF WebSocket on CF Workers)
389
- * @param head - upgrade head buffer
390
- * @param callback - receives the wrapped WebSocket
391
- */
392
- handleUpgrade(
393
- _message: unknown,
394
- socket: CFWebSocket | unknown,
395
- _head: unknown,
396
- callback: (ws: WebSocket) => void
397
- ): void {
398
- // wrap the CF WebSocket in our shim
399
- debugWS({ event: 'handle-upgrade' })
400
- const ws = new WebSocket(socket as CFWebSocket)
401
- callback(ws)
402
- }
403
- }
404
-
405
- // -- createWebSocketStream --
406
- // creates a Node.js Duplex stream from a WebSocket.
407
- // used by zero-cache's Connection class for streaming messages.
408
-
409
- function createWebSocketStream(
410
- ws: WebSocket,
411
- _opts?: { decodeStrings?: boolean }
412
- ): Duplex {
413
- const duplex = new Duplex({
414
- objectMode: false,
415
- decodeStrings: false,
416
-
417
- read() {
418
- // data is pushed from ws message events
419
- },
420
-
421
- write(
422
- chunk: Buffer | string,
423
- _encoding: string,
424
- callback: (err?: Error | null) => void
425
- ) {
426
- try {
427
- ws.send(typeof chunk === 'string' ? chunk : chunk.toString(), callback)
428
- } catch (err) {
429
- callback(err as Error)
430
- }
431
- },
432
-
433
- destroy(err: Error | null, callback: (err?: Error | null) => void) {
434
- ws.close()
435
- callback(err)
436
- },
437
- })
438
-
439
- // pipe ws messages into the readable side
440
- ws.on('message', (event: any) => {
441
- const data = event?.data ?? event
442
- if (typeof data === 'string') {
443
- duplex.push(data)
444
- } else if (data instanceof ArrayBuffer) {
445
- duplex.push(Buffer.from(data))
446
- } else if (ArrayBuffer.isView(data)) {
447
- duplex.push(Buffer.from(data.buffer, data.byteOffset, data.byteLength))
448
- } else {
449
- duplex.push(String(data))
450
- }
451
- })
452
-
453
- ws.on('close', () => {
454
- duplex.push(null) // signal end of readable
455
- duplex.destroy()
456
- })
457
-
458
- ws.on('error', (event: any) => {
459
- const err = event?.error ?? new Error(event?.message ?? 'WebSocket error')
460
- duplex.destroy(err)
461
- })
462
-
463
- return duplex
464
- }
465
-
466
- export default WebSocket
467
- export { WebSocket, WebSocketServer, createWebSocketStream }
@@ -1,11 +0,0 @@
1
- const globalProcess = ((globalThis as any).process ??= {})
2
-
3
- globalProcess.env ??= {}
4
- globalProcess.pid ??= 1
5
- globalProcess.argv ??= []
6
- globalProcess.kill ??= () => true
7
-
8
- globalProcess.env.SINGLE_PROCESS = '1'
9
- globalProcess.env.NODE_ENV ??= 'development'
10
-
11
- export {}
@@ -1,75 +0,0 @@
1
- /**
2
- * orez/worker types.
3
- *
4
- * interfaces for the embeddable orez worker that runs PGlite + change
5
- * tracking without Node.js dependencies. designed for CF Workers/DO
6
- * but usable in any JS runtime (browser, vitest, bun, deno).
7
- */
8
-
9
- import type { Mutex } from '../mutex.js'
10
- import type { ChangeRecord } from '../replication/change-tracker.js'
11
- import type { ReplicationWriter } from '../replication/handler.js'
12
- import type { PGlite, PGliteOptions, Results } from '@electric-sql/pglite'
13
-
14
- /** options for creating an orez worker */
15
- export interface OrezWorkerOptions {
16
- /**
17
- * pre-created PGlite instance. when provided, orez wraps it
18
- * without managing its lifecycle (caller is responsible for closing).
19
- */
20
- pglite?: PGlite
21
-
22
- /**
23
- * PGlite constructor options. used when `pglite` is not provided.
24
- * in CF Workers, pass wasmModule/fsBundle/loadDataDir here.
25
- */
26
- pgliteOptions?: PGliteOptions
27
-
28
- /** publication names to track. defaults to all public tables. */
29
- publications?: string[]
30
-
31
- /** log level (default: 'warn') */
32
- logLevel?: 'error' | 'warn' | 'info' | 'debug'
33
- }
34
-
35
- /** the orez worker instance */
36
- export interface OrezWorker {
37
- /** the underlying PGlite instance */
38
- readonly db: PGlite
39
-
40
- /** mutex for serializing PGlite access */
41
- readonly mutex: Mutex
42
-
43
- /** run a parameterized query */
44
- query<T extends Record<string, unknown> = Record<string, unknown>>(
45
- sql: string,
46
- params?: unknown[]
47
- ): Promise<Results<T>>
48
-
49
- /** execute raw SQL (DDL, multi-statement) */
50
- exec(sql: string): Promise<void>
51
-
52
- /** install/reinstall change tracking triggers on all published tables */
53
- installChangeTracking(): Promise<void>
54
-
55
- /** get changes since a watermark */
56
- getChangesSince(watermark: number, limit?: number): Promise<ChangeRecord[]>
57
-
58
- /** get current watermark value */
59
- getCurrentWatermark(): Promise<number>
60
-
61
- /** purge consumed changes up to watermark */
62
- purgeChanges(watermark: number): Promise<number>
63
-
64
- /**
65
- * start streaming replication to a writer.
66
- * runs until the writer is closed or the worker is shut down.
67
- */
68
- startReplication(writer: ReplicationWriter): Promise<void>
69
-
70
- /** whether this worker owns the PGlite instance (manages its lifecycle) */
71
- readonly ownsInstance: boolean
72
-
73
- /** close the worker. if ownsInstance, also closes PGlite. */
74
- close(): Promise<void>
75
- }