orez 0.0.18 → 0.0.20

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 (45) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config.js +1 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +46 -12
  8. package/dist/index.js.map +1 -1
  9. package/dist/mutex.d.ts +7 -0
  10. package/dist/mutex.d.ts.map +1 -0
  11. package/dist/mutex.js +24 -0
  12. package/dist/mutex.js.map +1 -0
  13. package/dist/pg-proxy.d.ts +6 -1
  14. package/dist/pg-proxy.d.ts.map +1 -1
  15. package/dist/pg-proxy.js +64 -76
  16. package/dist/pg-proxy.js.map +1 -1
  17. package/dist/pglite-manager.d.ts +14 -1
  18. package/dist/pglite-manager.d.ts.map +1 -1
  19. package/dist/pglite-manager.js +37 -18
  20. package/dist/pglite-manager.js.map +1 -1
  21. package/dist/replication/change-tracker.d.ts +7 -0
  22. package/dist/replication/change-tracker.d.ts.map +1 -1
  23. package/dist/replication/change-tracker.js +40 -3
  24. package/dist/replication/change-tracker.js.map +1 -1
  25. package/dist/replication/handler.d.ts +2 -1
  26. package/dist/replication/handler.d.ts.map +1 -1
  27. package/dist/replication/handler.js +136 -60
  28. package/dist/replication/handler.js.map +1 -1
  29. package/dist/replication/pgoutput-encoder.d.ts.map +1 -1
  30. package/dist/replication/pgoutput-encoder.js +11 -1
  31. package/dist/replication/pgoutput-encoder.js.map +1 -1
  32. package/package.json +3 -3
  33. package/src/cli.ts +1 -1
  34. package/src/config.ts +1 -1
  35. package/src/index.ts +45 -12
  36. package/src/integration/integration.test.ts +24 -14
  37. package/src/mutex.ts +24 -0
  38. package/src/pg-proxy.ts +78 -76
  39. package/src/pglite-manager.ts +48 -18
  40. package/src/replication/change-tracker.test.ts +4 -4
  41. package/src/replication/change-tracker.ts +49 -3
  42. package/src/replication/handler.test.ts +18 -8
  43. package/src/replication/handler.ts +179 -69
  44. package/src/replication/pgoutput-encoder.ts +9 -1
  45. package/src/replication/zero-compat.test.ts +7 -3
