orez 0.2.27 → 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 (150) hide show
  1. package/package.json +3 -4
  2. package/src/admin/admin-data.test.ts +0 -348
  3. package/src/admin/http-proxy.ts +0 -252
  4. package/src/admin/log-store.ts +0 -192
  5. package/src/admin/server.ts +0 -471
  6. package/src/admin/ui.ts +0 -1322
  7. package/src/bench/proxy-throughput.bench.ts +0 -343
  8. package/src/bench/serial-mutations.bench.ts +0 -270
  9. package/src/browser.ts +0 -203
  10. package/src/cf-do/.wrangler/cache/cf.json +0 -1
  11. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  12. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  13. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  14. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0ffaabee41a60e04dd0eb7db3073f0a40139e6a97ccd26823967acb652b89a7b.sqlite +0 -0
  15. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
  16. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
  17. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
  18. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-insertion-facade.js +0 -11
  19. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-loader.entry.ts +0 -134
  20. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-insertion-facade.js +0 -11
  21. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-loader.entry.ts +0 -134
  22. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js +0 -1059
  23. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js.map +0 -8
  24. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js +0 -1059
  25. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js.map +0 -8
  26. package/src/cf-do/ARCHITECTURE.md +0 -93
  27. package/src/cf-do/CHAT_E2E.md +0 -213
  28. package/src/cf-do/watermark.test.ts +0 -103
  29. package/src/cf-do/watermark.ts +0 -118
  30. package/src/cf-do/worker.ts +0 -1041
  31. package/src/cf-do/wrangler.toml +0 -11
  32. package/src/cf-pglite/README.md +0 -19
  33. package/src/change-tracking.ts +0 -25
  34. package/src/child-process.test.ts +0 -147
  35. package/src/child-process.ts +0 -90
  36. package/src/cli-entry.ts +0 -72
  37. package/src/cli.test.ts +0 -40
  38. package/src/cli.ts +0 -1214
  39. package/src/config.ts +0 -150
  40. package/src/do-sql-tracking.test.ts +0 -19
  41. package/src/do-sql-tracking.ts +0 -19
  42. package/src/index.ts +0 -1215
  43. package/src/integration/integration.test.ts +0 -517
  44. package/src/integration/native-binary.guard.test.ts +0 -13
  45. package/src/integration/native-startup.test.ts +0 -44
  46. package/src/integration/replication-latency.test.ts +0 -428
  47. package/src/integration/restore-live-stress.test.ts +0 -433
  48. package/src/integration/restore-reset.test.ts +0 -400
  49. package/src/integration/restore.test.ts +0 -274
  50. package/src/integration/test-permissions.ts +0 -147
  51. package/src/load-config.ts +0 -46
  52. package/src/log.ts +0 -96
  53. package/src/mutex.ts +0 -47
  54. package/src/pg-proxy-browser.singledb.test.ts +0 -233
  55. package/src/pg-proxy-browser.ts +0 -2022
  56. package/src/pg-proxy-do-backend.test.ts +0 -3890
  57. package/src/pg-proxy-do-backend.ts +0 -7191
  58. package/src/pg-proxy.ts +0 -1087
  59. package/src/pg-sqlite-compiler/README.md +0 -53
  60. package/src/pg-sqlite-compiler/catalog/seed.ts +0 -524
  61. package/src/pg-sqlite-compiler/fixtures/pgsqlite/arithmetic.json +0 -307
  62. package/src/pg-sqlite-compiler/fixtures/pgsqlite/array.json +0 -377
  63. package/src/pg-sqlite-compiler/fixtures/pgsqlite/cast.json +0 -12
  64. package/src/pg-sqlite-compiler/fixtures/pgsqlite/catalog.json +0 -447
  65. package/src/pg-sqlite-compiler/fixtures/pgsqlite/create-table.json +0 -32
  66. package/src/pg-sqlite-compiler/fixtures/pgsqlite/datetime.json +0 -397
  67. package/src/pg-sqlite-compiler/fixtures/pgsqlite/enum.json +0 -337
  68. package/src/pg-sqlite-compiler/fixtures/pgsqlite/insert.json +0 -337
  69. package/src/pg-sqlite-compiler/fixtures/pgsqlite/json.json +0 -537
  70. package/src/pg-sqlite-compiler/fixtures/pgsqlite/misc.json +0 -1837
  71. package/src/pg-sqlite-compiler/index.ts +0 -73
  72. package/src/pg-sqlite-compiler/integration.test.ts +0 -136
  73. package/src/pg-sqlite-compiler/passes/ast-utils.ts +0 -113
  74. package/src/pg-sqlite-compiler/passes/catalog.ts +0 -65
  75. package/src/pg-sqlite-compiler/passes/datetime.ts +0 -74
  76. package/src/pg-sqlite-compiler/passes/index.ts +0 -49
  77. package/src/pg-sqlite-compiler/passes/types.ts +0 -156
  78. package/src/pg-sqlite-compiler/smoke.test.ts +0 -69
  79. package/src/pg-sqlite-compiler/test/catalog.test.ts +0 -171
  80. package/src/pg-sqlite-compiler/test/corpus.test.ts +0 -161
  81. package/src/pg-sqlite-compiler/test/datetime.oracle.test.ts +0 -102
  82. package/src/pg-sqlite-compiler/test/oracle.ts +0 -237
  83. package/src/pg-sqlite-compiler/test/types.test.ts +0 -109
  84. package/src/pg-sqlite-compiler/types.ts +0 -63
  85. package/src/pglite-ipc.test.ts +0 -116
  86. package/src/pglite-ipc.ts +0 -266
  87. package/src/pglite-manager.ts +0 -557
  88. package/src/pglite-web-proxy.test.ts +0 -57
  89. package/src/pglite-web-proxy.ts +0 -221
  90. package/src/pglite-web-worker.ts +0 -152
  91. package/src/pglite-worker-thread.ts +0 -253
  92. package/src/port.ts +0 -25
  93. package/src/process-title.ts +0 -9
  94. package/src/recovery.ts +0 -155
  95. package/src/replication/change-tracker.test.ts +0 -357
  96. package/src/replication/change-tracker.ts +0 -279
  97. package/src/replication/handler.test.ts +0 -511
  98. package/src/replication/handler.ts +0 -1190
  99. package/src/replication/pgoutput-encoder.test.ts +0 -697
  100. package/src/replication/pgoutput-encoder.ts +0 -373
  101. package/src/replication/tcp-replication.test.ts +0 -876
  102. package/src/replication/zero-compat.test.ts +0 -1150
  103. package/src/restore-stress.test.ts +0 -188
  104. package/src/s3-local.ts +0 -203
  105. package/src/shim/hooks.mjs +0 -120
  106. package/src/shim/register.mjs +0 -4
  107. package/src/sqlite-mode/apply-mode.ts +0 -224
  108. package/src/sqlite-mode/index.ts +0 -15
  109. package/src/sqlite-mode/native-binary.ts +0 -89
  110. package/src/sqlite-mode/package-resolve.ts +0 -17
  111. package/src/sqlite-mode/resolve-mode.ts +0 -80
  112. package/src/sqlite-mode/shim-template.ts +0 -159
  113. package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
  114. package/src/sqlite-mode/types.ts +0 -30
  115. package/src/vite-plugin.ts +0 -67
  116. package/src/wasm-sqlite.test.ts +0 -537
  117. package/src/worker/browser-admin.ts +0 -52
  118. package/src/worker/browser-build-config.test.ts +0 -71
  119. package/src/worker/browser-build-config.ts +0 -109
  120. package/src/worker/browser-embed-admin.test.ts +0 -75
  121. package/src/worker/browser-embed.ts +0 -345
  122. package/src/worker/cf-patches.ts +0 -384
  123. package/src/worker/embed-integration.test.ts +0 -321
  124. package/src/worker/index.ts +0 -138
  125. package/src/worker/shims/fastify.test.ts +0 -255
  126. package/src/worker/shims/fastify.ts +0 -306
  127. package/src/worker/shims/http-service.test.ts +0 -355
  128. package/src/worker/shims/http-service.ts +0 -293
  129. package/src/worker/shims/node-stub.ts +0 -290
  130. package/src/worker/shims/oxfmt.ts +0 -3
  131. package/src/worker/shims/postgres-browser.ts +0 -59
  132. package/src/worker/shims/postgres-socket.test.ts +0 -576
  133. package/src/worker/shims/postgres-socket.ts +0 -310
  134. package/src/worker/shims/postgres.test.ts +0 -364
  135. package/src/worker/shims/postgres.ts +0 -1454
  136. package/src/worker/shims/sqlite-browser.test.ts +0 -233
  137. package/src/worker/shims/sqlite-browser.ts +0 -175
  138. package/src/worker/shims/sqlite.test.ts +0 -786
  139. package/src/worker/shims/sqlite.ts +0 -978
  140. package/src/worker/shims/stream-browser.ts +0 -15
  141. package/src/worker/shims/ws-browser.test.ts +0 -205
  142. package/src/worker/shims/ws-browser.ts +0 -248
  143. package/src/worker/shims/ws.test.ts +0 -288
  144. package/src/worker/shims/ws.ts +0 -467
  145. package/src/worker/shims/zero-process-env.ts +0 -11
  146. package/src/worker/types.ts +0 -75
  147. package/src/worker/worker-integration.test.ts +0 -223
  148. package/src/worker/worker.test.ts +0 -136
  149. package/src/worker/zero-cache-embed-cf.ts +0 -463
  150. package/src/worker/zero-cache-embed.ts +0 -277
