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,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
- }