orez 0.0.1
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/README.md +116 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +20 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +195 -0
- package/dist/index.js.map +1 -0
- package/dist/pg-proxy.d.ts +14 -0
- package/dist/pg-proxy.d.ts.map +1 -0
- package/dist/pg-proxy.js +385 -0
- package/dist/pg-proxy.js.map +1 -0
- package/dist/pglite-manager.d.ts +5 -0
- package/dist/pglite-manager.d.ts.map +1 -0
- package/dist/pglite-manager.js +71 -0
- package/dist/pglite-manager.js.map +1 -0
- package/dist/replication/change-tracker.d.ts +14 -0
- package/dist/replication/change-tracker.d.ts.map +1 -0
- package/dist/replication/change-tracker.js +86 -0
- package/dist/replication/change-tracker.js.map +1 -0
- package/dist/replication/handler.d.ts +24 -0
- package/dist/replication/handler.d.ts.map +1 -0
- package/dist/replication/handler.js +300 -0
- package/dist/replication/handler.js.map +1 -0
- package/dist/replication/pgoutput-encoder.d.ts +26 -0
- package/dist/replication/pgoutput-encoder.d.ts.map +1 -0
- package/dist/replication/pgoutput-encoder.js +204 -0
- package/dist/replication/pgoutput-encoder.js.map +1 -0
- package/dist/s3-local.d.ts +8 -0
- package/dist/s3-local.d.ts.map +1 -0
- package/dist/s3-local.js +131 -0
- package/dist/s3-local.js.map +1 -0
- package/package.json +56 -0
- package/src/config.ts +40 -0
- package/src/index.ts +255 -0
- package/src/pg-proxy.ts +474 -0
- package/src/pglite-manager.ts +105 -0
- package/src/replication/change-tracker.test.ts +179 -0
- package/src/replication/change-tracker.ts +115 -0
- package/src/replication/handler.test.ts +331 -0
- package/src/replication/handler.ts +378 -0
- package/src/replication/pgoutput-encoder.test.ts +381 -0
- package/src/replication/pgoutput-encoder.ts +252 -0
- package/src/replication/tcp-replication.test.ts +824 -0
- package/src/replication/zero-compat.test.ts +882 -0
- package/src/s3-local.ts +179 -0
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# orez
|
|
2
|
+
|
|
3
|
+
Drop-in replacement for the Docker-based development backend that Rocicorp's Zero requires. Instead of running PostgreSQL, zero-cache, and MinIO in Docker containers, orez bundles everything into a single process using PGlite (PostgreSQL compiled to WASM).
|
|
4
|
+
|
|
5
|
+
The goal is simple: `bun install && bun dev` with zero system dependencies.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## How it works
|
|
9
|
+
|
|
10
|
+
orez starts four things in one process:
|
|
11
|
+
|
|
12
|
+
1. A PGlite instance (full PostgreSQL 16 running in-process via WASM)
|
|
13
|
+
2. A TCP proxy that speaks the PostgreSQL wire protocol, including logical replication
|
|
14
|
+
3. A zero-cache child process that connects to the proxy thinking it's a real Postgres server
|
|
15
|
+
4. A minimal S3-compatible HTTP server for file uploads
|
|
16
|
+
|
|
17
|
+
The trick is in the TCP proxy. zero-cache needs logical replication to stay in sync with the upstream database. PGlite doesn't support logical replication natively, so orez fakes it. Every mutation is captured by triggers into a changes table, then encoded into the pgoutput binary protocol and streamed to zero-cache through the replication connection. zero-cache can't tell the difference.
|
|
18
|
+
|
|
19
|
+
The proxy also handles multi-database routing. zero-cache expects three separate databases (upstream, CVR, change), but PGlite is a single database. orez maps database names to schemas, so `zero_cvr` becomes the `zero_cvr` schema and `zero_cdb` becomes `zero_cdb`.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
npm install orez
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
or with bun:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
bun add orez
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You also need `@rocicorp/zero` installed in your project for the zero-cache binary.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { startZeroLite } from 'orez'
|
|
41
|
+
|
|
42
|
+
const { config, stop } = await startZeroLite({
|
|
43
|
+
pgPort: 6434,
|
|
44
|
+
zeroPort: 5849,
|
|
45
|
+
s3Port: 10201,
|
|
46
|
+
migrationsDir: 'src/database/migrations',
|
|
47
|
+
seedFile: 'src/database/seed.sql',
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// your app connects to zero-cache at localhost:5849
|
|
51
|
+
// database is at postgresql://user:password@localhost:6434/postgres
|
|
52
|
+
|
|
53
|
+
// when done
|
|
54
|
+
await stop()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
All options are optional and have sensible defaults. See `src/config.ts` for the full list.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## What gets faked
|
|
61
|
+
|
|
62
|
+
The proxy intercepts several things to convince zero-cache it's talking to a real PostgreSQL server with logical replication enabled:
|
|
63
|
+
|
|
64
|
+
- `IDENTIFY_SYSTEM` returns a fake system ID and timeline
|
|
65
|
+
- `CREATE_REPLICATION_SLOT` persists slot info in a local table and returns a valid LSN
|
|
66
|
+
- `START_REPLICATION` enters streaming mode, encoding changes as pgoutput binary messages
|
|
67
|
+
- `current_setting('wal_level')` always returns `logical`
|
|
68
|
+
- `pg_replication_slots` queries are redirected to a local tracking table
|
|
69
|
+
- `SET TRANSACTION SNAPSHOT` is silently accepted (PGlite doesn't support imported snapshots)
|
|
70
|
+
- `ALTER ROLE ... REPLICATION` returns success
|
|
71
|
+
- `READ ONLY` is stripped from transaction starts to avoid PGlite serialization issues
|
|
72
|
+
|
|
73
|
+
The pgoutput encoder produces spec-compliant binary messages: Begin, Relation, Insert, Update, Delete, Commit, and Keepalive. All column values are encoded as text (typeOid 25), which zero-cache handles fine since it re-maps types downstream anyway.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Tests
|
|
77
|
+
|
|
78
|
+
80 unit tests across 5 test files covering the full stack from binary encoding to TCP-level integration:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
bun test
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The test suite includes a zero-cache compatibility layer that decodes pgoutput messages into the same typed format that zero-cache's PgoutputParser produces, validating end-to-end compatibility.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Limitations
|
|
88
|
+
|
|
89
|
+
This is a development tool. It is not suitable for production use.
|
|
90
|
+
|
|
91
|
+
- PGlite runs single-threaded. All queries are serialized through a mutex. This is fine for development but would be a bottleneck under real load.
|
|
92
|
+
- Column types are all encoded as text in the replication stream. Zero-cache handles this, but other pgoutput consumers might not.
|
|
93
|
+
- Triggers add overhead to every write. Again, fine for development.
|
|
94
|
+
- PGlite stores data on the local filesystem. No replication, no backups, no high availability.
|
|
95
|
+
- The S3 server is just a filesystem wrapper. No multipart uploads, no ACLs, no versioning.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Project structure
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
src/
|
|
102
|
+
index.ts main entry, orchestrates startup
|
|
103
|
+
config.ts configuration with defaults
|
|
104
|
+
pg-proxy.ts tcp proxy with query rewriting
|
|
105
|
+
pglite-manager.ts pglite instance and migration runner
|
|
106
|
+
s3-local.ts minimal s3 http server
|
|
107
|
+
replication/
|
|
108
|
+
handler.ts replication protocol state machine
|
|
109
|
+
pgoutput-encoder.ts binary pgoutput message encoder
|
|
110
|
+
change-tracker.ts trigger installation and change reader
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ZeroLiteConfig {
|
|
2
|
+
dataDir: string;
|
|
3
|
+
pgPort: number;
|
|
4
|
+
zeroPort: number;
|
|
5
|
+
s3Port: number;
|
|
6
|
+
webPort: number;
|
|
7
|
+
pgUser: string;
|
|
8
|
+
pgPassword: string;
|
|
9
|
+
migrationsDir: string;
|
|
10
|
+
seedFile: string;
|
|
11
|
+
skipZeroCache: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function getConfig(overrides?: Partial<ZeroLiteConfig>): ZeroLiteConfig;
|
|
14
|
+
export declare function getConnectionString(config: ZeroLiteConfig, dbName?: string): string;
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,SAAS,CACvB,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GACtC,cAAc,CAiBhB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,EACtB,MAAM,SAAa,GAClB,MAAM,CAER"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function getConfig(overrides = {}) {
|
|
2
|
+
return {
|
|
3
|
+
dataDir: overrides.dataDir || '.zero-lite',
|
|
4
|
+
pgPort: overrides.pgPort || 6434,
|
|
5
|
+
zeroPort: overrides.zeroPort || 5849,
|
|
6
|
+
s3Port: overrides.s3Port || 10201,
|
|
7
|
+
webPort: overrides.webPort ||
|
|
8
|
+
Number(process.env.VITE_PORT_WEB) ||
|
|
9
|
+
8081,
|
|
10
|
+
pgUser: overrides.pgUser || 'user',
|
|
11
|
+
pgPassword: overrides.pgPassword || 'password',
|
|
12
|
+
migrationsDir: overrides.migrationsDir || 'src/database/migrations',
|
|
13
|
+
seedFile: overrides.seedFile || 'src/database/seed.sql',
|
|
14
|
+
skipZeroCache: overrides.skipZeroCache || false,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function getConnectionString(config, dbName = 'postgres') {
|
|
18
|
+
return `postgresql://${config.pgUser}:${config.pgPassword}@127.0.0.1:${config.pgPort}/${dbName}`;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,SAAS,CACvB,YAAqC,EAAE;IAEvC,OAAO;QACL,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,YAAY;QAC1C,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,IAAI;QAChC,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,IAAI;QACpC,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,KAAK;QACjC,OAAO,EACL,SAAS,CAAC,OAAO;YACjB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YACjC,IAAI;QACN,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,MAAM;QAClC,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,UAAU;QAC9C,aAAa,EACX,SAAS,CAAC,aAAa,IAAI,yBAAyB;QACtD,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,uBAAuB;QACvD,aAAa,EAAE,SAAS,CAAC,aAAa,IAAI,KAAK;KAChD,CAAA;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAsB,EACtB,MAAM,GAAG,UAAU;IAEnB,OAAO,gBAAgB,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,cAAc,MAAM,CAAC,MAAM,IAAI,MAAM,EAAE,CAAA;AAClG,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* orez: pglite-powered zero-sync development backend.
|
|
3
|
+
*
|
|
4
|
+
* starts a pglite instance, tcp proxy, s3 server, and zero-cache
|
|
5
|
+
* process. replaces docker-based postgresql, zero-cache, and minio
|
|
6
|
+
* with a single `bun run` command.
|
|
7
|
+
*/
|
|
8
|
+
import type { ZeroLiteConfig } from './config';
|
|
9
|
+
export type { ZeroLiteConfig } from './config';
|
|
10
|
+
export { getConfig, getConnectionString } from './config';
|
|
11
|
+
export declare function startZeroLite(overrides?: Partial<ZeroLiteConfig>): Promise<{
|
|
12
|
+
config: ZeroLiteConfig;
|
|
13
|
+
stop: () => Promise<void>;
|
|
14
|
+
}>;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEzD,wBAAsB,aAAa,CAAC,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM;;;GAoD1E"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* orez: pglite-powered zero-sync development backend.
|
|
3
|
+
*
|
|
4
|
+
* starts a pglite instance, tcp proxy, s3 server, and zero-cache
|
|
5
|
+
* process. replaces docker-based postgresql, zero-cache, and minio
|
|
6
|
+
* with a single `bun run` command.
|
|
7
|
+
*/
|
|
8
|
+
import { resolve, join } from 'node:path';
|
|
9
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, unlinkSync, } from 'node:fs';
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { getConfig, getConnectionString } from './config';
|
|
12
|
+
import { installChangeTracking } from './replication/change-tracker';
|
|
13
|
+
import { createPGliteInstance, runMigrations } from './pglite-manager';
|
|
14
|
+
import { startPgProxy } from './pg-proxy';
|
|
15
|
+
import { startS3Server } from './s3-local';
|
|
16
|
+
export { getConfig, getConnectionString } from './config';
|
|
17
|
+
export async function startZeroLite(overrides = {}) {
|
|
18
|
+
const config = getConfig(overrides);
|
|
19
|
+
console.info('[orez] starting...');
|
|
20
|
+
console.info(`[orez] data dir: ${resolve(config.dataDir)}`);
|
|
21
|
+
mkdirSync(config.dataDir, { recursive: true });
|
|
22
|
+
// start pglite
|
|
23
|
+
const db = await createPGliteInstance(config);
|
|
24
|
+
// run migrations
|
|
25
|
+
await runMigrations(db, config);
|
|
26
|
+
// install change tracking
|
|
27
|
+
console.info('[orez] installing change tracking');
|
|
28
|
+
await installChangeTracking(db);
|
|
29
|
+
// start tcp proxy
|
|
30
|
+
const pgServer = await startPgProxy(db, config);
|
|
31
|
+
// start s3 server
|
|
32
|
+
const s3Server = await startS3Server(config);
|
|
33
|
+
// seed data if needed
|
|
34
|
+
await seedIfNeeded(db, config);
|
|
35
|
+
// write .env.local so `bun dev` connects to orez ports
|
|
36
|
+
writeEnvLocal(config);
|
|
37
|
+
// start zero-cache
|
|
38
|
+
let zeroCacheProcess = null;
|
|
39
|
+
if (!config.skipZeroCache) {
|
|
40
|
+
console.info('[orez] starting zero-cache...');
|
|
41
|
+
zeroCacheProcess = await startZeroCache(config);
|
|
42
|
+
await waitForZeroCache(config);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.info('[orez] skipping zero-cache (skipZeroCache=true)');
|
|
46
|
+
}
|
|
47
|
+
const stop = async () => {
|
|
48
|
+
console.info('[orez] shutting down...');
|
|
49
|
+
if (zeroCacheProcess) {
|
|
50
|
+
zeroCacheProcess.kill('SIGTERM');
|
|
51
|
+
}
|
|
52
|
+
pgServer.close();
|
|
53
|
+
s3Server.close();
|
|
54
|
+
await db.close();
|
|
55
|
+
cleanupEnvLocal();
|
|
56
|
+
console.info('[orez] stopped');
|
|
57
|
+
};
|
|
58
|
+
return { config, stop };
|
|
59
|
+
}
|
|
60
|
+
const ENV_LOCAL_PATH = resolve('.env.local');
|
|
61
|
+
const ENV_LOCAL_MARKER = '# auto-generated by orez';
|
|
62
|
+
function writeEnvLocal(config) {
|
|
63
|
+
const upstreamUrl = getConnectionString(config, 'postgres');
|
|
64
|
+
const cvrUrl = getConnectionString(config, 'zero_cvr');
|
|
65
|
+
const cdbUrl = getConnectionString(config, 'zero_cdb');
|
|
66
|
+
const content = `${ENV_LOCAL_MARKER}
|
|
67
|
+
VITE_PORT_POSTGRES=${config.pgPort}
|
|
68
|
+
VITE_PORT_ZERO=${config.zeroPort}
|
|
69
|
+
VITE_PORT_MINIO=${config.s3Port}
|
|
70
|
+
VITE_PUBLIC_ZERO_SERVER="http://localhost:${config.zeroPort}"
|
|
71
|
+
ZERO_UPSTREAM_DB="${upstreamUrl}"
|
|
72
|
+
ZERO_CVR_DB="${cvrUrl}"
|
|
73
|
+
ZERO_CHANGE_DB="${cdbUrl}"
|
|
74
|
+
CLOUDFLARE_R2_ENDPOINT="http://localhost:${config.s3Port}"
|
|
75
|
+
CLOUDFLARE_R2_PUBLIC_URL="http://localhost:${config.s3Port}"
|
|
76
|
+
`;
|
|
77
|
+
writeFileSync(ENV_LOCAL_PATH, content);
|
|
78
|
+
console.info('[orez] wrote .env.local for dev server');
|
|
79
|
+
}
|
|
80
|
+
function cleanupEnvLocal() {
|
|
81
|
+
try {
|
|
82
|
+
if (existsSync(ENV_LOCAL_PATH)) {
|
|
83
|
+
const content = readFileSync(ENV_LOCAL_PATH, 'utf-8');
|
|
84
|
+
if (content.startsWith(ENV_LOCAL_MARKER)) {
|
|
85
|
+
unlinkSync(ENV_LOCAL_PATH);
|
|
86
|
+
console.info('[orez] cleaned up .env.local');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// ignore cleanup errors
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function seedIfNeeded(db, config) {
|
|
95
|
+
// check if we already have data
|
|
96
|
+
try {
|
|
97
|
+
const result = await db.query('SELECT count(*) as count FROM public."user"');
|
|
98
|
+
if (Number(result.rows[0].count) > 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// table might not exist yet
|
|
104
|
+
}
|
|
105
|
+
console.info('[orez] seeding demo data...');
|
|
106
|
+
const seedFile = resolve(config.seedFile);
|
|
107
|
+
if (!existsSync(seedFile)) {
|
|
108
|
+
console.info('[orez] no seed file found, skipping');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const sql = readFileSync(seedFile, 'utf-8');
|
|
112
|
+
const statements = sql
|
|
113
|
+
.split('--> statement-breakpoint')
|
|
114
|
+
.map((s) => s.trim())
|
|
115
|
+
.filter(Boolean);
|
|
116
|
+
for (const stmt of statements) {
|
|
117
|
+
await db.exec(stmt);
|
|
118
|
+
}
|
|
119
|
+
console.info('[orez] seeded demo data');
|
|
120
|
+
}
|
|
121
|
+
async function startZeroCache(config) {
|
|
122
|
+
// find zero-cache binary
|
|
123
|
+
const zeroCachePaths = [
|
|
124
|
+
resolve('node_modules/.bin/zero-cache'),
|
|
125
|
+
resolve('node_modules/@rocicorp/zero/out/zero-cache/src/bin/main.js'),
|
|
126
|
+
];
|
|
127
|
+
let zeroCacheBin = '';
|
|
128
|
+
for (const p of zeroCachePaths) {
|
|
129
|
+
if (existsSync(p)) {
|
|
130
|
+
zeroCacheBin = p;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!zeroCacheBin) {
|
|
135
|
+
throw new Error('zero-cache binary not found. install @rocicorp/zero');
|
|
136
|
+
}
|
|
137
|
+
const upstreamUrl = getConnectionString(config, 'postgres');
|
|
138
|
+
const cvrUrl = getConnectionString(config, 'zero_cvr');
|
|
139
|
+
const cdbUrl = getConnectionString(config, 'zero_cdb');
|
|
140
|
+
const env = {
|
|
141
|
+
...process.env,
|
|
142
|
+
NODE_ENV: 'development',
|
|
143
|
+
ZERO_UPSTREAM_DB: upstreamUrl,
|
|
144
|
+
ZERO_CVR_DB: cvrUrl,
|
|
145
|
+
ZERO_CHANGE_DB: cdbUrl,
|
|
146
|
+
ZERO_REPLICA_FILE: resolve(config.dataDir, 'zero-replica.db'),
|
|
147
|
+
ZERO_PORT: String(config.zeroPort),
|
|
148
|
+
ZERO_MUTATE_URL: `http://localhost:${config.webPort}/api/zero/push`,
|
|
149
|
+
ZERO_QUERY_URL: `http://localhost:${config.webPort}/api/zero/pull`,
|
|
150
|
+
ZERO_LOG_LEVEL: 'info',
|
|
151
|
+
ZERO_NUM_SYNC_WORKERS: '1',
|
|
152
|
+
DO_NOT_TRACK: '1',
|
|
153
|
+
};
|
|
154
|
+
const child = spawn(zeroCacheBin, [], {
|
|
155
|
+
env,
|
|
156
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
157
|
+
});
|
|
158
|
+
child.stdout?.on('data', (data) => {
|
|
159
|
+
const lines = data.toString().trim().split('\n');
|
|
160
|
+
for (const line of lines) {
|
|
161
|
+
console.info(`[zero-cache] ${line}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
child.stderr?.on('data', (data) => {
|
|
165
|
+
const lines = data.toString().trim().split('\n');
|
|
166
|
+
for (const line of lines) {
|
|
167
|
+
console.info(`[zero-cache] ${line}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
child.on('exit', (code) => {
|
|
171
|
+
if (code !== 0 && code !== null) {
|
|
172
|
+
console.info(`[zero-cache] exited with code ${code}`);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return child;
|
|
176
|
+
}
|
|
177
|
+
async function waitForZeroCache(config, timeoutMs = 60000) {
|
|
178
|
+
const start = Date.now();
|
|
179
|
+
const url = `http://127.0.0.1:${config.zeroPort}/`;
|
|
180
|
+
while (Date.now() - start < timeoutMs) {
|
|
181
|
+
try {
|
|
182
|
+
const res = await fetch(url);
|
|
183
|
+
if (res.ok) {
|
|
184
|
+
console.info('[orez] zero-cache is ready');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// not ready yet
|
|
190
|
+
}
|
|
191
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
192
|
+
}
|
|
193
|
+
console.info('[orez] warning: zero-cache health check timed out, continuing anyway');
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tcp proxy that makes pglite speak postgresql wire protocol.
|
|
3
|
+
*
|
|
4
|
+
* uses pg-gateway to handle protocol lifecycle for regular connections,
|
|
5
|
+
* and directly handles the raw socket for replication connections.
|
|
6
|
+
*
|
|
7
|
+
* regular connections: forwarded to pglite via execProtocolRaw()
|
|
8
|
+
* replication connections: intercepted, replication protocol faked
|
|
9
|
+
*/
|
|
10
|
+
import { type Server } from 'node:net';
|
|
11
|
+
import type { PGlite } from '@electric-sql/pglite';
|
|
12
|
+
import type { ZeroLiteConfig } from './config';
|
|
13
|
+
export declare function startPgProxy(db: PGlite, config: ZeroLiteConfig): Promise<Server>;
|
|
14
|
+
//# sourceMappingURL=pg-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg-proxy.d.ts","sourceRoot":"","sources":["../src/pg-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAgB,KAAK,MAAM,EAAe,MAAM,UAAU,CAAA;AAIjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAgR9C,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,MAAM,CAAC,CAoHjB"}
|