@@ -1,463 +0,0 @@
1
- /**
2
- * zero-cache embedded runner for cloudflare workers.
3
- *
4
- * runs zero-cache in-process with SINGLE_PROCESS=1, using bundler aliases
5
- * to swap Node.js dependencies for CF-compatible shims:
6
- *
7
- * postgres → orez/worker/shims/postgres-browser
8
- * (real postgres package over MessagePort)
9
- * @rocicorp/zero-sqlite3 → orez/worker/shims/sqlite (DO SQLite)
10
- * fastify → orez/worker/shims/fastify (route capture)
11
- * ws → orez/worker/shims/ws (CF WebSocket)
12
- *
13
- * the postgres MessagePort proxy is backed by DoBackend, so zero-cache still
14
- * uses its real PG wire protocol, but storage is Cloudflare DO SQLite instead
15
- * of PGlite.
16
- *
17
- * usage in a Durable Object:
18
- *
19
- * import { startZeroCacheEmbedCF } from 'orez/worker'
20
- *
21
- * // in ensureInitialized():
22
- * const zc = await startZeroCacheEmbedCF({ ... })
23
- *
24
- * // in DO fetch():
25
- * return zc.handleRequest(request)
26
- */
27
-
28
- import './shims/zero-process-env.js'
29
-
30
- import EventEmitter from 'node:events'
31
-
32
- // static import so wrangler can follow the dependency tree and bundle
33
- // zero-cache with all its transitive deps + our shim aliases.
34
- // @ts-expect-error — internal zero-cache module, no type declarations
35
- import { runWorker as _runWorker } from '@rocicorp/zero/out/zero-cache/src/server/runner/run-worker.js'
36
-
37
- import { createBrowserProxy, type BrowserProxy } from '../pg-proxy-browser.js'
38
- import { DoBackend } from '../pg-proxy-do-backend.js'
39
-
40
- const runWorkerFn = _runWorker as (
41
- parent: unknown,
42
- env: Record<string, string>
43
- ) => Promise<void>
44
-
45
- export interface ZeroCacheEmbedCFOptions {
46
- /** DO SQLite storage (also registered on globalThis.__orez_do_sqlite) */
47
- doSqlite: unknown
48
-
49
- /**
50
- * base URL for the DO SQL execution endpoints (`/exec`, `/batch`).
51
- * ignored when `backends` is supplied.
52
- */
53
- backendUrl?: string
54
-
55
- /** custom fetch used by DoBackend; lets a DO route directly to another DO stub. */
56
- backendFetch?: typeof fetch
57
-
58
- /** namespace sent to the DO SQL endpoints. */
59
- backendNamespace?: string
60
-
61
- /** pre-created DoBackend instances. mainly useful for tests. */
62
- backends?: {
63
- postgres: DoBackend
64
- cvr: DoBackend
65
- cdb: DoBackend
66
- }
67
-
68
- /** postgres username/password expected by the in-process proxy. */
69
- pgUser?: string
70
- pgPassword?: string
71
-
72
- /** zero app ID (default: 'zero') */
73
- appId?: string
74
-
75
- /** publication names */
76
- publications?: string[]
77
-
78
- /** additional env vars passed to zero-cache */
79
- env?: Record<string, string>
80
-
81
- /** fetch implementation for Worker-local mutate/query API URLs. */
82
- apiFetch?: typeof fetch
83
-
84
- /** timeout in ms waiting for zero-cache ready (default: 30000) */
85
- readyTimeout?: number
86
- }
87
-
88
- export interface ZeroCacheEmbedCF {
89
- /** whether zero-cache is ready */
90
- readonly ready: boolean
91
-
92
- /**
93
- * handle an incoming request from the DO's fetch() handler.
94
- * routes HTTP to zero-cache's Fastify handlers, WebSocket
95
- * upgrades through the zero-cache handoff mechanism.
96
- */
97
- handleRequest(request: Request): Promise<Response>
98
-
99
- /** stop zero-cache */
100
- stop(): Promise<void>
101
- }
102
-
103
- /**
104
- * start zero-cache in embedded CF Workers mode.
105
- *
106
- * must be called with a DO SQLite handle for zero-cache's replica storage and
107
- * a DoBackend target for upstream/CVR/change Postgres connections.
108
- */
109
- export async function startZeroCacheEmbedCF(
110
- opts: ZeroCacheEmbedCFOptions
111
- ): Promise<ZeroCacheEmbedCF> {
112
- const appId = opts.appId || 'zero'
113
- const publications = opts.publications?.join(',') || `orez_${appId}_public`
114
- const readyTimeout = opts.readyTimeout ?? 30000
115
- const pgUser = opts.pgUser || 'user'
116
- const pgPassword = opts.pgPassword || ''
117
- const backendUrl = opts.backendUrl || 'https://orez-do-backend.local'
118
- const backendNamespace = opts.backendNamespace || appId
119
-
120
- const backends =
121
- opts.backends ??
122
- ({
123
- postgres: new DoBackend(backendUrl, 'postgres', backendNamespace, {
124
- fetch: opts.backendFetch,
125
- }),
126
- cvr: new DoBackend(backendUrl, 'zero_cvr', backendNamespace, {
127
- fetch: opts.backendFetch,
128
- }),
129
- cdb: new DoBackend(backendUrl, 'zero_cdb', backendNamespace, {
130
- fetch: opts.backendFetch,
131
- }),
132
- } satisfies NonNullable<ZeroCacheEmbedCFOptions['backends']>)
133
-
134
- await Promise.all([
135
- backends.postgres.waitReady,
136
- backends.cvr.waitReady,
137
- backends.cdb.waitReady,
138
- ])
139
-
140
- const proxy: BrowserProxy = await createBrowserProxy(
141
- {
142
- postgres: backends.postgres as any,
143
- cvr: backends.cvr as any,
144
- cdb: backends.cdb as any,
145
- postgresReplicas: [],
146
- } as any,
147
- {
148
- pgUser,
149
- pgPassword,
150
- singleDb: false,
151
- logLevel: opts.env?.ZERO_LOG_LEVEL || 'info',
152
- }
153
- )
154
-
155
- // ensure globals are set for shims
156
- ;(globalThis as any).__orez_do_sqlite = opts.doSqlite
157
- ;(globalThis as any).__orez_proxy_connect = (port: MessagePort) => {
158
- proxy.handleConnection(port)
159
- }
160
- ;(globalThis as any).__orez_proxy_user = pgUser
161
- ;(globalThis as any).__orez_proxy_password = pgPassword
162
-
163
- // ensure process.env exists (CF Workers doesn't have it natively)
164
- ;(globalThis as any).process ??= {}
165
- ;(globalThis as any).process.env ??= {}
166
- ;(globalThis as any).process.pid ??= 1
167
- ;(globalThis as any).process.argv ??= []
168
-
169
- // CRITICAL: set SINGLE_PROCESS before importing zero-cache.
170
- // zero-cache's childWorker() checks process.env.SINGLE_PROCESS directly.
171
- ;(globalThis as any).process.env.SINGLE_PROCESS = '1'
172
- ;(globalThis as any).process.env.NODE_ENV = 'development'
173
-
174
- // shim process.kill (used by HeartbeatMonitor) to be a no-op
175
- ;(globalThis as any).process.kill ??= () => {}
176
-
177
- // create fake parent EventEmitter for zero-cache's runWorker()
178
- // must be declared before process.exit shim (which references it)
179
- const parent = new EventEmitter() as EventEmitter & {
180
- send: (msg: unknown) => boolean
181
- kill: (signal?: string) => void
182
- pid: number
183
- }
184
-
185
- const parentEmitter = new EventEmitter()
186
-
187
- parent.send = (message: unknown, sendHandle?: unknown) => {
188
- parentEmitter.emit('message', message, sendHandle)
189
- return true
190
- }
191
- parent.kill = (signal = 'SIGTERM') => {
192
- parent.emit(signal, signal)
193
- }
194
- parent.pid = (globalThis as any).process.pid ?? 1
195
-
196
- // shim process.exit to emit on parent instead of actually exiting
197
- const origExit = (globalThis as any).process.exit
198
- const origNodeEnv = (globalThis as any).process.env.NODE_ENV
199
- const origKill = (globalThis as any).process.kill
200
- const origFetch = (globalThis as any).fetch
201
- ;(globalThis as any).process.exit = (code?: number) => {
202
- parent.emit('exit', code ?? 0)
203
- }
204
- if (opts.apiFetch) {
205
- ;(globalThis as any).fetch = (input: RequestInfo | URL, init?: RequestInit) => {
206
- const request = new Request(input, init)
207
- const url = new URL(request.url)
208
- if (url.hostname === 'orez-zero-api.local') return opts.apiFetch!(request)
209
- return origFetch(input as any, init as any)
210
- }
211
- }
212
-
213
- // build env for zero-cache
214
- const env: Record<string, string> = {
215
- ...((globalThis as any).process.env as Record<string, string>),
216
- SINGLE_PROCESS: '1',
217
- NODE_ENV: 'development',
218
- // postgres-browser intercepts these URLs and routes PG wire over
219
- // MessagePort to the DoBackend-backed proxy above.
220
- ZERO_UPSTREAM_DB: `postgres://${pgUser}:ignored@127.0.0.1/postgres`,
221
- ZERO_CVR_DB: `postgres://${pgUser}:ignored@127.0.0.1/zero_cvr`,
222
- ZERO_CHANGE_DB: `postgres://${pgUser}:ignored@127.0.0.1/zero_cdb`,
223
- // this path is intercepted by the sqlite shim
224
- ZERO_REPLICA_FILE: ':do-sqlite:',
225
- // don't bind a port — we route via inject/handoff
226
- ZERO_PORT: '0',
227
- ZERO_APP_ID: appId,
228
- ZERO_APP_PUBLICATIONS: publications,
229
- ZERO_ADMIN_PASSWORD: opts.env?.ZERO_ADMIN_PASSWORD || crypto.randomUUID(),
230
- ZERO_LOG_LEVEL: opts.env?.ZERO_LOG_LEVEL || 'info',
231
- ZERO_NUM_SYNC_WORKERS: opts.env?.ZERO_NUM_SYNC_WORKERS || '1',
232
- ZERO_ENABLE_QUERY_PLANNER: 'false',
233
- ...opts.env,
234
- }
235
- Object.assign((globalThis as any).process.env, env)
236
-
237
- const debugEmbed =
238
- env.OREZ_DEBUG_EMBED === '1' || (globalThis as any).__OREZ_DEBUG_EMBED__ === true
239
-
240
- // wrap parent with onMessageType/onceMessageType helpers
241
- // must forward sendHandle (second arg) for WebSocket handoff
242
- const wrappedParent = new Proxy(parent, {
243
- get(target, prop, receiver) {
244
- if (prop === 'onMessageType') {
245
- return (type: string, handler: (msg: unknown, sendHandle?: unknown) => void) => {
246
- target.on('message', (data: unknown, sendHandle?: unknown) => {
247
- if (Array.isArray(data) && data.length === 2 && data[0] === type) {
248
- handler(data[1], sendHandle)
249
- }
250
- })
251
- return receiver
252
- }
253
- }
254
- if (prop === 'onceMessageType') {
255
- return (type: string, handler: (msg: unknown, sendHandle?: unknown) => void) => {
256
- const listener = (data: unknown, sendHandle?: unknown) => {
257
- if (Array.isArray(data) && data.length === 2 && data[0] === type) {
258
- target.off('message', listener)
259
- handler(data[1], sendHandle)
260
- }
261
- }
262
- target.on('message', listener)
263
- return receiver
264
- }
265
- }
266
- return Reflect.get(target, prop, receiver)
267
- },
268
- })
269
-
270
- // track state
271
- let isReady = false
272
- let runWorkerPromise: Promise<void> | null = null
273
-
274
- // capture the Fastify shim instance from zero-cache's HttpService.
275
- // the fastify shim stores itself on globalThis when created.
276
- let fastifyInstance: any = null
277
-
278
- // wait for "ready" message
279
- const readyPromise = new Promise<void>((resolve, reject) => {
280
- const timeout = setTimeout(() => {
281
- reject(
282
- new Error(
283
- `zero-cache CF embed: timed out waiting for ready after ${readyTimeout}ms`
284
- )
285
- )
286
- }, readyTimeout)
287
-
288
- parentEmitter.on('message', (msg: unknown) => {
289
- if (debugEmbed) console.debug('[orez-zero-cache-cf] parent message', msg)
290
- if (Array.isArray(msg) && msg[0] === 'ready') {
291
- clearTimeout(timeout)
292
- isReady = true
293
- resolve()
294
- }
295
- })
296
- })
297
-
298
- // start zero-cache
299
- runWorkerPromise = runWorkerFn(wrappedParent, env).catch((err) => {
300
- if (debugEmbed) console.error('[orez-zero-cache-cf] runWorker error', err)
301
- if (!isReady) {
302
- throw err
303
- }
304
- // after ready, errors during shutdown are expected
305
- })
306
-
307
- // wait for ready
308
- await readyPromise
309
-
310
- // get the fastify instance (set by our shim during init)
311
- fastifyInstance = (globalThis as any).__orez_fastify_instance
312
-
313
- return {
314
- get ready() {
315
- return isReady
316
- },
317
-
318
- async handleRequest(request: Request): Promise<Response> {
319
- if (!isReady) {
320
- return new Response('zero-cache not ready', { status: 503 })
321
- }
322
-
323
- const url = new URL(request.url)
324
- const isUpgrade =
325
- request.headers.get('upgrade')?.toLowerCase() === 'websocket' ||
326
- request.headers.get('x-soot-ws-upgrade') === 'true'
327
-
328
- if (isUpgrade) {
329
- return handleWebSocketUpgrade(request, url, fastifyInstance)
330
- }
331
-
332
- return handleHttpRequest(request, url, fastifyInstance)
333
- },
334
-
335
- async stop() {
336
- isReady = false
337
- wrappedParent.kill('SIGTERM')
338
- if (runWorkerPromise) {
339
- await Promise.race([runWorkerPromise, new Promise((r) => setTimeout(r, 5000))])
340
- }
341
- await new Promise((r) => setTimeout(r, 200))
342
- proxy.close()
343
- await Promise.all([
344
- backends.postgres.close(),
345
- backends.cvr.close(),
346
- backends.cdb.close(),
347
- ])
348
- // restore all modified globals
349
- if (origExit) {
350
- ;(globalThis as any).process.exit = origExit
351
- }
352
- if (origNodeEnv !== undefined) {
353
- ;(globalThis as any).process.env.NODE_ENV = origNodeEnv
354
- }
355
- if (origKill) {
356
- ;(globalThis as any).process.kill = origKill
357
- }
358
- if (opts.apiFetch) {
359
- ;(globalThis as any).fetch = origFetch
360
- }
361
- delete (globalThis as any).process.env.SINGLE_PROCESS
362
- delete (globalThis as any).__orez_proxy_connect
363
- delete (globalThis as any).__orez_proxy_user
364
- delete (globalThis as any).__orez_proxy_password
365
- },
366
- }
367
- }
368
-
369
- // -- HTTP request handling --
370
- // routes through the Fastify shim's inject() method
371
-
372
- async function handleHttpRequest(
373
- request: Request,
374
- url: URL,
375
- fastify: any
376
- ): Promise<Response> {
377
- if (!fastify?.inject) {
378
- return new Response('fastify not available', { status: 503 })
379
- }
380
-
381
- const headers: Record<string, string> = {}
382
- request.headers.forEach((value, key) => {
383
- headers[key] = value
384
- })
385
-
386
- let payload: string | null = null
387
- if (request.method !== 'GET' && request.method !== 'HEAD' && request.body) {
388
- payload = await request.text()
389
- }
390
-
391
- const result = await fastify.inject({
392
- method: request.method,
393
- url: url.pathname + url.search,
394
- headers,
395
- payload,
396
- })
397
-
398
- return new Response(result.body, {
399
- status: result.statusCode,
400
- headers: result.headers,
401
- })
402
- }
403
-
404
- // -- WebSocket upgrade handling --
405
- // creates WebSocketPair and feeds the server socket into zero-cache's
406
- // handoff mechanism via the Fastify shim's server EventEmitter.
407
-
408
- function handleWebSocketUpgrade(request: Request, url: URL, fastify: any): Response {
409
- const WsPair = (globalThis as any).WebSocketPair
410
- if (!WsPair) {
411
- return new Response('WebSocketPair not available', { status: 500 })
412
- }
413
-
414
- const pair = new WsPair()
415
- const [client, server] = Object.values(pair) as [any, any]
416
-
417
- // accept the server side (CF Workers requirement)
418
- server.accept()
419
-
420
- // build a serializable request object for the handoff
421
- const headers: Record<string, string> = {}
422
- request.headers.forEach((value, key) => {
423
- headers[key] = value
424
- })
425
-
426
- const message = {
427
- url: url.pathname + url.search,
428
- headers,
429
- method: 'GET',
430
- }
431
-
432
- // emit handoff on the Fastify server's EventEmitter.
433
- // installWebSocketHandoff (non-Server branch) listens for this:
434
- // source.onMessageType("handoff", (msg, socket) => { ... })
435
- if (fastify?.server) {
436
- fastify.server.emit(
437
- 'message',
438
- ['handoff', { message, head: new Uint8Array(0) }],
439
- server // the CF WebSocket as sendHandle
440
- )
441
- }
442
-
443
- // return 101 with client socket
444
- // must echo Sec-WebSocket-Protocol — browsers reject the upgrade without it
445
- const secProtocol = request.headers.get('sec-websocket-protocol')
446
- const upgradeHeaders: Record<string, string> = {}
447
- if (secProtocol) {
448
- upgradeHeaders['Sec-WebSocket-Protocol'] = secProtocol
449
- }
450
- try {
451
- return new Response(null, {
452
- status: 101,
453
- headers: upgradeHeaders,
454
- // @ts-expect-error CF Workers Response extension
455
- webSocket: client,
456
- })
457
- } catch {
458
- const resp = new Response(null, { status: 200 })
459
- ;(resp as any).__orez_websocket = client
460
- ;(resp as any).__orez_ws_upgrade = true
461
- return resp
462
- }
463
- }