@@ -1 +1 @@
1
- {"version":3,"file":"pgoutput-encoder.js","sourceRoot":"","sources":["../../src/replication/pgoutput-encoder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pgoutput-encoder.js","sourceRoot":"","sources":["../../src/replication/pgoutput-encoder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orez",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "PGlite-powered zero-sync development backend. No Docker required.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,7 +32,7 @@
32
32
  "dev": "tsc --watch",
33
33
  "test": "vitest run",
34
34
  "test:watch": "vitest",
35
- "lint": "oxlint --import-plugin",
35
+ "lint": "oxlint --import-plugin --ignore-pattern sqlite-wasm/",
36
36
  "format": "oxfmt .",
37
37
  "format:check": "oxfmt --check .",
38
38
  "check": "tsc --noEmit",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@electric-sql/pglite": "^0.2.17",
45
45
  "@rocicorp/zero": ">=0.1.0",
46
- "bedrock-sqlite": "0.0.10",
46
+ "bedrock-sqlite": "0.0.12",
47
47
  "citty": "^0.2.0",
48
48
  "pg-gateway": "^0.3.0-beta.4"
49
49
  },
package/src/cli.ts CHANGED
@@ -105,7 +105,7 @@ const main = defineCommand({
105
105
  'disable-wasm-sqlite': {
106
106
  type: 'boolean',
107
107
  description: 'use native @rocicorp/zero-sqlite3 instead of wasm bedrock-sqlite',
108
- default: false,
108
+ default: true,
109
109
  },
110
110
  'on-db-ready': {
111
111
  type: 'string',
package/src/config.ts CHANGED
@@ -27,7 +27,7 @@ export function getConfig(overrides: Partial<ZeroLiteConfig> = {}): ZeroLiteConf
27
27
  migrationsDir: overrides.migrationsDir || '',
28
28
  seedFile: overrides.seedFile || 'src/database/seed.sql',
29
29
  skipZeroCache: overrides.skipZeroCache || false,
30
- disableWasmSqlite: overrides.disableWasmSqlite || false,
30
+ disableWasmSqlite: overrides.disableWasmSqlite ?? true,
31
31
  logLevel: overrides.logLevel || 'info',
32
32
  pgliteOptions: overrides.pgliteOptions || {},
33
33
  onDbReady: overrides.onDbReady || '',
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ import { basename, dirname, resolve } from 'node:path'
14
14
  import { getConfig, getConnectionString } from './config.js'
15
15
  import { log, setLogLevel } from './log.js'
16
16
  import { startPgProxy } from './pg-proxy.js'
17
- import { createPGliteInstance, runMigrations } from './pglite-manager.js'
17
+ import { createPGliteInstances, runMigrations } from './pglite-manager.js'
18
18
  import { findPort } from './port.js'
19
19
  import { installChangeTracking } from './replication/change-tracker.js'
20
20
 
@@ -57,18 +57,19 @@ export async function startZeroLite(overrides: Partial<ZeroLiteConfig> = {}) {
57
57
 
58
58
  mkdirSync(config.dataDir, { recursive: true })
59
59
 
60
- // start pglite
61
- const db = await createPGliteInstance(config)
60
+ // start pglite (separate instances for postgres, zero_cvr, zero_cdb)
61
+ const instances = await createPGliteInstances(config)
62
+ const db = instances.postgres
62
63
 
63
- // run migrations
64
+ // run migrations (on postgres instance only)
64
65
  await runMigrations(db, config)
65
66
 
66
- // install change tracking
67
+ // install change tracking (on postgres instance only)
67
68
  log.debug.orez('installing change tracking')
68
69
  await installChangeTracking(db)
69
70
 
70
- // start tcp proxy
71
- const pgServer = await startPgProxy(db, config)
71
+ // start tcp proxy (routes connections to correct instance by database name)
72
+ const pgServer = await startPgProxy(instances, config)
72
73
 
73
74
  // seed data if needed
74
75
  await seedIfNeeded(db, config)
@@ -143,12 +144,12 @@ export async function startZeroLite(overrides: Partial<ZeroLiteConfig> = {}) {
143
144
  })
144
145
  }
145
146
  pgServer.close()
146
- await db.close()
147
+ await Promise.all([instances.postgres.close(), instances.cvr.close(), instances.cdb.close()])
147
148
  cleanupEnvLocal()
148
149
  log.orez('stopped')
149
150
  }
150
151
 
151
- return { config, stop, db, pgPort: config.pgPort, zeroPort: config.zeroPort }
152
+ return { config, stop, db, instances, pgPort: config.pgPort, zeroPort: config.zeroPort }
152
153
  }
153
154
 
154
155
  // use .env.development.local so it overrides .env.development in vite's load order:
@@ -272,6 +273,15 @@ function patchSqliteForWasm(): void {
272
273
  if (current.includes('OrigDatabase')) return // already patched
273
274
  }
274
275
 
276
+ // back up originals before patching
277
+ if (existsSync(indexPath)) {
278
+ writeFileSync(indexPath + '.original', readFileSync(indexPath))
279
+ }
280
+ const dbBackupPath = resolve(libDir, 'database.js')
281
+ if (existsSync(dbBackupPath)) {
282
+ writeFileSync(dbBackupPath + '.original', readFileSync(dbBackupPath))
283
+ }
284
+
275
285
  // resolve bedrock-sqlite's dist entry point
276
286
  const bedrockEntry = resolvePackage('bedrock-sqlite')
277
287
  if (!existsSync(bedrockEntry)) {
@@ -287,9 +297,6 @@ var OrigDatabase = mod.Database;
287
297
  var SqliteError = mod.SqliteError;
288
298
 
289
299
  // wrap constructor to set busy_timeout on every connection immediately.
290
- // VFS nodejsLock retries with Atomics.wait, and nodejsSleep enables
291
- // SQLite's busy handler - so busy_timeout works properly in WASM now.
292
- // WAL mode is left to zero-cache to manage (needed for BEGIN CONCURRENT).
293
300
  function Database() {
294
301
  var db = new OrigDatabase(...arguments);
295
302
  try {
@@ -358,6 +365,31 @@ module.exports.SqliteError = SqliteError;
358
365
  }
359
366
  }
360
367
 
368
+ function unpatchSqliteWasm(): void {
369
+ // restore native @rocicorp/zero-sqlite3 if it was previously patched
370
+ try {
371
+ const sqliteEntry = resolvePackage('@rocicorp/zero-sqlite3')
372
+ if (!sqliteEntry) return
373
+ const libDir = resolve(sqliteEntry, '..')
374
+ const indexPath = resolve(libDir, 'index.js')
375
+ if (!existsSync(indexPath)) return
376
+ const current = readFileSync(indexPath, 'utf-8')
377
+ if (!current.includes('OrigDatabase')) return // not patched
378
+
379
+ // restore from backups if available
380
+ for (const file of ['index.js', 'database.js']) {
381
+ const filePath = resolve(libDir, file)
382
+ const backupPath = filePath + '.original'
383
+ if (existsSync(backupPath)) {
384
+ writeFileSync(filePath, readFileSync(backupPath))
385
+ }
386
+ }
387
+ log.orez('restored native @rocicorp/zero-sqlite3 (removed wasm patch)')
388
+ } catch (e) {
389
+ log.orez(`failed to restore native sqlite: ${e}`)
390
+ }
391
+ }
392
+
361
393
  async function startZeroCache(config: ZeroLiteConfig): Promise<ChildProcess> {
362
394
  // resolve @rocicorp/zero entry for finding zero-cache modules
363
395
  const zeroEntry = resolvePackage('@rocicorp/zero')
@@ -370,6 +402,7 @@ async function startZeroCache(config: ZeroLiteConfig): Promise<ChildProcess> {
370
402
  if (!config.disableWasmSqlite) {
371
403
  patchSqliteForWasm()
372
404
  } else {
405
+ unpatchSqliteWasm()
373
406
  log.debug.orez('wasm sqlite disabled, using native @rocicorp/zero-sqlite3')
374
407
  }
375
408
 
@@ -9,13 +9,18 @@
9
9
 
10
10
  import { describe, expect, test, beforeAll, afterAll, beforeEach } from 'vitest'
11
11
  import WebSocket from 'ws'
12
+
12
13
  import { startZeroLite } from '../index.js'
14
+
13
15
  import type { PGlite } from '@electric-sql/pglite'
14
16
 
15
17
  // simple async queue for collecting websocket messages
16
18
  class Queue<T> {
17
19
  private items: T[] = []
18
- private waiters: Array<{ resolve: (v: T) => void; timer?: ReturnType<typeof setTimeout> }> = []
20
+ private waiters: Array<{
21
+ resolve: (v: T) => void
22
+ timer?: ReturnType<typeof setTimeout>
23
+ }> = []
19
24
 
20
25
  enqueue(item: T) {
21
26
  const waiter = this.waiters.shift()
@@ -113,7 +118,7 @@ describe('orez integration', { timeout: 120000 }, () => {
113
118
  test('zero-cache starts and accepts websocket connections', async () => {
114
119
  const ws = new WebSocket(
115
120
  `ws://localhost:${zeroPort}/sync/v4/connect` +
116
- `?clientGroupID=test-cg&clientID=test-client&wsid=ws1&schemaVersion=1&baseCookie=&ts=${Date.now()}&lmid=0`,
121
+ `?clientGroupID=test-cg&clientID=test-client&wsid=ws1&schemaVersion=1&baseCookie=&ts=${Date.now()}&lmid=0`
117
122
  )
118
123
 
119
124
  const connected = new Promise<void>((resolve, reject) => {
@@ -161,7 +166,7 @@ describe('orez integration', { timeout: 120000 }, () => {
161
166
  value: 'hello',
162
167
  }),
163
168
  }),
164
- ]),
169
+ ])
165
170
  )
166
171
 
167
172
  ws.close()
@@ -196,7 +201,7 @@ describe('orez integration', { timeout: 120000 }, () => {
196
201
  value: 'live-value',
197
202
  }),
198
203
  }),
199
- ]),
204
+ ])
200
205
  )
