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,384 +0,0 @@
1
- /**
2
- * zero-cache CF Workers patches.
3
- *
4
- * applies patches to @rocicorp/zero's internal files so zero-cache
5
- * can run in SINGLE_PROCESS mode on CF Workers where dynamic import()
6
- * doesn't work.
7
- *
8
- * five patches:
9
- * 1. worker-urls.js — replace file:// URLs with zero-worker:// identifiers
10
- * 2. server worker entrypoints — disable CLI auto-start blocks
11
- * 3. processes.js — replace dynamic import() with static worker module lookup
12
- * 4. write-worker-client.js — run zero-cache's replica writer in-process
13
- * 5. pgsql-parser — embed libpg-query wasm bytes for Workers
14
- *
15
- * usage in a post-build script:
16
- *
17
- * import { patchZeroCacheForCF } from 'orez/worker/cf-patches'
18
- * patchZeroCacheForCF('./node_modules')
19
- *
20
- * idempotent: safe to run multiple times.
21
- */
22
-
23
- import { readFileSync, writeFileSync, existsSync } from 'node:fs'
24
- import { resolve } from 'node:path'
25
-
26
- export function patchZeroCacheForCF(nodeModulesPath: string): void {
27
- const zcBase = resolve(nodeModulesPath, '@rocicorp', 'zero', 'out', 'zero-cache', 'src')
28
-
29
- patchWorkerUrls(zcBase)
30
- patchWorkerEntrypoints(zcBase)
31
- patchProcesses(zcBase)
32
- patchWriteWorkerClient(zcBase)
33
- patchPgsqlParserWasm(nodeModulesPath)
34
- }
35
-
36
- function patchWorkerUrls(zcBase: string): void {
37
- const workerUrlsPath = resolve(zcBase, 'server', 'worker-urls.js')
38
- if (!existsSync(workerUrlsPath)) {
39
- console.warn('[orez] worker-urls.js not found at', workerUrlsPath)
40
- return
41
- }
42
-
43
- const content = readFileSync(workerUrlsPath, 'utf-8')
44
-
45
- // skip if already patched
46
- if (content.includes('zero-worker://')) {
47
- return
48
- }
49
-
50
- writeFileSync(
51
- workerUrlsPath,
52
- `// patched by orez for CF Workers (replaces file:// URLs with identifiers)
53
- const u = (n) => new URL("zero-worker://" + n);
54
- export const MAIN_URL = u("main");
55
- export const CHANGE_STREAMER_URL = u("change-streamer");
56
- export const REAPER_URL = u("reaper");
57
- export const REPLICATOR_URL = u("replicator");
58
- export const SYNCER_URL = u("syncer");
59
- // write-worker is spawned via 'new Worker()' (node:worker_threads), not via
60
- // childWorker() — it uses its own URL → worker resolution path. we still expose
61
- // it here so write-worker-client.js can import it without throwing.
62
- export const WRITE_WORKER_URL = u("write-worker");
63
- `
64
- )
65
- console.log('[orez] patched zero-cache worker-urls.js')
66
- }
67
-
68
- function patchWorkerEntrypoints(zcBase: string): void {
69
- const entrypoints = ['main', 'change-streamer', 'reaper', 'replicator', 'syncer']
70
-
71
- for (const entrypoint of entrypoints) {
72
- const entrypointPath = resolve(zcBase, 'server', `${entrypoint}.js`)
73
- if (!existsSync(entrypointPath)) {
74
- console.warn('[orez] zero-cache worker entrypoint not found at', entrypointPath)
75
- continue
76
- }
77
-
78
- let code = readFileSync(entrypointPath, 'utf-8')
79
- if (code.includes('orez-disable-autostart')) {
80
- continue
81
- }
82
-
83
- const next = code.replace(
84
- /if \(!singleProcessMode\(\)\) exitAfter\(\(\) => runWorker\(must\(parentWorker\), process\.env(?:, \.\.\.process\.argv\.slice\(2\))?\)\);/g,
85
- '// orez-disable-autostart: childWorker invokes runWorker explicitly in CF embeds.'
86
- )
87
-
88
- if (next === code) {
89
- console.warn(
90
- `[orez] could not find auto-start guard in ${entrypoint}.js. ` +
91
- 'zero-cache version may have changed — check compatibility.'
92
- )
93
- continue
94
- }
95
-
96
- code = next
97
- writeFileSync(entrypointPath, code)
98
- console.log(`[orez] patched zero-cache ${entrypoint}.js (disabled auto-start)`)
99
- }
100
- }
101
-
102
- function patchProcesses(zcBase: string): void {
103
- const processesPath = resolve(zcBase, 'types', 'processes.js')
104
- if (!existsSync(processesPath)) {
105
- console.warn('[orez] processes.js not found at', processesPath)
106
- return
107
- }
108
-
109
- let code = readFileSync(processesPath, 'utf-8')
110
-
111
- // skip if already patched
112
- if (code.includes('__zc_workers')) {
113
- return
114
- }
115
-
116
- // add static imports of all zero-cache worker modules at the top.
117
- // these are relative to processes.js location in @rocicorp/zero.
118
- // NOTE: mutator.js and write-worker.js don't export a default `runWorker`
119
- // (mutator runs via auto-run guard, write-worker spawns via node:worker_threads
120
- // not via childWorker()), so they're not in the lookup table.
121
- const workerImports = `\
122
- // patched by orez for CF Workers (static imports replace dynamic import())
123
- import { default as __zc_main } from "../server/main.js";
124
- import { default as __zc_change_streamer } from "../server/change-streamer.js";
125
- import { default as __zc_reaper } from "../server/reaper.js";
126
- import { default as __zc_replicator } from "../server/replicator.js";
127
- import { default as __zc_syncer } from "../server/syncer.js";
128
- const __zc_workers = {
129
- "main": __zc_main,
130
- "change-streamer": __zc_change_streamer,
131
- "reaper": __zc_reaper,
132
- "replicator": __zc_replicator,
133
- "syncer": __zc_syncer,
134
- };
135
- `
136
-
137
- // replace the dynamic import in childWorker with a synchronous lookup.
138
- // original: import(moduleUrl.href).then(async ({ default: runWorker }) => ...
139
- // patched: lookup __zc_workers by name, then continue as before
140
- const dynamicImportPattern =
141
- 'import(moduleUrl.href).then(async ({ default: runWorker })'
142
- const staticLookup =
143
- '((async () => { ' +
144
- 'const _name = moduleUrl.hostname || moduleUrl.pathname.split("/").pop()?.replace(".js",""); ' +
145
- 'if (process.env.OREZ_DEBUG_WIRE === "1" || globalThis.__OREZ_DEBUG_WIRE__ === true) console.debug("[orez-zc-worker] start", _name, args); ' +
146
- 'const runWorker = __zc_workers[_name]; ' +
147
- 'if (!runWorker) throw new Error("orez: unknown zero-cache worker: " + _name + " (available: " + Object.keys(__zc_workers).join(", ") + ")"); ' +
148
- 'return { default: runWorker, name: _name }; ' +
149
- '})()).then(async ({ default: runWorker, name })'
150
-
151
- if (!code.includes(dynamicImportPattern)) {
152
- console.warn(
153
- '[orez] could not find dynamic import pattern in processes.js. ' +
154
- 'zero-cache version may have changed — check compatibility.'
155
- )
156
- return
157
- }
158
-
159
- code = workerImports + code.replace(dynamicImportPattern, staticLookup)
160
- writeFileSync(processesPath, code)
161
- console.log('[orez] patched zero-cache processes.js (static worker imports)')
162
- }
163
-
164
- function patchWriteWorkerClient(zcBase: string): void {
165
- const clientPath = resolve(zcBase, 'services', 'replicator', 'write-worker-client.js')
166
- if (!existsSync(clientPath)) {
167
- console.warn('[orez] write-worker-client.js not found at', clientPath)
168
- return
169
- }
170
-
171
- let code = readFileSync(clientPath, 'utf-8')
172
- if (
173
- code.includes('orez-inline-write-worker') &&
174
- code.includes('__orez_zero_sqlite_role')
175
- ) {
176
- return
177
- }
178
-
179
- if (
180
- !code.includes('orez-inline-write-worker') &&
181
- !code.includes('import { Worker } from "node:worker_threads";')
182
- ) {
183
- console.warn(
184
- '[orez] could not find node:worker_threads import in write-worker-client.js. ' +
185
- 'zero-cache version may have changed — check compatibility.'
186
- )
187
- return
188
- }
189
-
190
- writeFileSync(
191
- clientPath,
192
- `// patched by orez for CF Workers (orez-inline-write-worker)
193
- import { must } from "../../../../shared/src/must.js";
194
- import { Database } from "../../../../zqlite/src/db.js";
195
- import { createLogContext } from "../../server/logging.js";
196
- import { StatementRunner } from "../../db/statements.js";
197
- import { getSubscriptionState } from "./schema/replication-state.js";
198
- import { ChangeProcessor } from "./change-processor.js";
199
-
200
- function applyPragmas(db, pragmas) {
201
- db.pragma(\`busy_timeout = \${pragmas.busyTimeout}\`);
202
- db.pragma(\`analysis_limit = \${pragmas.analysisLimit}\`);
203
- if (pragmas.walAutocheckpoint !== void 0) {
204
- db.pragma(\`wal_autocheckpoint = \${pragmas.walAutocheckpoint}\`);
205
- }
206
- }
207
-
208
- function createAPI(onWriteError) {
209
- let db;
210
- let runner;
211
- let processor;
212
- let mode;
213
- let lc;
214
-
215
- function createProcessor() {
216
- processor = new ChangeProcessor(must(runner), must(mode), (_lc, err) => {
217
- onWriteError(err instanceof Error ? err : new Error(String(err)));
218
- });
219
- }
220
-
221
- return {
222
- init(dbPath, cpMode, pragmas, logConfig) {
223
- lc = createLogContext({ log: logConfig }, { worker: "write-worker" });
224
- const previousRole = globalThis.__orez_zero_sqlite_role;
225
- globalThis.__orez_zero_sqlite_role = "replica-writer";
226
- try {
227
- db = new Database(lc, dbPath);
228
- } finally {
229
- if (previousRole === void 0) {
230
- delete globalThis.__orez_zero_sqlite_role;
231
- } else {
232
- globalThis.__orez_zero_sqlite_role = previousRole;
233
- }
234
- }
235
- applyPragmas(db, pragmas);
236
- runner = new StatementRunner(db);
237
- mode = cpMode;
238
- createProcessor();
239
- },
240
- getSubscriptionState() {
241
- return getSubscriptionState(must(runner));
242
- },
243
- processMessage(downstream) {
244
- return must(processor).processMessage(must(lc), downstream);
245
- },
246
- abort() {
247
- must(processor).abort(must(lc));
248
- createProcessor();
249
- },
250
- stop() {
251
- db?.close();
252
- db = void 0;
253
- runner = void 0;
254
- processor = void 0;
255
- },
256
- };
257
- }
258
-
259
- class ThreadWriteWorkerClient {
260
- #api;
261
- #errorHandler = () => {};
262
- #writeError = null;
263
-
264
- constructor() {
265
- this.#api = createAPI((err) => {
266
- this.#writeError = err;
267
- this.#errorHandler(err);
268
- });
269
- }
270
-
271
- async #call(method, args) {
272
- if (this.#writeError) throw this.#writeError;
273
- try {
274
- const result = this.#api[method](...args);
275
- if (this.#writeError) throw this.#writeError;
276
- return result;
277
- } catch (err) {
278
- throw err instanceof Error ? err : new Error(String(err));
279
- }
280
- }
281
-
282
- init(dbPath, mode, pragmas, logConfig) {
283
- return this.#call("init", [dbPath, mode, pragmas, logConfig]);
284
- }
285
-
286
- getSubscriptionState() {
287
- return this.#call("getSubscriptionState", []);
288
- }
289
-
290
- processMessage(downstream) {
291
- return this.#call("processMessage", [downstream]);
292
- }
293
-
294
- abort() {
295
- if (!this.#writeError) {
296
- try {
297
- this.#api.abort();
298
- } catch {
299
- }
300
- }
301
- }
302
-
303
- async stop() {
304
- await this.#call("stop", []);
305
- }
306
-
307
- onError(handler) {
308
- this.#errorHandler = handler;
309
- }
310
- }
311
-
312
- export { ThreadWriteWorkerClient, applyPragmas };
313
- `
314
- )
315
- console.log('[orez] patched zero-cache write-worker-client.js (inline writer)')
316
- }
317
-
318
- function patchPgsqlParserWasm(nodeModulesPath: string): void {
319
- const parserIndexPath = resolve(nodeModulesPath, 'libpg-query', 'wasm', 'index.js')
320
- const wasmPath = resolve(nodeModulesPath, 'libpg-query', 'wasm', 'libpg-query.wasm')
321
-
322
- if (!existsSync(parserIndexPath) || !existsSync(wasmPath)) {
323
- console.warn('[orez] libpg-query wasm files not found under', nodeModulesPath)
324
- return
325
- }
326
-
327
- let code = readFileSync(parserIndexPath, 'utf-8')
328
- if (
329
- code.includes('orez-libpg-query-wasm-binary') &&
330
- code.includes('__orezLibPgQueryInit')
331
- ) {
332
- return
333
- }
334
- if (code.includes('orez-libpg-query-wasm-binary')) {
335
- console.warn(
336
- '[orez] libpg-query wasm loader already patched with an older shape. ' +
337
- 'Reinstall libpg-query or restore node_modules before re-patching.'
338
- )
339
- return
340
- }
341
-
342
- const pattern = 'const initPromise = PgQueryModule().then((module) => {'
343
- if (!code.includes(pattern)) {
344
- console.warn(
345
- '[orez] could not find PgQueryModule init in libpg-query wasm index. ' +
346
- 'pgsql-parser version may have changed — check compatibility.'
347
- )
348
- return
349
- }
350
-
351
- const wasmBase64 = readFileSync(wasmPath).toString('base64')
352
- const replacement = `\
353
- // orez-libpg-query-wasm-binary: embed parser wasm for CF Workers.
354
- const __orezLibPgQueryWasmBase64 = '${wasmBase64}';
355
- function __orezLibPgQueryWasmBinary() {
356
- const decode = globalThis.atob
357
- ? globalThis.atob(__orezLibPgQueryWasmBase64)
358
- : Buffer.from(__orezLibPgQueryWasmBase64, 'base64').toString('binary');
359
- const bytes = new Uint8Array(decode.length);
360
- for (let i = 0; i < decode.length; i++) bytes[i] = decode.charCodeAt(i);
361
- return bytes;
362
- }
363
- try {
364
- const g = globalThis;
365
- if (g.self && !g.self.location) g.self.location = { href: 'https://orez.local/libpg-query.js' };
366
- if (!g.location) g.location = { href: 'https://orez.local/libpg-query.js' };
367
- }
368
- catch {
369
- }
370
- const __orezLibPgQueryPreviousProcessType = globalThis.process?.type;
371
- if (globalThis.process && !globalThis.process.type) globalThis.process.type = 'renderer';
372
- const __orezLibPgQueryInit = PgQueryModule({ wasmBinary: __orezLibPgQueryWasmBinary() });
373
- if (globalThis.process && __orezLibPgQueryPreviousProcessType === undefined) {
374
- delete globalThis.process.type;
375
- }
376
- else if (globalThis.process) {
377
- globalThis.process.type = __orezLibPgQueryPreviousProcessType;
378
- }
379
- const initPromise = __orezLibPgQueryInit.then((module) => {`
380
-
381
- code = code.replace(pattern, replacement)
382
- writeFileSync(parserIndexPath, code)
383
- console.log('[orez] patched libpg-query wasm loader (embedded wasm bytes)')
384
- }
@@ -1,321 +0,0 @@
1
- /**
2
- * integration test for zero-cache embedded mode.
3
- *
4
- * validates that zero-cache can run in-process with SINGLE_PROCESS=1,
5
- * connected to PGlite via the TCP proxy. this is the same pipeline as
6
- * the full integration test but without child_process.fork().
7
- *
8
- * test flow:
9
- * 1. create PGlite instances (postgres, cvr, cdb)
10
- * 2. start TCP proxy
11
- * 3. start zero-cache in-process via startZeroCacheEmbed()
12
- * 4. connect WebSocket client and verify sync
13
- */
14
-
15
- import { mkdirSync } from 'node:fs'
16
- import { resolve } from 'node:path'
17
-
18
- import { describe, test, expect, beforeAll, afterAll } from 'vitest'
19
- import WebSocket from 'ws'
20
-
21
- import { getConfig, getConnectionString } from '../config.js'
22
- import {
23
- ensureTablesInPublications,
24
- installAllowAllPermissions,
25
- } from '../integration/test-permissions.js'
26
- import { startPgProxy } from '../pg-proxy.js'
27
- import { createPGliteInstances, type PGliteInstances } from '../pglite-manager.js'
28
- import { installChangeTracking } from '../replication/change-tracker.js'
29
- import { startZeroCacheEmbed, type ZeroCacheEmbed } from './zero-cache-embed.js'
30
-
31
- import type { PGlite } from '@electric-sql/pglite'
32
-
33
- const SYNC_PROTOCOL_VERSION = 49
34
-
35
- function encodeSecProtocols(
36
- initConnectionMessage: unknown,
37
- authToken: string | undefined
38
- ): string {
39
- const payload = JSON.stringify({ initConnectionMessage, authToken })
40
- return encodeURIComponent(Buffer.from(payload, 'utf-8').toString('base64'))
41
- }
42
-
43
- describe('zero-cache embed integration', { timeout: 120000 }, () => {
44
- let db: PGlite
45
- let instances: PGliteInstances
46
- let pgServer: ReturnType<Awaited<ReturnType<typeof startPgProxy>>>
47
- let embed: ZeroCacheEmbed
48
- let zeroPort: number
49
- let pgPort: number
50
- let dataDir: string
51
-
52
- beforeAll(async () => {
53
- // use random ports to avoid conflicts with other tests
54
- pgPort = 24000 + Math.floor(Math.random() * 1000)
55
- zeroPort = pgPort + 100
56
-
57
- dataDir = `.orez-embed-test-${Date.now()}`
58
-
59
- const config = getConfig({
60
- pgPort,
61
- zeroPort,
62
- dataDir,
63
- logLevel: 'info',
64
- useWorkerThreads: false,
65
- singleDb: false,
66
- })
67
-
68
- mkdirSync(dataDir, { recursive: true })
69
-
70
- // create PGlite instances
71
- instances = await createPGliteInstances(config)
72
- db = instances.postgres
73
-
74
- // create test table
75
- await db.exec(`
76
- CREATE TABLE IF NOT EXISTS foo (
77
- id TEXT PRIMARY KEY,
78
- value TEXT,
79
- num INTEGER
80
- )
81
- `)
82
-
83
- // set up publications
84
- const pubName = `orez_zero_public`
85
- process.env.ZERO_APP_PUBLICATIONS = pubName
86
- await db.exec(`CREATE PUBLICATION "${pubName}"`).catch(() => {})
87
- await db
88
- .exec(`ALTER PUBLICATION "${pubName}" ADD TABLE "public"."foo"`)
89
- .catch(() => {})
90
-
91
- // install change tracking
92
- await installChangeTracking(db)
93
-
94
- // install allow-all permissions for test
95
- await installAllowAllPermissions(db, ['foo'])
96
- await ensureTablesInPublications(db, ['foo'])
97
-
98
- // start TCP proxy
99
- pgServer = await startPgProxy(instances, config)
100
-
101
- // start zero-cache in-process
102
- const upstreamDb = getConnectionString(config, 'postgres')
103
- const cvrDb = getConnectionString(config, 'zero_cvr')
104
- const changeDb = getConnectionString(config, 'zero_cdb')
105
- const replicaFile = resolve(dataDir, 'zero-replica.db')
106
-
107
- console.log(`[embed-test] starting in-process zero-cache on port ${zeroPort}`)
108
- console.log(`[embed-test] upstream: ${upstreamDb}`)
109
-
110
- embed = await startZeroCacheEmbed({
111
- pglite: db,
112
- upstreamDb,
113
- cvrDb,
114
- changeDb,
115
- replicaFile,
116
- port: zeroPort,
117
- publications: [pubName],
118
- env: {
119
- ZERO_LOG_LEVEL: 'info',
120
- },
121
- })
122
-
123
- console.log(`[embed-test] zero-cache ready on port ${embed.port}`)
124
-
125
- // wait for HTTP health check
126
- await waitForZero(zeroPort, 30000)
127
- console.log(`[embed-test] health check passed`)
128
- }, 120000)
129
-
130
- afterAll(async () => {
131
- if (embed) await embed.stop()
132
- if (pgServer) pgServer.close()
133
- if (instances) {
134
- await instances.postgres.close().catch(() => {})
135
- await instances.cvr.close().catch(() => {})
136
- await instances.cdb.close().catch(() => {})
137
- }
138
- if (dataDir) {
139
- const { rmSync } = await import('node:fs')
140
- try {
141
- rmSync(dataDir, { recursive: true, force: true })
142
- } catch {}
143
- }
144
- })
145
-
146
- test('zero-cache is ready', () => {
147
- expect(embed.ready).toBe(true)
148
- expect(embed.port).toBe(zeroPort)
149
- })
150
-
151
- test('accepts WebSocket connections', async () => {
152
- const cg = `test-cg-${Date.now()}`
153
- const cid = `test-client-${Date.now()}`
154
- const secProtocol = encodeSecProtocols(
155
- [
156
- 'initConnection',
157
- {
158
- desiredQueriesPatch: [],
159
- clientSchema: {
160
- tables: {
161
- foo: {
162
- columns: {
163
- id: { type: 'string' },
164
- value: { type: 'string' },
165
- num: { type: 'number' },
166
- },
167
- primaryKey: ['id'],
168
- },
169
- },
170
- },
171
- },
172
- ],
173
- undefined
174
- )
175
- const ws = new WebSocket(
176
- `ws://localhost:${zeroPort}/sync/v${SYNC_PROTOCOL_VERSION}/connect` +
177
- `?clientGroupID=${cg}&clientID=${cid}&wsid=ws1&schemaVersion=1&baseCookie=&ts=${Date.now()}&lmid=0`,
178
- secProtocol
179
- )
180
-
181
- // collect messages — attach listener before open to catch everything
182
- const messages: unknown[] = []
183
- ws.on('message', (data) => {
184
- messages.push(JSON.parse(data.toString()))
185
- })
186
-
187
- const connected = new Promise<void>((resolve, reject) => {
188
- ws.on('open', resolve)
189
- ws.on('error', reject)
190
- setTimeout(() => reject(new Error('ws connect timeout')), 10000)
191
- })
192
-
193
- await connected
194
-
195
- // wait for messages to arrive
196
- const deadline = Date.now() + 10000
197
- while (
198
- Date.now() < deadline &&
199
- !messages.some((m) => Array.isArray(m) && m[0] === 'connected')
200
- ) {
201
- await new Promise((r) => setTimeout(r, 100))
202
- }
203
-
204
- const connectedMsg = messages.find((m) => Array.isArray(m) && m[0] === 'connected')
205
- expect(connectedMsg).toMatchObject(['connected', { wsid: 'ws1' }])
206
- ws.close()
207
- })
208
-
209
- test('live replication: insert triggers poke', async () => {
210
- // insert data
211
- await db.query(`INSERT INTO foo (id, value, num) VALUES ($1, $2, $3)`, [
212
- 'embed-row',
213
- 'hello-embed',
214
- 42,
215
- ])
216
-
217
- // wait for replication to deliver
218
- await waitForReplicationCatchup(db)
219
- await new Promise((r) => setTimeout(r, 1000))
220
-
221
- // connect and subscribe
222
- const downstream: unknown[] = []
223
- const ws = connectAndSubscribe(zeroPort, downstream)
224
-
225
- // wait for poke with our data
226
- const deadline = Date.now() + 30000
227
- let found = false
228
- while (Date.now() < deadline && !found) {
229
- await new Promise((r) => setTimeout(r, 500))
230
- for (const msg of downstream) {
231
- if (Array.isArray(msg) && msg[0] === 'pokePart' && msg[1]?.rowsPatch) {
232
- for (const patch of msg[1].rowsPatch) {
233
- if (
234
- patch.op === 'put' &&
235
- patch.tableName === 'foo' &&
236
- patch.value?.id === 'embed-row'
237
- ) {
238
- found = true
239
- break
240
- }
241
- }
242
- }
243
- }
244
- }
245
-
246
- ws.close()
247
- expect(found).toBe(true)
248
- })
249
- })
250
-
251
- function connectAndSubscribe(port: number, downstream: unknown[]): WebSocket {
252
- const cg = `test-cg-${Date.now()}`
253
- const cid = `test-client-${Date.now()}`
254
- const secProtocol = encodeSecProtocols(
255
- [
256
- 'initConnection',
257
- {
258
- desiredQueriesPatch: [
259
- {
260
- op: 'put',
261
- hash: 'q1',
262
- ast: {
263
- table: 'foo',
264
- orderBy: [['id', 'asc']],
265
- },
266
- },
267
- ],
268
- clientSchema: {
269
- tables: {
270
- foo: {
271
- columns: {
272
- id: { type: 'string' },
273
- value: { type: 'string' },
274
- num: { type: 'number' },
275
- },
276
- primaryKey: ['id'],
277
- },
278
- },
279
- },
280
- },
281
- ],
282
- undefined
283
- )
284
- const ws = new WebSocket(
285
- `ws://localhost:${port}/sync/v${SYNC_PROTOCOL_VERSION}/connect` +
286
- `?clientGroupID=${cg}&clientID=${cid}&wsid=ws1&schemaVersion=1&baseCookie=&ts=${Date.now()}&lmid=0`,
287
- secProtocol
288
- )
289
-
290
- ws.on('message', (data) => {
291
- downstream.push(JSON.parse(data.toString()))
292
- })
293
-
294
- return ws
295
- }
296
-
297
- async function waitForReplicationCatchup(
298
- pglite: PGlite,
299
- timeoutMs = 15000
300
- ): Promise<void> {
301
- const deadline = Date.now() + timeoutMs
302
- while (Date.now() < deadline) {
303
- const result = await pglite.query<{ count: string }>(
304
- `SELECT count(*)::text as count FROM _orez._zero_changes`
305
- )
306
- if (Number(result.rows[0]?.count) === 0) return
307
- await new Promise((r) => setTimeout(r, 100))
308
- }
309
- }
310
-
311
- async function waitForZero(port: number, timeoutMs = 30000) {
312
- const deadline = Date.now() + timeoutMs
313
- while (Date.now() < deadline) {
314
- try {
315
- const res = await fetch(`http://localhost:${port}/`)
316
- if (res.ok || res.status === 404) return
317
- } catch {}
318
- await new Promise((r) => setTimeout(r, 500))
319
- }
320
- throw new Error(`zero-cache not ready on port ${port} after ${timeoutMs}ms`)
321
- }