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.
Files changed (172) hide show
  1. package/dist/cf-do/worker.d.ts.map +1 -1
  2. package/dist/cf-do/worker.js +9 -1
  3. package/dist/cf-do/worker.js.map +1 -1
  4. package/dist/pg-proxy-do-backend.d.ts +2 -0
  5. package/dist/pg-proxy-do-backend.d.ts.map +1 -1
  6. package/dist/pg-proxy-do-backend.js +49 -7
  7. package/dist/pg-proxy-do-backend.js.map +1 -1
  8. package/dist/pg-sqlite-compiler/catalog/seed.d.ts +67 -0
  9. package/dist/pg-sqlite-compiler/catalog/seed.d.ts.map +1 -0
  10. package/dist/pg-sqlite-compiler/catalog/seed.js +436 -0
  11. package/dist/pg-sqlite-compiler/catalog/seed.js.map +1 -0
  12. package/dist/pg-sqlite-compiler/index.d.ts +12 -0
  13. package/dist/pg-sqlite-compiler/index.d.ts.map +1 -0
  14. package/dist/pg-sqlite-compiler/index.js +59 -0
  15. package/dist/pg-sqlite-compiler/index.js.map +1 -0
  16. package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts +48 -0
  17. package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts.map +1 -0
  18. package/dist/pg-sqlite-compiler/passes/ast-utils.js +93 -0
  19. package/dist/pg-sqlite-compiler/passes/ast-utils.js.map +1 -0
  20. package/dist/pg-sqlite-compiler/passes/catalog.d.ts +34 -0
  21. package/dist/pg-sqlite-compiler/passes/catalog.d.ts.map +1 -0
  22. package/dist/pg-sqlite-compiler/passes/catalog.js +30 -0
  23. package/dist/pg-sqlite-compiler/passes/catalog.js.map +1 -0
  24. package/dist/pg-sqlite-compiler/passes/datetime.d.ts +21 -0
  25. package/dist/pg-sqlite-compiler/passes/datetime.d.ts.map +1 -0
  26. package/dist/pg-sqlite-compiler/passes/datetime.js +53 -0
  27. package/dist/pg-sqlite-compiler/passes/datetime.js.map +1 -0
  28. package/dist/pg-sqlite-compiler/passes/index.d.ts +21 -0
  29. package/dist/pg-sqlite-compiler/passes/index.d.ts.map +1 -0
  30. package/dist/pg-sqlite-compiler/passes/index.js +39 -0
  31. package/dist/pg-sqlite-compiler/passes/index.js.map +1 -0
  32. package/dist/pg-sqlite-compiler/passes/types.d.ts +41 -0
  33. package/dist/pg-sqlite-compiler/passes/types.d.ts.map +1 -0
  34. package/dist/pg-sqlite-compiler/passes/types.js +103 -0
  35. package/dist/pg-sqlite-compiler/passes/types.js.map +1 -0
  36. package/dist/pg-sqlite-compiler/test/oracle.d.ts +34 -0
  37. package/dist/pg-sqlite-compiler/test/oracle.d.ts.map +1 -0
  38. package/dist/pg-sqlite-compiler/test/oracle.js +204 -0
  39. package/dist/pg-sqlite-compiler/test/oracle.js.map +1 -0
  40. package/dist/pg-sqlite-compiler/types.d.ts +55 -0
  41. package/dist/pg-sqlite-compiler/types.d.ts.map +1 -0
  42. package/dist/pg-sqlite-compiler/types.js +2 -0
  43. package/dist/pg-sqlite-compiler/types.js.map +1 -0
  44. package/package.json +8 -4
  45. package/src/admin/admin-data.test.ts +0 -348
  46. package/src/admin/http-proxy.ts +0 -252
  47. package/src/admin/log-store.ts +0 -192
  48. package/src/admin/server.ts +0 -471
  49. package/src/admin/ui.ts +0 -1322
  50. package/src/bench/proxy-throughput.bench.ts +0 -343
  51. package/src/bench/serial-mutations.bench.ts +0 -270
  52. package/src/browser.ts +0 -203
  53. package/src/cf-do/.wrangler/cache/cf.json +0 -1
  54. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  55. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  56. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  57. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0f0f3bdf0abda097eb6f1246db4657d9fc622081362d894d82c1a1ce067b05b6.sqlite +0 -0
  58. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/1ddd3a4a48a11b51658444f5458a1fb175194b1d5b6a5bda20ef3fe3205b900c.sqlite +0 -0
  59. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/204a39120310d37e972c5914cfd71ad55c151bdb9e8ed289a5f8c5b052dd60e4.sqlite +0 -0
  60. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/3835f242df9728adba3d127a238793fd054ed3e51df3f60749ee744c469bf2a2.sqlite +0 -0
  61. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/4aa9c80eb716cf55b8995ccf7afab0b36c683e6da07d7c37a3f9c570136036df.sqlite +0 -0
  62. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/533e2fd1d6ea46e7a9a0017916ef341802d438d72583462755f2c1f8225e9bf2.sqlite +0 -0
  63. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/5ffa1aced1225ecaeac6366f7586aa3de92761cdff8711d81fbd81f248076abd.sqlite +0 -0
  64. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/686c3a9f0d7e59ed2ab607efd4b76d779c97cafeb3818380033bf7c7eb86c819.sqlite +0 -0
  65. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/6e8214e8dcfadd0deb52d64e5e9ca85c6b329ace11193909845995396914c473.sqlite +0 -0
  66. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/78d9ec9ff873d3fe3507ff53c2a6f6dfc408b4268eb0db3f2a146c0678965366.sqlite +0 -0
  67. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/7eff9f0ed7e27ad0d3f9d923de0682fab1928591172c1ba336c5f79a134a5d85.sqlite +0 -0
  68. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/836cda5b995b25867d722ed4f4c2292167e80351a3c6038db626648eb247dd8b.sqlite +0 -0
  69. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/91ef63b112209ab30172763acd8a0935106c248f7f1bcae5545ce37a9f201551.sqlite +0 -0
  70. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/a66ea4293a5f5938bc6d116edfa2522bb85bc37aea3541fbc09c3b613b9b32c0.sqlite +0 -0
  71. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/ceb2ab26b80590840b65651deb6e948d3bf81565c6751f3a58752cf4bf4aecae.sqlite +0 -0
  72. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
  73. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
  74. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
  75. package/src/cf-do/ARCHITECTURE.md +0 -83
  76. package/src/cf-do/watermark.test.ts +0 -103
  77. package/src/cf-do/watermark.ts +0 -118
  78. package/src/cf-do/worker.ts +0 -1033
  79. package/src/cf-do/wrangler.toml +0 -11
  80. package/src/cf-pglite/README.md +0 -19
  81. package/src/change-tracking.ts +0 -25
  82. package/src/child-process.test.ts +0 -147
  83. package/src/child-process.ts +0 -90
  84. package/src/cli-entry.ts +0 -72
  85. package/src/cli.test.ts +0 -38
  86. package/src/cli.ts +0 -1214
  87. package/src/config.ts +0 -150
  88. package/src/do-sql-tracking.test.ts +0 -19
  89. package/src/do-sql-tracking.ts +0 -19
  90. package/src/index.ts +0 -1215
  91. package/src/integration/integration.test.ts +0 -517
  92. package/src/integration/native-binary.guard.test.ts +0 -13
  93. package/src/integration/native-startup.test.ts +0 -44
  94. package/src/integration/replication-latency.test.ts +0 -428
  95. package/src/integration/restore-live-stress.test.ts +0 -433
  96. package/src/integration/restore-reset.test.ts +0 -400
  97. package/src/integration/restore.test.ts +0 -274
  98. package/src/integration/test-permissions.ts +0 -147
  99. package/src/load-config.ts +0 -46
  100. package/src/log.ts +0 -96
  101. package/src/mutex.ts +0 -47
  102. package/src/pg-proxy-browser.singledb.test.ts +0 -233
  103. package/src/pg-proxy-browser.ts +0 -2022
  104. package/src/pg-proxy-do-backend.test.ts +0 -3890
  105. package/src/pg-proxy-do-backend.ts +0 -7157
  106. package/src/pg-proxy.ts +0 -1087
  107. package/src/pglite-ipc.test.ts +0 -116
  108. package/src/pglite-ipc.ts +0 -266
  109. package/src/pglite-manager.ts +0 -557
  110. package/src/pglite-web-proxy.test.ts +0 -57
  111. package/src/pglite-web-proxy.ts +0 -221
  112. package/src/pglite-web-worker.ts +0 -152
  113. package/src/pglite-worker-thread.ts +0 -253
  114. package/src/port.ts +0 -25
  115. package/src/process-title.ts +0 -9
  116. package/src/recovery.ts +0 -155
  117. package/src/replication/change-tracker.test.ts +0 -357
  118. package/src/replication/change-tracker.ts +0 -279
  119. package/src/replication/handler.test.ts +0 -511
  120. package/src/replication/handler.ts +0 -1190
  121. package/src/replication/pgoutput-encoder.test.ts +0 -697
  122. package/src/replication/pgoutput-encoder.ts +0 -373
  123. package/src/replication/tcp-replication.test.ts +0 -876
  124. package/src/replication/zero-compat.test.ts +0 -1150
  125. package/src/restore-stress.test.ts +0 -188
  126. package/src/s3-local.ts +0 -203
  127. package/src/shim/hooks.mjs +0 -120
  128. package/src/shim/register.mjs +0 -4
  129. package/src/sqlite-mode/apply-mode.ts +0 -224
  130. package/src/sqlite-mode/index.ts +0 -15
  131. package/src/sqlite-mode/native-binary.ts +0 -89
  132. package/src/sqlite-mode/package-resolve.ts +0 -17
  133. package/src/sqlite-mode/resolve-mode.ts +0 -80
  134. package/src/sqlite-mode/shim-template.ts +0 -159
  135. package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
  136. package/src/sqlite-mode/types.ts +0 -30
  137. package/src/vite-plugin.ts +0 -67
  138. package/src/wasm-sqlite.test.ts +0 -537
  139. package/src/worker/browser-admin.ts +0 -52
  140. package/src/worker/browser-build-config.test.ts +0 -71
  141. package/src/worker/browser-build-config.ts +0 -109
  142. package/src/worker/browser-embed-admin.test.ts +0 -75
  143. package/src/worker/browser-embed.ts +0 -345
  144. package/src/worker/cf-patches.ts +0 -384
  145. package/src/worker/embed-integration.test.ts +0 -321
  146. package/src/worker/index.ts +0 -138
  147. package/src/worker/shims/fastify.test.ts +0 -255
  148. package/src/worker/shims/fastify.ts +0 -306
  149. package/src/worker/shims/http-service.test.ts +0 -355
  150. package/src/worker/shims/http-service.ts +0 -293
  151. package/src/worker/shims/node-stub.ts +0 -290
  152. package/src/worker/shims/oxfmt.ts +0 -3
  153. package/src/worker/shims/postgres-browser.ts +0 -59
  154. package/src/worker/shims/postgres-socket.test.ts +0 -576
  155. package/src/worker/shims/postgres-socket.ts +0 -310
  156. package/src/worker/shims/postgres.test.ts +0 -364
  157. package/src/worker/shims/postgres.ts +0 -1454
  158. package/src/worker/shims/sqlite-browser.test.ts +0 -233
  159. package/src/worker/shims/sqlite-browser.ts +0 -175
  160. package/src/worker/shims/sqlite.test.ts +0 -786
  161. package/src/worker/shims/sqlite.ts +0 -978
  162. package/src/worker/shims/stream-browser.ts +0 -15
  163. package/src/worker/shims/ws-browser.test.ts +0 -205
  164. package/src/worker/shims/ws-browser.ts +0 -248
  165. package/src/worker/shims/ws.test.ts +0 -288
  166. package/src/worker/shims/ws.ts +0 -467
  167. package/src/worker/shims/zero-process-env.ts +0 -11
  168. package/src/worker/types.ts +0 -75
  169. package/src/worker/worker-integration.test.ts +0 -223
  170. package/src/worker/worker.test.ts +0 -136
  171. package/src/worker/zero-cache-embed-cf.ts +0 -463
  172. 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
- }