201
206
 
202
207
  ws.close()
@@ -236,7 +241,7 @@ describe('orez integration', { timeout: 120000 }, () => {
236
241
  value: 'updated',
237
242
  }),
238
243
  }),
239
- ]),
244
+ ])
240
245
  )
241
246
 
242
247
  ws.close()
@@ -267,7 +272,7 @@ describe('orez integration', { timeout: 120000 }, () => {
267
272
  op: 'del',
268
273
  tableName: 'foo',
269
274
  }),
270
- ]),
275
+ ])
271
276
  )
272
277
 
273
278
  ws.close()
@@ -289,8 +294,8 @@ describe('orez integration', { timeout: 120000 }, () => {
289
294
  `concurrent-${i}`,
290
295
  `value-${i}`,
291
296
  i,
292
- ]),
293
- ),
297
+ ])
298
+ )
294
299
  )
295
300
 
296
301
  // collect all poke parts within a window
@@ -316,11 +321,11 @@ describe('orez integration', { timeout: 120000 }, () => {
316
321
  function connectAndSubscribe(
317
322
  port: number,
318
323
  downstream: Queue<unknown>,
319
- query: Record<string, unknown>,
324
+ query: Record<string, unknown>
320
325
  ): WebSocket {
321
326
  const ws = new WebSocket(
322
327
  `ws://localhost:${port}/sync/v4/connect` +
323
- `?clientGroupID=test-cg-${Date.now()}&clientID=test-client&wsid=ws1&schemaVersion=1&baseCookie=&ts=${Date.now()}&lmid=0`,
328
+ `?clientGroupID=test-cg-${Date.now()}&clientID=test-client&wsid=ws1&schemaVersion=1&baseCookie=&ts=${Date.now()}&lmid=0`
324
329
  )
325
330
 
326
331
  ws.on('message', (data) => {
@@ -334,7 +339,7 @@ describe('orez integration', { timeout: 120000 }, () => {
334
339
  {
335
340
  desiredQueriesPatch: [{ op: 'put', hash: 'q1', ast: query }],
336
341
  },
337
- ]),
342
+ ])
338
343
  )
339
344
  })
