orez 0.1.36 → 0.1.38
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.
- package/dist/cli-entry.js +0 -0
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -11
- package/dist/index.js.map +1 -1
- package/dist/pg-proxy.d.ts.map +1 -1
- package/dist/pg-proxy.js +8 -4
- package/dist/pg-proxy.js.map +1 -1
- package/dist/pglite-manager.d.ts +12 -0
- package/dist/pglite-manager.d.ts.map +1 -1
- package/dist/pglite-manager.js +81 -0
- package/dist/pglite-manager.js.map +1 -1
- package/dist/recovery.js +2 -2
- package/dist/recovery.js.map +1 -1
- package/dist/replication/change-tracker.js +9 -9
- package/dist/replication/change-tracker.js.map +1 -1
- package/dist/replication/handler.d.ts +12 -0
- package/dist/replication/handler.d.ts.map +1 -1
- package/dist/replication/handler.js +34 -6
- package/dist/replication/handler.js.map +1 -1
- package/dist/worker/browser-build-config.d.ts +59 -0
- package/dist/worker/browser-build-config.d.ts.map +1 -0
- package/dist/worker/browser-build-config.js +101 -0
- package/dist/worker/browser-build-config.js.map +1 -0
- package/dist/worker/browser-embed.d.ts +58 -0
- package/dist/worker/browser-embed.d.ts.map +1 -0
- package/dist/worker/browser-embed.js +195 -0
- package/dist/worker/browser-embed.js.map +1 -0
- package/dist/worker/cf-patches.d.ts +20 -0
- package/dist/worker/cf-patches.d.ts.map +1 -0
- package/dist/worker/cf-patches.js +94 -0
- package/dist/worker/cf-patches.js.map +1 -0
- package/dist/worker/index.d.ts +12 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +105 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/shims/fastify.d.ts +80 -0
- package/dist/worker/shims/fastify.d.ts.map +1 -0
- package/dist/worker/shims/fastify.js +223 -0
- package/dist/worker/shims/fastify.js.map +1 -0
- package/dist/worker/shims/http-service.d.ts +104 -0
- package/dist/worker/shims/http-service.d.ts.map +1 -0
- package/dist/worker/shims/http-service.js +198 -0
- package/dist/worker/shims/http-service.js.map +1 -0
- package/dist/worker/shims/node-stub.d.ts +147 -0
- package/dist/worker/shims/node-stub.d.ts.map +1 -0
- package/dist/worker/shims/node-stub.js +204 -0
- package/dist/worker/shims/node-stub.js.map +1 -0
- package/dist/worker/shims/postgres.d.ts +115 -0
- package/dist/worker/shims/postgres.d.ts.map +1 -0
- package/dist/worker/shims/postgres.js +1181 -0
- package/dist/worker/shims/postgres.js.map +1 -0
- package/dist/worker/shims/sqlite-browser.d.ts +54 -0
- package/dist/worker/shims/sqlite-browser.d.ts.map +1 -0
- package/dist/worker/shims/sqlite-browser.js +144 -0
- package/dist/worker/shims/sqlite-browser.js.map +1 -0
- package/dist/worker/shims/sqlite.d.ts +126 -0
- package/dist/worker/shims/sqlite.d.ts.map +1 -0
- package/dist/worker/shims/sqlite.js +599 -0
- package/dist/worker/shims/sqlite.js.map +1 -0
- package/dist/worker/shims/stream-browser.d.ts +9 -0
- package/dist/worker/shims/stream-browser.d.ts.map +1 -0
- package/dist/worker/shims/stream-browser.js +13 -0
- package/dist/worker/shims/stream-browser.js.map +1 -0
- package/dist/worker/shims/ws-browser.d.ts +50 -0
- package/dist/worker/shims/ws-browser.d.ts.map +1 -0
- package/dist/worker/shims/ws-browser.js +105 -0
- package/dist/worker/shims/ws-browser.js.map +1 -0
- package/dist/worker/shims/ws.d.ts +62 -0
- package/dist/worker/shims/ws.d.ts.map +1 -0
- package/dist/worker/shims/ws.js +310 -0
- package/dist/worker/shims/ws.js.map +1 -0
- package/dist/worker/types.d.ts +57 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +9 -0
- package/dist/worker/types.js.map +1 -0
- package/dist/worker/zero-cache-embed-cf.d.ts +63 -0
- package/dist/worker/zero-cache-embed-cf.d.ts.map +1 -0
- package/dist/worker/zero-cache-embed-cf.js +268 -0
- package/dist/worker/zero-cache-embed-cf.js.map +1 -0
- package/dist/worker/zero-cache-embed.d.ts +66 -0
- package/dist/worker/zero-cache-embed.d.ts.map +1 -0
- package/dist/worker/zero-cache-embed.js +200 -0
- package/dist/worker/zero-cache-embed.js.map +1 -0
- package/package.json +62 -3
- package/src/cli-entry.ts +0 -0
- package/src/cli.ts +8 -1
- package/src/config.ts +2 -0
- package/src/index.ts +15 -10
- package/src/integration/integration.test.ts +1 -1
- package/src/integration/restore-live-stress.test.ts +2 -2
- package/src/pg-proxy.ts +9 -4
- package/src/pglite-manager.ts +111 -0
- package/src/recovery.ts +2 -2
- package/src/replication/change-tracker.test.ts +1 -1
- package/src/replication/change-tracker.ts +9 -9
- package/src/replication/handler.test.ts +37 -0
- package/src/replication/handler.ts +46 -6
- package/src/wasm-sqlite.test.ts +2 -1
- package/src/worker/browser-build-config.test.ts +59 -0
- package/src/worker/browser-build-config.ts +105 -0
- package/src/worker/browser-embed.ts +306 -0
- package/src/worker/cf-patches.ts +114 -0
- package/src/worker/embed-integration.test.ts +321 -0
- package/src/worker/index.ts +138 -0
- package/src/worker/shims/fastify.test.ts +255 -0
- package/src/worker/shims/fastify.ts +292 -0
- package/src/worker/shims/http-service.test.ts +355 -0
- package/src/worker/shims/http-service.ts +293 -0
- package/src/worker/shims/node-stub.ts +223 -0
- package/src/worker/shims/postgres.test.ts +364 -0
- package/src/worker/shims/postgres.ts +1434 -0
- package/src/worker/shims/sqlite-browser.test.ts +233 -0
- package/src/worker/shims/sqlite-browser.ts +178 -0
- package/src/worker/shims/sqlite.test.ts +641 -0
- package/src/worker/shims/sqlite.ts +731 -0
- package/src/worker/shims/ws-browser.test.ts +184 -0
- package/src/worker/shims/ws-browser.ts +125 -0
- package/src/worker/shims/ws.test.ts +288 -0
- package/src/worker/shims/ws.ts +367 -0
- package/src/worker/types.ts +75 -0
- package/src/worker/worker-integration.test.ts +223 -0
- package/src/worker/worker.test.ts +136 -0
- package/src/worker/zero-cache-embed-cf.ts +367 -0
- package/src/worker/zero-cache-embed.ts +277 -0
|
@@ -0,0 +1,63 @@
|
|
|
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 (PGlite-backed)
|
|
8
|
+
* @rocicorp/zero-sqlite3 → orez/worker/shims/sqlite (DO SQLite)
|
|
9
|
+
* fastify → orez/worker/shims/fastify (route capture)
|
|
10
|
+
* ws → orez/worker/shims/ws (CF WebSocket)
|
|
11
|
+
*
|
|
12
|
+
* the consumer's wrangler.toml must configure these aliases and enable
|
|
13
|
+
* nodejs_compat for the remaining Node.js APIs (events, stream, etc.).
|
|
14
|
+
*
|
|
15
|
+
* usage in a Durable Object:
|
|
16
|
+
*
|
|
17
|
+
* import { startZeroCacheEmbedCF } from 'orez/worker'
|
|
18
|
+
*
|
|
19
|
+
* // in ensureInitialized():
|
|
20
|
+
* globalThis.__orez_pglite = pglite // for postgres shim
|
|
21
|
+
* globalThis.__orez_do_sqlite = ctx.storage.sql // for sqlite shim
|
|
22
|
+
*
|
|
23
|
+
* const zc = await startZeroCacheEmbedCF({ ... })
|
|
24
|
+
*
|
|
25
|
+
* // in DO fetch():
|
|
26
|
+
* return zc.handleRequest(request)
|
|
27
|
+
*/
|
|
28
|
+
import type { PGlite } from '@electric-sql/pglite';
|
|
29
|
+
export interface ZeroCacheEmbedCFOptions {
|
|
30
|
+
/** PGlite instance (also registered on globalThis.__orez_pglite) */
|
|
31
|
+
pglite: PGlite;
|
|
32
|
+
/** DO SQLite storage (also registered on globalThis.__orez_do_sqlite) */
|
|
33
|
+
doSqlite: unknown;
|
|
34
|
+
/** zero app ID (default: 'zero') */
|
|
35
|
+
appId?: string;
|
|
36
|
+
/** publication names */
|
|
37
|
+
publications?: string[];
|
|
38
|
+
/** additional env vars passed to zero-cache */
|
|
39
|
+
env?: Record<string, string>;
|
|
40
|
+
/** timeout in ms waiting for zero-cache ready (default: 30000) */
|
|
41
|
+
readyTimeout?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ZeroCacheEmbedCF {
|
|
44
|
+
/** whether zero-cache is ready */
|
|
45
|
+
readonly ready: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* handle an incoming request from the DO's fetch() handler.
|
|
48
|
+
* routes HTTP to zero-cache's Fastify handlers, WebSocket
|
|
49
|
+
* upgrades through the zero-cache handoff mechanism.
|
|
50
|
+
*/
|
|
51
|
+
handleRequest(request: Request): Promise<Response>;
|
|
52
|
+
/** stop zero-cache */
|
|
53
|
+
stop(): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* start zero-cache in embedded CF Workers mode.
|
|
57
|
+
*
|
|
58
|
+
* must be called AFTER setting up globalThis:
|
|
59
|
+
* globalThis.__orez_pglite = pgliteInstance
|
|
60
|
+
* globalThis.__orez_do_sqlite = ctx.storage.sql
|
|
61
|
+
*/
|
|
62
|
+
export declare function startZeroCacheEmbedCF(opts: ZeroCacheEmbedCFOptions): Promise<ZeroCacheEmbedCF>;
|
|
63
|
+
//# sourceMappingURL=zero-cache-embed-cf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zero-cache-embed-cf.d.ts","sourceRoot":"","sources":["../../src/worker/zero-cache-embed-cf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AASH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAOlD,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAA;IAEd,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAA;IAEjB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IAEvB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE5B,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IAEvB;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAElD,sBAAsB;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAwL3B"}
|
|
@@ -0,0 +1,268 @@
|
|
|
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 (PGlite-backed)
|
|
8
|
+
* @rocicorp/zero-sqlite3 → orez/worker/shims/sqlite (DO SQLite)
|
|
9
|
+
* fastify → orez/worker/shims/fastify (route capture)
|
|
10
|
+
* ws → orez/worker/shims/ws (CF WebSocket)
|
|
11
|
+
*
|
|
12
|
+
* the consumer's wrangler.toml must configure these aliases and enable
|
|
13
|
+
* nodejs_compat for the remaining Node.js APIs (events, stream, etc.).
|
|
14
|
+
*
|
|
15
|
+
* usage in a Durable Object:
|
|
16
|
+
*
|
|
17
|
+
* import { startZeroCacheEmbedCF } from 'orez/worker'
|
|
18
|
+
*
|
|
19
|
+
* // in ensureInitialized():
|
|
20
|
+
* globalThis.__orez_pglite = pglite // for postgres shim
|
|
21
|
+
* globalThis.__orez_do_sqlite = ctx.storage.sql // for sqlite shim
|
|
22
|
+
*
|
|
23
|
+
* const zc = await startZeroCacheEmbedCF({ ... })
|
|
24
|
+
*
|
|
25
|
+
* // in DO fetch():
|
|
26
|
+
* return zc.handleRequest(request)
|
|
27
|
+
*/
|
|
28
|
+
import EventEmitter from 'node:events';
|
|
29
|
+
// static import so wrangler can follow the dependency tree and bundle
|
|
30
|
+
// zero-cache with all its transitive deps + our shim aliases.
|
|
31
|
+
// @ts-expect-error — internal zero-cache module, no type declarations
|
|
32
|
+
import { runWorker as _runWorker } from '@rocicorp/zero/out/zero-cache/src/server/runner/run-worker.js';
|
|
33
|
+
const runWorkerFn = _runWorker;
|
|
34
|
+
/**
|
|
35
|
+
* start zero-cache in embedded CF Workers mode.
|
|
36
|
+
*
|
|
37
|
+
* must be called AFTER setting up globalThis:
|
|
38
|
+
* globalThis.__orez_pglite = pgliteInstance
|
|
39
|
+
* globalThis.__orez_do_sqlite = ctx.storage.sql
|
|
40
|
+
*/
|
|
41
|
+
export async function startZeroCacheEmbedCF(opts) {
|
|
42
|
+
const appId = opts.appId || 'zero';
|
|
43
|
+
const publications = opts.publications?.join(',') || `orez_${appId}_public`;
|
|
44
|
+
const readyTimeout = opts.readyTimeout ?? 30000;
|
|
45
|
+
globalThis.__orez_pglite = opts.pglite;
|
|
46
|
+
globalThis.__orez_do_sqlite = opts.doSqlite;
|
|
47
|
+
globalThis.process ??= {};
|
|
48
|
+
globalThis.process.env ??= {};
|
|
49
|
+
globalThis.process.pid ??= 1;
|
|
50
|
+
globalThis.process.argv ??= [];
|
|
51
|
+
globalThis.process.env.SINGLE_PROCESS = '1';
|
|
52
|
+
globalThis.process.env.NODE_ENV = 'development';
|
|
53
|
+
globalThis.process.kill ??= () => { };
|
|
54
|
+
// create fake parent EventEmitter for zero-cache's runWorker()
|
|
55
|
+
// must be declared before process.exit shim (which references it)
|
|
56
|
+
const parent = new EventEmitter();
|
|
57
|
+
const parentEmitter = new EventEmitter();
|
|
58
|
+
parent.send = (message, sendHandle) => {
|
|
59
|
+
parentEmitter.emit('message', message, sendHandle);
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
62
|
+
parent.kill = (signal = 'SIGTERM') => {
|
|
63
|
+
parent.emit(signal, signal);
|
|
64
|
+
};
|
|
65
|
+
parent.pid = globalThis.process.pid ?? 1;
|
|
66
|
+
// shim process.exit to emit on parent instead of actually exiting
|
|
67
|
+
const origExit = globalThis.process.exit;
|
|
68
|
+
const origNodeEnv = globalThis.process.env.NODE_ENV;
|
|
69
|
+
const origKill = globalThis.process.kill;
|
|
70
|
+
globalThis.process.exit = (code) => {
|
|
71
|
+
parent.emit('exit', code ?? 0);
|
|
72
|
+
};
|
|
73
|
+
// build env for zero-cache
|
|
74
|
+
const env = {
|
|
75
|
+
...globalThis.process.env,
|
|
76
|
+
SINGLE_PROCESS: '1',
|
|
77
|
+
NODE_ENV: 'development',
|
|
78
|
+
// these connection strings are intercepted by the postgres shim
|
|
79
|
+
ZERO_UPSTREAM_DB: 'pglite://in-process',
|
|
80
|
+
ZERO_CVR_DB: 'pglite://in-process',
|
|
81
|
+
ZERO_CHANGE_DB: 'pglite://in-process',
|
|
82
|
+
// this path is intercepted by the sqlite shim
|
|
83
|
+
ZERO_REPLICA_FILE: ':do-sqlite:',
|
|
84
|
+
// don't bind a port — we route via inject/handoff
|
|
85
|
+
ZERO_PORT: '0',
|
|
86
|
+
ZERO_APP_ID: appId,
|
|
87
|
+
ZERO_APP_PUBLICATIONS: publications,
|
|
88
|
+
ZERO_LOG_LEVEL: opts.env?.ZERO_LOG_LEVEL || 'info',
|
|
89
|
+
ZERO_NUM_SYNC_WORKERS: opts.env?.ZERO_NUM_SYNC_WORKERS || '1',
|
|
90
|
+
ZERO_ENABLE_QUERY_PLANNER: 'false',
|
|
91
|
+
...opts.env,
|
|
92
|
+
};
|
|
93
|
+
// wrap parent with onMessageType/onceMessageType helpers
|
|
94
|
+
// must forward sendHandle (second arg) for WebSocket handoff
|
|
95
|
+
const wrappedParent = new Proxy(parent, {
|
|
96
|
+
get(target, prop, receiver) {
|
|
97
|
+
if (prop === 'onMessageType') {
|
|
98
|
+
return (type, handler) => {
|
|
99
|
+
target.on('message', (data, sendHandle) => {
|
|
100
|
+
if (Array.isArray(data) && data.length === 2 && data[0] === type) {
|
|
101
|
+
handler(data[1], sendHandle);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return receiver;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (prop === 'onceMessageType') {
|
|
108
|
+
return (type, handler) => {
|
|
109
|
+
const listener = (data, sendHandle) => {
|
|
110
|
+
if (Array.isArray(data) && data.length === 2 && data[0] === type) {
|
|
111
|
+
target.off('message', listener);
|
|
112
|
+
handler(data[1], sendHandle);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
target.on('message', listener);
|
|
116
|
+
return receiver;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return Reflect.get(target, prop, receiver);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
// track state
|
|
123
|
+
let isReady = false;
|
|
124
|
+
let runWorkerPromise = null;
|
|
125
|
+
// capture the Fastify shim instance from zero-cache's HttpService.
|
|
126
|
+
// the fastify shim stores itself on globalThis when created.
|
|
127
|
+
let fastifyInstance = null;
|
|
128
|
+
// wait for "ready" message
|
|
129
|
+
const readyPromise = new Promise((resolve, reject) => {
|
|
130
|
+
const timeout = setTimeout(() => {
|
|
131
|
+
reject(new Error(`zero-cache CF embed: timed out waiting for ready after ${readyTimeout}ms`));
|
|
132
|
+
}, readyTimeout);
|
|
133
|
+
parentEmitter.on('message', (msg) => {
|
|
134
|
+
if (Array.isArray(msg) && msg[0] === 'ready') {
|
|
135
|
+
clearTimeout(timeout);
|
|
136
|
+
isReady = true;
|
|
137
|
+
resolve();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
// start zero-cache
|
|
142
|
+
runWorkerPromise = runWorkerFn(wrappedParent, env).catch((err) => {
|
|
143
|
+
if (!isReady) {
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
// after ready, errors during shutdown are expected
|
|
147
|
+
});
|
|
148
|
+
// wait for ready
|
|
149
|
+
await readyPromise;
|
|
150
|
+
// get the fastify instance (set by our shim during init)
|
|
151
|
+
fastifyInstance = globalThis.__orez_fastify_instance;
|
|
152
|
+
return {
|
|
153
|
+
get ready() {
|
|
154
|
+
return isReady;
|
|
155
|
+
},
|
|
156
|
+
async handleRequest(request) {
|
|
157
|
+
if (!isReady) {
|
|
158
|
+
return new Response('zero-cache not ready', { status: 503 });
|
|
159
|
+
}
|
|
160
|
+
const url = new URL(request.url);
|
|
161
|
+
const isUpgrade = request.headers.get('upgrade')?.toLowerCase() === 'websocket' ||
|
|
162
|
+
request.headers.get('x-soot-ws-upgrade') === 'true';
|
|
163
|
+
if (isUpgrade) {
|
|
164
|
+
return handleWebSocketUpgrade(request, url, fastifyInstance);
|
|
165
|
+
}
|
|
166
|
+
return handleHttpRequest(request, url, fastifyInstance);
|
|
167
|
+
},
|
|
168
|
+
async stop() {
|
|
169
|
+
isReady = false;
|
|
170
|
+
wrappedParent.kill('SIGTERM');
|
|
171
|
+
if (runWorkerPromise) {
|
|
172
|
+
await Promise.race([runWorkerPromise, new Promise((r) => setTimeout(r, 5000))]);
|
|
173
|
+
}
|
|
174
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
175
|
+
// restore all modified globals
|
|
176
|
+
if (origExit) {
|
|
177
|
+
;
|
|
178
|
+
globalThis.process.exit = origExit;
|
|
179
|
+
}
|
|
180
|
+
if (origNodeEnv !== undefined) {
|
|
181
|
+
;
|
|
182
|
+
globalThis.process.env.NODE_ENV = origNodeEnv;
|
|
183
|
+
}
|
|
184
|
+
if (origKill) {
|
|
185
|
+
;
|
|
186
|
+
globalThis.process.kill = origKill;
|
|
187
|
+
}
|
|
188
|
+
delete globalThis.process.env.SINGLE_PROCESS;
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// -- HTTP request handling --
|
|
193
|
+
// routes through the Fastify shim's inject() method
|
|
194
|
+
async function handleHttpRequest(request, url, fastify) {
|
|
195
|
+
if (!fastify?.inject) {
|
|
196
|
+
return new Response('fastify not available', { status: 503 });
|
|
197
|
+
}
|
|
198
|
+
const headers = {};
|
|
199
|
+
request.headers.forEach((value, key) => {
|
|
200
|
+
headers[key] = value;
|
|
201
|
+
});
|
|
202
|
+
let payload = null;
|
|
203
|
+
if (request.method !== 'GET' && request.method !== 'HEAD' && request.body) {
|
|
204
|
+
payload = await request.text();
|
|
205
|
+
}
|
|
206
|
+
const result = await fastify.inject({
|
|
207
|
+
method: request.method,
|
|
208
|
+
url: url.pathname + url.search,
|
|
209
|
+
headers,
|
|
210
|
+
payload,
|
|
211
|
+
});
|
|
212
|
+
return new Response(result.body, {
|
|
213
|
+
status: result.statusCode,
|
|
214
|
+
headers: result.headers,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
// -- WebSocket upgrade handling --
|
|
218
|
+
// creates WebSocketPair and feeds the server socket into zero-cache's
|
|
219
|
+
// handoff mechanism via the Fastify shim's server EventEmitter.
|
|
220
|
+
function handleWebSocketUpgrade(request, url, fastify) {
|
|
221
|
+
const WsPair = globalThis.WebSocketPair;
|
|
222
|
+
if (!WsPair) {
|
|
223
|
+
return new Response('WebSocketPair not available', { status: 500 });
|
|
224
|
+
}
|
|
225
|
+
const pair = new WsPair();
|
|
226
|
+
const [client, server] = Object.values(pair);
|
|
227
|
+
// accept the server side (CF Workers requirement)
|
|
228
|
+
server.accept();
|
|
229
|
+
// build a serializable request object for the handoff
|
|
230
|
+
const headers = {};
|
|
231
|
+
request.headers.forEach((value, key) => {
|
|
232
|
+
headers[key] = value;
|
|
233
|
+
});
|
|
234
|
+
const message = {
|
|
235
|
+
url: url.pathname + url.search,
|
|
236
|
+
headers,
|
|
237
|
+
method: 'GET',
|
|
238
|
+
};
|
|
239
|
+
// emit handoff on the Fastify server's EventEmitter.
|
|
240
|
+
// installWebSocketHandoff (non-Server branch) listens for this:
|
|
241
|
+
// source.onMessageType("handoff", (msg, socket) => { ... })
|
|
242
|
+
if (fastify?.server) {
|
|
243
|
+
fastify.server.emit('message', ['handoff', { message, head: new Uint8Array(0) }], server // the CF WebSocket as sendHandle
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
// return 101 with client socket
|
|
247
|
+
// must echo Sec-WebSocket-Protocol — browsers reject the upgrade without it
|
|
248
|
+
const secProtocol = request.headers.get('sec-websocket-protocol');
|
|
249
|
+
const upgradeHeaders = {};
|
|
250
|
+
if (secProtocol) {
|
|
251
|
+
upgradeHeaders['Sec-WebSocket-Protocol'] = secProtocol;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
return new Response(null, {
|
|
255
|
+
status: 101,
|
|
256
|
+
headers: upgradeHeaders,
|
|
257
|
+
// @ts-expect-error CF Workers Response extension
|
|
258
|
+
webSocket: client,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
const resp = new Response(null, { status: 200 });
|
|
263
|
+
resp.__orez_websocket = client;
|
|
264
|
+
resp.__orez_ws_upgrade = true;
|
|
265
|
+
return resp;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=zero-cache-embed-cf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zero-cache-embed-cf.js","sourceRoot":"","sources":["../../src/worker/zero-cache-embed-cf.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zero-cache embedded runner.
|
|
3
|
+
*
|
|
4
|
+
* runs zero-cache in-process with SINGLE_PROCESS=1 instead of spawning
|
|
5
|
+
* a child process. uses the same TCP proxy approach as startZeroLite()
|
|
6
|
+
* for database connectivity — zero-cache connects to PGlite via the proxy.
|
|
7
|
+
*
|
|
8
|
+
* two modes:
|
|
9
|
+
*
|
|
10
|
+
* 1. **development** (this file): zero-cache uses real postgres package
|
|
11
|
+
* to connect to PGlite via TCP proxy. no bundler aliases needed.
|
|
12
|
+
*
|
|
13
|
+
* 2. **CF Workers** (future): bundler aliases swap postgres/sqlite3 for
|
|
14
|
+
* our shims. no TCP proxy, no port binding, all in-process.
|
|
15
|
+
*
|
|
16
|
+
* env vars:
|
|
17
|
+
* SINGLE_PROCESS=1 — all workers in-process via EventEmitter
|
|
18
|
+
* ZERO_UPSTREAM_DB — postgres connection string (to TCP proxy)
|
|
19
|
+
* ZERO_CVR_DB — postgres connection string (to TCP proxy)
|
|
20
|
+
* ZERO_CHANGE_DB — postgres connection string (to TCP proxy)
|
|
21
|
+
* ZERO_REPLICA_FILE — sqlite replica file path
|
|
22
|
+
* ZERO_PORT — HTTP port for zero-cache dispatcher
|
|
23
|
+
*/
|
|
24
|
+
import type { PGlite } from '@electric-sql/pglite';
|
|
25
|
+
export interface ZeroCacheEmbedOptions {
|
|
26
|
+
/** PGlite instance (not used directly — zero-cache connects via TCP proxy) */
|
|
27
|
+
pglite: PGlite;
|
|
28
|
+
/** connection string for the upstream database (postgres://...) */
|
|
29
|
+
upstreamDb: string;
|
|
30
|
+
/** connection string for the CVR database */
|
|
31
|
+
cvrDb: string;
|
|
32
|
+
/** connection string for the change database */
|
|
33
|
+
changeDb: string;
|
|
34
|
+
/** path to the SQLite replica file */
|
|
35
|
+
replicaFile: string;
|
|
36
|
+
/** port for zero-cache HTTP server (0 = random) */
|
|
37
|
+
port?: number;
|
|
38
|
+
/** zero app ID (default: 'zero') */
|
|
39
|
+
appId?: string;
|
|
40
|
+
/** publication names */
|
|
41
|
+
publications?: string[];
|
|
42
|
+
/** additional env vars passed to zero-cache */
|
|
43
|
+
env?: Record<string, string>;
|
|
44
|
+
/** timeout in ms waiting for zero-cache to be ready (default: 60000) */
|
|
45
|
+
readyTimeout?: number;
|
|
46
|
+
}
|
|
47
|
+
export interface ZeroCacheEmbed {
|
|
48
|
+
/** the port zero-cache is listening on */
|
|
49
|
+
readonly port: number;
|
|
50
|
+
/** whether zero-cache is ready to handle requests */
|
|
51
|
+
readonly ready: boolean;
|
|
52
|
+
/** stop zero-cache and all in-process workers */
|
|
53
|
+
stop(): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* start zero-cache in embedded (in-process) mode.
|
|
57
|
+
*
|
|
58
|
+
* instead of spawning a child process, imports and runs zero-cache's
|
|
59
|
+
* runWorker() directly with SINGLE_PROCESS=1. all worker coordination
|
|
60
|
+
* happens via EventEmitter IPC channels instead of process.fork().
|
|
61
|
+
*
|
|
62
|
+
* zero-cache still connects to PGlite via the TCP proxy (same as
|
|
63
|
+
* the child process mode), so no bundler aliases are needed.
|
|
64
|
+
*/
|
|
65
|
+
export declare function startZeroCacheEmbed(opts: ZeroCacheEmbedOptions): Promise<ZeroCacheEmbed>;
|
|
66
|
+
//# sourceMappingURL=zero-cache-embed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zero-cache-embed.d.ts","sourceRoot":"","sources":["../../src/worker/zero-cache-embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElD,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAA;IAEd,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAA;IAElB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IAEb,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAA;IAEnB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IAEvB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE5B,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IAEvB,iDAAiD;IACjD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAgMzB"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zero-cache embedded runner.
|
|
3
|
+
*
|
|
4
|
+
* runs zero-cache in-process with SINGLE_PROCESS=1 instead of spawning
|
|
5
|
+
* a child process. uses the same TCP proxy approach as startZeroLite()
|
|
6
|
+
* for database connectivity — zero-cache connects to PGlite via the proxy.
|
|
7
|
+
*
|
|
8
|
+
* two modes:
|
|
9
|
+
*
|
|
10
|
+
* 1. **development** (this file): zero-cache uses real postgres package
|
|
11
|
+
* to connect to PGlite via TCP proxy. no bundler aliases needed.
|
|
12
|
+
*
|
|
13
|
+
* 2. **CF Workers** (future): bundler aliases swap postgres/sqlite3 for
|
|
14
|
+
* our shims. no TCP proxy, no port binding, all in-process.
|
|
15
|
+
*
|
|
16
|
+
* env vars:
|
|
17
|
+
* SINGLE_PROCESS=1 — all workers in-process via EventEmitter
|
|
18
|
+
* ZERO_UPSTREAM_DB — postgres connection string (to TCP proxy)
|
|
19
|
+
* ZERO_CVR_DB — postgres connection string (to TCP proxy)
|
|
20
|
+
* ZERO_CHANGE_DB — postgres connection string (to TCP proxy)
|
|
21
|
+
* ZERO_REPLICA_FILE — sqlite replica file path
|
|
22
|
+
* ZERO_PORT — HTTP port for zero-cache dispatcher
|
|
23
|
+
*/
|
|
24
|
+
import EventEmitter from 'node:events';
|
|
25
|
+
import { resolve } from 'node:path';
|
|
26
|
+
/**
|
|
27
|
+
* start zero-cache in embedded (in-process) mode.
|
|
28
|
+
*
|
|
29
|
+
* instead of spawning a child process, imports and runs zero-cache's
|
|
30
|
+
* runWorker() directly with SINGLE_PROCESS=1. all worker coordination
|
|
31
|
+
* happens via EventEmitter IPC channels instead of process.fork().
|
|
32
|
+
*
|
|
33
|
+
* zero-cache still connects to PGlite via the TCP proxy (same as
|
|
34
|
+
* the child process mode), so no bundler aliases are needed.
|
|
35
|
+
*/
|
|
36
|
+
export async function startZeroCacheEmbed(opts) {
|
|
37
|
+
const appId = opts.appId || 'zero';
|
|
38
|
+
const publications = opts.publications?.join(',') || `orez_${appId}_public`;
|
|
39
|
+
const readyTimeout = opts.readyTimeout ?? 60000;
|
|
40
|
+
// CRITICAL: set SINGLE_PROCESS on process.env BEFORE importing zero-cache.
|
|
41
|
+
// zero-cache's childWorker() and ProcessManager check process.env directly,
|
|
42
|
+
// not the env object passed to runWorker(). without this, zero-cache will
|
|
43
|
+
// fork() child processes instead of using inProcChannel().
|
|
44
|
+
process.env.SINGLE_PROCESS = '1';
|
|
45
|
+
// also set NODE_ENV on process.env — zero-cache's config normalization
|
|
46
|
+
// reads process.env.NODE_ENV to decide production vs development mode
|
|
47
|
+
const origNodeEnv = process.env.NODE_ENV;
|
|
48
|
+
process.env.NODE_ENV = 'development';
|
|
49
|
+
// build env for zero-cache. these are passed to runWorker() and also
|
|
50
|
+
// propagated to in-process child workers via childWorker().
|
|
51
|
+
const env = {
|
|
52
|
+
// inherit process env for NODE_PATH, PATH, etc.
|
|
53
|
+
...process.env,
|
|
54
|
+
// zero-cache config (must come after spread to override)
|
|
55
|
+
SINGLE_PROCESS: '1',
|
|
56
|
+
NODE_ENV: 'development',
|
|
57
|
+
ZERO_UPSTREAM_DB: opts.upstreamDb,
|
|
58
|
+
ZERO_CVR_DB: opts.cvrDb,
|
|
59
|
+
ZERO_CHANGE_DB: opts.changeDb,
|
|
60
|
+
ZERO_REPLICA_FILE: opts.replicaFile,
|
|
61
|
+
ZERO_PORT: String(opts.port ?? 0),
|
|
62
|
+
ZERO_APP_ID: appId,
|
|
63
|
+
ZERO_APP_PUBLICATIONS: publications,
|
|
64
|
+
ZERO_LOG_LEVEL: opts.env?.ZERO_LOG_LEVEL || 'info',
|
|
65
|
+
ZERO_NUM_SYNC_WORKERS: opts.env?.ZERO_NUM_SYNC_WORKERS || '1',
|
|
66
|
+
ZERO_ENABLE_QUERY_PLANNER: 'false',
|
|
67
|
+
...opts.env,
|
|
68
|
+
};
|
|
69
|
+
// create a fake parent that zero-cache's runWorker() can communicate with.
|
|
70
|
+
// in normal mode, this is the child process object. here it's an EventEmitter.
|
|
71
|
+
const parent = new EventEmitter();
|
|
72
|
+
// capture messages from zero-cache
|
|
73
|
+
const parentMessages = [];
|
|
74
|
+
const parentEmitter = new EventEmitter();
|
|
75
|
+
parent.send = (message) => {
|
|
76
|
+
parentMessages.push(message);
|
|
77
|
+
parentEmitter.emit('message', message);
|
|
78
|
+
return true;
|
|
79
|
+
};
|
|
80
|
+
parent.kill = (signal = 'SIGTERM') => {
|
|
81
|
+
parent.emit(signal, signal);
|
|
82
|
+
};
|
|
83
|
+
parent.pid = process.pid;
|
|
84
|
+
// wrap parent with onMessageType/onceMessageType helpers that zero-cache expects
|
|
85
|
+
const wrappedParent = new Proxy(parent, {
|
|
86
|
+
get(target, prop, receiver) {
|
|
87
|
+
if (prop === 'onMessageType') {
|
|
88
|
+
return (type, handler) => {
|
|
89
|
+
target.on('message', (data) => {
|
|
90
|
+
if (Array.isArray(data) && data.length === 2 && data[0] === type) {
|
|
91
|
+
handler(data[1]);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return receiver;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (prop === 'onceMessageType') {
|
|
98
|
+
return (type, handler) => {
|
|
99
|
+
const listener = (data) => {
|
|
100
|
+
if (Array.isArray(data) && data.length === 2 && data[0] === type) {
|
|
101
|
+
target.off('message', listener);
|
|
102
|
+
handler(data[1]);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
target.on('message', listener);
|
|
106
|
+
return receiver;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return Reflect.get(target, prop, receiver);
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
// import and start zero-cache's runner
|
|
113
|
+
let runWorkerFn;
|
|
114
|
+
try {
|
|
115
|
+
// @rocicorp/zero's package.json exports don't expose internal modules,
|
|
116
|
+
// so we resolve the full filesystem path and import directly.
|
|
117
|
+
const { createRequire } = await import('node:module');
|
|
118
|
+
const require = createRequire(import.meta.url);
|
|
119
|
+
const zeroEntry = require.resolve('@rocicorp/zero');
|
|
120
|
+
const runWorkerPath = zeroEntry.replace(/\/out\/.*$/, '/out/zero-cache/src/server/runner/run-worker.js');
|
|
121
|
+
const mod = await import(runWorkerPath);
|
|
122
|
+
runWorkerFn = mod.runWorker;
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
throw new Error(`failed to import zero-cache runWorker: ${err}. ` +
|
|
126
|
+
'ensure @rocicorp/zero is installed.');
|
|
127
|
+
}
|
|
128
|
+
// track state
|
|
129
|
+
let isReady = false;
|
|
130
|
+
let resolvedPort = opts.port ?? 0;
|
|
131
|
+
let runWorkerPromise = null;
|
|
132
|
+
// wait for "ready" message from zero-cache
|
|
133
|
+
const readyPromise = new Promise((resolve, reject) => {
|
|
134
|
+
const timeout = setTimeout(() => {
|
|
135
|
+
reject(new Error(`zero-cache embed: timed out waiting for ready after ${readyTimeout}ms`));
|
|
136
|
+
}, readyTimeout);
|
|
137
|
+
parentEmitter.on('message', (msg) => {
|
|
138
|
+
if (Array.isArray(msg) && msg[0] === 'ready') {
|
|
139
|
+
clearTimeout(timeout);
|
|
140
|
+
isReady = true;
|
|
141
|
+
resolve();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
// intercept process.exit() — zero-cache's ProcessManager may call it
|
|
146
|
+
// during shutdown even in single-process mode (nested ProcessManagers).
|
|
147
|
+
// we convert it to a no-op and handle cleanup ourselves.
|
|
148
|
+
const origExit = process.exit;
|
|
149
|
+
process.exit = ((code) => {
|
|
150
|
+
// don't actually exit — just emit on parent to trigger cleanup
|
|
151
|
+
parent.emit('exit', code ?? 0);
|
|
152
|
+
});
|
|
153
|
+
// start runWorker (runs until killed)
|
|
154
|
+
runWorkerPromise = runWorkerFn(wrappedParent, env).catch((err) => {
|
|
155
|
+
if (!isReady) {
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
158
|
+
// after ready, errors during shutdown are expected
|
|
159
|
+
});
|
|
160
|
+
// wait for zero-cache to be ready
|
|
161
|
+
await readyPromise;
|
|
162
|
+
// if port was 0, we need to discover the actual port.
|
|
163
|
+
// zero-cache logs the address but doesn't expose it programmatically.
|
|
164
|
+
// for now, if port=0, the caller needs to discover it themselves.
|
|
165
|
+
if (opts.port && opts.port > 0) {
|
|
166
|
+
resolvedPort = opts.port;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
get port() {
|
|
170
|
+
return resolvedPort;
|
|
171
|
+
},
|
|
172
|
+
get ready() {
|
|
173
|
+
return isReady;
|
|
174
|
+
},
|
|
175
|
+
async stop() {
|
|
176
|
+
isReady = false;
|
|
177
|
+
// send SIGTERM to trigger graceful shutdown
|
|
178
|
+
wrappedParent.kill('SIGTERM');
|
|
179
|
+
// wait for runWorker to finish (with timeout).
|
|
180
|
+
// IMPORTANT: do NOT clean up process.env.SINGLE_PROCESS until after
|
|
181
|
+
// runWorker completes — the ProcessManager's async exit handler
|
|
182
|
+
// checks singleProcessMode() and must find it still set.
|
|
183
|
+
if (runWorkerPromise) {
|
|
184
|
+
await Promise.race([runWorkerPromise, new Promise((r) => setTimeout(r, 5000))]);
|
|
185
|
+
}
|
|
186
|
+
// give async exit handlers time to complete
|
|
187
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
188
|
+
// now safe to restore process.exit and process.env
|
|
189
|
+
process.exit = origExit;
|
|
190
|
+
delete process.env.SINGLE_PROCESS;
|
|
191
|
+
if (origNodeEnv !== undefined) {
|
|
192
|
+
process.env.NODE_ENV = origNodeEnv;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
delete process.env.NODE_ENV;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=zero-cache-embed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zero-cache-embed.js","sourceRoot":"","sources":["../../src/worker/zero-cache-embed.ts"],"names":[],"mappings":"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"}
|