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