340
345
 
@@ -363,7 +368,7 @@ describe('orez integration', { timeout: 120000 }, () => {
363
368
 
364
369
  async function waitForPokePart(
365
370
  downstream: Queue<unknown>,
366
- timeoutMs = 10000,
371
+ timeoutMs = 10000
367
372
  ): Promise<Record<string, any>> {
368
373
  const deadline = Date.now() + timeoutMs
369
374
  while (Date.now() < deadline) {
@@ -379,7 +384,7 @@ describe('orez integration', { timeout: 120000 }, () => {
379
384
 
380
385
  async function collectPokeRows(
381
386
  downstream: Queue<unknown>,
382
- windowMs = 5000,
387
+ windowMs = 5000
383
388
  ): Promise<any[]> {
384
389
  const rows: any[] = []
385
390
  const deadline = Date.now() + windowMs
@@ -392,7 +397,12 @@ describe('orez integration', { timeout: 120000 }, () => {
392
397
  rows.push(...msg[1].rowsPatch)
393
398
  // check if more poke parts come quickly
394
399
  const more = (await downstream.dequeue('timeout' as any, 2000)) as any
395
- if (more !== 'timeout' && Array.isArray(more) && more[0] === 'pokePart' && more[1]?.rowsPatch) {
400
+ if (
401
+ more !== 'timeout' &&
402
+ Array.isArray(more) &&
403
+ more[0] === 'pokePart' &&
404
+ more[1]?.rowsPatch
405
+ ) {
396
406
  rows.push(...more[1].rowsPatch)
397
407
  }
398
408
  break
package/src/mutex.ts ADDED
@@ -0,0 +1,24 @@
1
+ // simple mutex for serializing pglite access
2
+ export class Mutex {
3
+ private locked = false
4
+ private queue: Array<() => void> = []
5
+
6
+ async acquire(): Promise<void> {
7
+ if (!this.locked) {
8
+ this.locked = true
9
+ return
10
+ }
11
+ return new Promise<void>((resolve) => {
12
+ this.queue.push(resolve)
13
+ })
14
+ }
15
+
16
+ release(): void {
17
+ const next = this.queue.shift()
18
+ if (next) {
19
+ next()
20
+ } else {
21
+ this.locked = false
22
+ }
23
+ }
24
+ }
package/src/pg-proxy.ts CHANGED
@@ -6,6 +6,10 @@
6
6
  *
7
7
  * regular connections: forwarded to pglite via execProtocolRaw()
8
8
  * replication connections: intercepted, replication protocol faked
9
+ *
10
+ * each "database" (postgres, zero_cvr, zero_cdb) maps to its own pglite
11
+ * instance with independent transaction context, preventing cross-database
12
+ * query interleaving that causes CVR concurrent modification errors.
9
13
  */
10
14
 
11
15
  import { createServer, type Server, type Socket } from 'node:net'
@@ -14,16 +18,11 @@ import { fromNodeSocket } from 'pg-gateway/node'
14
18
 
15
19
  import { log } from './log.js'
16
20
  import { handleReplicationQuery, handleStartReplication } from './replication/handler.js'
21
+ import { Mutex } from './mutex.js'
17
22
 
18
23
  import type { ZeroLiteConfig } from './config.js'
19
24
  import type { PGlite } from '@electric-sql/pglite'
20
-
21
- // database name -> search_path mapping
22
- const DB_SCHEMA_MAP: Record<string, string> = {
23
- postgres: 'public',
24
- zero_cvr: 'zero_cvr, public',
25
- zero_cdb: 'zero_cdb, public',
26
- }
25
+ import type { PGliteInstances } from './pglite-manager.js'
27
26
 
28
27
  // query rewrites: make pglite look like real postgres with logical replication
29
28
  const QUERY_REWRITES: Array<{ match: RegExp; replace: string }> = [
@@ -32,26 +31,33 @@ const QUERY_REWRITES: Array<{ match: RegExp; replace: string }> = [
32
31
  match: /current_setting\s*\(\s*'wal_level'\s*\)/gi,
33
32
  replace: "'logical'::text",
34
33
  },
35
- // strip READ ONLY from BEGIN
34
+ // strip READ ONLY from BEGIN (pglite is single-session, no read-only transactions)
36
35
  {
37
36
  match: /\bREAD\s+ONLY\b/gi,
38
37
  replace: '',
39
38
  },
39
+ // strip ISOLATION LEVEL from any query (pglite is single-session, isolation is meaningless)
40
+ // catches: SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, BEGIN ISOLATION LEVEL SERIALIZABLE, etc.
41
+ {
42
+ match:
43
+ /\bISOLATION\s+LEVEL\s+(SERIALIZABLE|REPEATABLE\s+READ|READ\s+COMMITTED|READ\s+UNCOMMITTED)\b/gi,
44
+ replace: '',
45
+ },
46
+ // strip bare SET TRANSACTION (after ISOLATION LEVEL is removed, this becomes a no-op statement)
47
+ {
48
+ match: /\bSET\s+TRANSACTION\s*;/gi,
49
+ replace: ';',
50
+ },
40
51
  // redirect pg_replication_slots to our fake table
41
52
  {
42
53
  match: /\bpg_replication_slots\b/g,
43
54
  replace: 'public._zero_replication_slots',
44
55
  },
45
- // SET TRANSACTION queries: rewrite to SELECT 1 (PGlite doesn't support them,
46
- // and no-op interception doesn't work for extended protocol Bind/Execute)
47
- {
48
- match: /^\s*SET\s+TRANSACTION\b.*$/gis,
49
- replace: 'SELECT 1',
50
- },
51
56
  ]
52
57
 
53
- // queries to intercept and return no-op success
54
- const NOOP_QUERY_PATTERNS: RegExp[] = []
58
+ // queries to intercept and return no-op success (synthetic SET response)
59
+ // pglite rejects SET TRANSACTION if any query (e.g. SET search_path) ran first
60
+ const NOOP_QUERY_PATTERNS: RegExp[] = [/^\s*SET\s+TRANSACTION\b/i, /^\s*SET\s+SESSION\b/i]
55
61
 
56
62
  /**
57
63
  * extract query text from a Parse message (0x50).
@@ -239,37 +245,30 @@ function stripReadyForQuery(data: Uint8Array): Uint8Array {
239
245
  return result
240
246
  }
241
247
 
242
- // simple mutex for serializing pglite access
243
- class Mutex {
244
- private locked = false
245
- private queue: Array<() => void> = []
246
-
247
- async acquire(): Promise<void> {
248
- if (!this.locked) {
249
- this.locked = true
250
- return
251
- }
252
- return new Promise<void>((resolve) => {
253
- this.queue.push(resolve)
254
- })
248
+ export async function startPgProxy(
249
+ dbInput: PGlite | PGliteInstances,
250
+ config: ZeroLiteConfig
251
+ ): Promise<Server> {
252
+ // normalize input: single PGlite instance = use it for all databases (backwards compat for tests)
253
+ const instances: PGliteInstances =
254
+ 'postgres' in dbInput
255
+ ? (dbInput as PGliteInstances)
256
+ : { postgres: dbInput as PGlite, cvr: dbInput as PGlite, cdb: dbInput as PGlite }
257
+
258
+ // per-instance mutexes for serializing pglite access
259
+ const mutexes = {
260
+ postgres: new Mutex(),
261
+ cvr: new Mutex(),
262
+ cdb: new Mutex(),
255
263
  }
256
264
 
257
- release(): void {
258
- const next = this.queue.shift()
259
- if (next) {
260
- next()
261
- } else {
262
- this.locked = false
263
- }
265
+ // helper to get instance + mutex for a database name
266
+ function getDbContext(dbName: string): { db: PGlite; mutex: Mutex } {
267
+ if (dbName === 'zero_cvr') return { db: instances.cvr, mutex: mutexes.cvr }
268
+ if (dbName === 'zero_cdb') return { db: instances.cdb, mutex: mutexes.cdb }
269
+ return { db: instances.postgres, mutex: mutexes.postgres }
264
270
  }
265
- }
266
-
267
- const mutex = new Mutex()
268
271
 
269
- // module-level search_path tracking
270
- let currentSearchPath = 'public'
271
-
272
- export async function startPgProxy(db: PGlite, config: ZeroLiteConfig): Promise<Server> {
273
272
  const server = createServer(async (socket: Socket) => {
274
273
  // prevent idle timeouts from killing connections
275
274
  socket.setKeepAlive(true, 30000)
@@ -280,11 +279,12 @@ export async function startPgProxy(db: PGlite, config: ZeroLiteConfig): Promise<
280
279
 
281
280
  // clean up pglite transaction state when a client disconnects
282
281
  socket.on('close', async () => {
282
+ const { db, mutex } = getDbContext(dbName)
283
283
  await mutex.acquire()
284
284
  try {
285
285
  await db.exec('ROLLBACK')
286
286
  } catch {
287
- // no transaction to rollback, that's fine
287
+ // no transaction to rollback
288
288
  } finally {
289
289
  mutex.release()
290
290
  }
@@ -318,13 +318,14 @@ export async function startPgProxy(db: PGlite, config: ZeroLiteConfig): Promise<
318
318
  log.debug.proxy(
319
319
  `connection: db=${dbName} user=${params?.user} replication=${params?.replication || 'none'}`
320
320
  )
321
+ const { db } = getDbContext(dbName)
321
322
  await db.waitReady
322
323
  },
323
324
 
324
325
  async onMessage(data, state) {
325
326
  if (!state.isAuthenticated) return
326
327
 
327
- // handle replication connections
328
+ // handle replication connections (always go to postgres instance)
328
329
  if (isReplicationConnection) {
329
330
  if (data[0] === 0x51) {
330
331
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength)
@@ -334,7 +335,13 @@ export async function startPgProxy(db: PGlite, config: ZeroLiteConfig): Promise<
334
335
  .replace(/\0$/, '')
335
336
  log.debug.proxy(`repl query: ${query.slice(0, 200)}`)
336
337
  }
337
- return handleReplicationMessage(data, socket, db, connection)
338
+ return handleReplicationMessage(
339
+ data,
340
+ socket,
341
+ instances.postgres,
342
+ mutexes.postgres,
343
+ connection
344
+ )
338
345
  }
339
346
 
340
347
  // check for no-op queries
@@ -349,31 +356,27 @@ export async function startPgProxy(db: PGlite, config: ZeroLiteConfig): Promise<
349
356
  // intercept and rewrite queries
350
357
  data = interceptQuery(data)
351
358
 
352
- // regular query: set search_path based on database name, then forward
359
+ // message-level locking on the connection's pglite instance
360
+ const { db, mutex } = getDbContext(dbName)
353
361
  await mutex.acquire()
362
+
363
+ let result: Uint8Array
354
364
  try {
355
- const searchPath = DB_SCHEMA_MAP[dbName] || 'public'
356
- if (currentSearchPath !== searchPath) {
357
- try {
358
- await db.exec(`SET search_path TO ${searchPath}`)
359
- } catch {
360
- // pglite may be in aborted transaction state — reset it
361
- await db.exec('ROLLBACK')
362
- await db.exec(`SET search_path TO ${searchPath}`)
363
- }
364
- currentSearchPath = searchPath
365
- }
366
- let result = await db.execProtocolRaw(data, {
365
+ result = await db.execProtocolRaw(data, {
367
366
  throwOnError: false,
368
367
  })
369
- // strip ReadyForQuery from non-Sync responses
370
- if (data[0] !== 0x53 && data[0] !== 0x51) {
371
- result = stripReadyForQuery(result)
372
- }
373
- return result
374
- } finally {
368
+ } catch (err) {
375
369
  mutex.release()
370
+ throw err
376
371
  }
372
+
373
+ // strip ReadyForQuery from non-Sync/non-SimpleQuery responses
374
+ if (data[0] !== 0x53 && data[0] !== 0x51) {
375
+ result = stripReadyForQuery(result)
376
+ }
377
+
378
+ mutex.release()
379
+ return result
377
380
  },
378
381
  })
379
382
  } catch (err) {
@@ -396,6 +399,7 @@ async function handleReplicationMessage(
396
399
  data: Uint8Array,
397
400
  socket: Socket,
398
401
  db: PGlite,
402
+ mutex: Mutex,
399
403
  connection: Awaited<ReturnType<typeof fromNodeSocket>>
400
404
  ): Promise<Uint8Array | undefined> {
401
405
  if (data[0] !== 0x51) return undefined
@@ -424,24 +428,22 @@ async function handleReplicationMessage(
424
428
  socket.destroy()
425
429
  })
426
430
 
427
- handleStartReplication(query, writer, db).catch((err) => {
431
+ handleStartReplication(query, writer, db, mutex).catch((err) => {
428
432
  log.debug.proxy(`replication stream ended: ${err}`)
429
433
  })
430
434
  return undefined
431
435
  }
432
436
 
433
- // handle other replication queries
434
- const response = await handleReplicationQuery(query, db)
435
- if (response) return response
436
-
437
- // fall through to pglite for unrecognized queries
437
+ // handle replication queries + fallthrough to pglite, all under mutex
438
438
  await mutex.acquire()
439
439
  try {
440
- const searchPath = 'public'
441
- if (currentSearchPath !== searchPath) {
442
- await db.exec(`SET search_path TO ${searchPath}`)
443
- currentSearchPath = searchPath
444
- }
440
+ const response = await handleReplicationQuery(query, db)
441
+ if (response) return response
442
+
443
+ // apply query rewrites before forwarding
444
+ data = interceptQuery(data)
445
+
446
+ // fall through to pglite for unrecognized queries
445
447
  return await db.execProtocolRaw(data, {
446
448
  throwOnError: false,
447
449
  })