orez 0.2.26 → 0.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cf-do/worker.d.ts.map +1 -1
- package/dist/cf-do/worker.js +9 -1
- package/dist/cf-do/worker.js.map +1 -1
- package/dist/pg-proxy-do-backend.d.ts +2 -0
- package/dist/pg-proxy-do-backend.d.ts.map +1 -1
- package/dist/pg-proxy-do-backend.js +49 -7
- package/dist/pg-proxy-do-backend.js.map +1 -1
- package/dist/pg-sqlite-compiler/catalog/seed.d.ts +67 -0
- package/dist/pg-sqlite-compiler/catalog/seed.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/catalog/seed.js +436 -0
- package/dist/pg-sqlite-compiler/catalog/seed.js.map +1 -0
- package/dist/pg-sqlite-compiler/index.d.ts +12 -0
- package/dist/pg-sqlite-compiler/index.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/index.js +59 -0
- package/dist/pg-sqlite-compiler/index.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts +48 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.js +93 -0
- package/dist/pg-sqlite-compiler/passes/ast-utils.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/catalog.d.ts +34 -0
- package/dist/pg-sqlite-compiler/passes/catalog.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/catalog.js +30 -0
- package/dist/pg-sqlite-compiler/passes/catalog.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/datetime.d.ts +21 -0
- package/dist/pg-sqlite-compiler/passes/datetime.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/datetime.js +53 -0
- package/dist/pg-sqlite-compiler/passes/datetime.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/index.d.ts +21 -0
- package/dist/pg-sqlite-compiler/passes/index.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/index.js +39 -0
- package/dist/pg-sqlite-compiler/passes/index.js.map +1 -0
- package/dist/pg-sqlite-compiler/passes/types.d.ts +41 -0
- package/dist/pg-sqlite-compiler/passes/types.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/passes/types.js +103 -0
- package/dist/pg-sqlite-compiler/passes/types.js.map +1 -0
- package/dist/pg-sqlite-compiler/test/oracle.d.ts +34 -0
- package/dist/pg-sqlite-compiler/test/oracle.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/test/oracle.js +204 -0
- package/dist/pg-sqlite-compiler/test/oracle.js.map +1 -0
- package/dist/pg-sqlite-compiler/types.d.ts +55 -0
- package/dist/pg-sqlite-compiler/types.d.ts.map +1 -0
- package/dist/pg-sqlite-compiler/types.js +2 -0
- package/dist/pg-sqlite-compiler/types.js.map +1 -0
- package/package.json +8 -4
- package/src/admin/admin-data.test.ts +0 -348
- package/src/admin/http-proxy.ts +0 -252
- package/src/admin/log-store.ts +0 -192
- package/src/admin/server.ts +0 -471
- package/src/admin/ui.ts +0 -1322
- package/src/bench/proxy-throughput.bench.ts +0 -343
- package/src/bench/serial-mutations.bench.ts +0 -270
- package/src/browser.ts +0 -203
- package/src/cf-do/.wrangler/cache/cf.json +0 -1
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0f0f3bdf0abda097eb6f1246db4657d9fc622081362d894d82c1a1ce067b05b6.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/1ddd3a4a48a11b51658444f5458a1fb175194b1d5b6a5bda20ef3fe3205b900c.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/204a39120310d37e972c5914cfd71ad55c151bdb9e8ed289a5f8c5b052dd60e4.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/3835f242df9728adba3d127a238793fd054ed3e51df3f60749ee744c469bf2a2.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/4aa9c80eb716cf55b8995ccf7afab0b36c683e6da07d7c37a3f9c570136036df.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/533e2fd1d6ea46e7a9a0017916ef341802d438d72583462755f2c1f8225e9bf2.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/5ffa1aced1225ecaeac6366f7586aa3de92761cdff8711d81fbd81f248076abd.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/686c3a9f0d7e59ed2ab607efd4b76d779c97cafeb3818380033bf7c7eb86c819.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/6e8214e8dcfadd0deb52d64e5e9ca85c6b329ace11193909845995396914c473.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/78d9ec9ff873d3fe3507ff53c2a6f6dfc408b4268eb0db3f2a146c0678965366.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/7eff9f0ed7e27ad0d3f9d923de0682fab1928591172c1ba336c5f79a134a5d85.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/836cda5b995b25867d722ed4f4c2292167e80351a3c6038db626648eb247dd8b.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/91ef63b112209ab30172763acd8a0935106c248f7f1bcae5545ce37a9f201551.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/a66ea4293a5f5938bc6d116edfa2522bb85bc37aea3541fbc09c3b613b9b32c0.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/ceb2ab26b80590840b65651deb6e948d3bf81565c6751f3a58752cf4bf4aecae.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
- package/src/cf-do/ARCHITECTURE.md +0 -83
- package/src/cf-do/watermark.test.ts +0 -103
- package/src/cf-do/watermark.ts +0 -118
- package/src/cf-do/worker.ts +0 -1033
- package/src/cf-do/wrangler.toml +0 -11
- package/src/cf-pglite/README.md +0 -19
- package/src/change-tracking.ts +0 -25
- package/src/child-process.test.ts +0 -147
- package/src/child-process.ts +0 -90
- package/src/cli-entry.ts +0 -72
- package/src/cli.test.ts +0 -38
- package/src/cli.ts +0 -1214
- package/src/config.ts +0 -150
- package/src/do-sql-tracking.test.ts +0 -19
- package/src/do-sql-tracking.ts +0 -19
- package/src/index.ts +0 -1215
- package/src/integration/integration.test.ts +0 -517
- package/src/integration/native-binary.guard.test.ts +0 -13
- package/src/integration/native-startup.test.ts +0 -44
- package/src/integration/replication-latency.test.ts +0 -428
- package/src/integration/restore-live-stress.test.ts +0 -433
- package/src/integration/restore-reset.test.ts +0 -400
- package/src/integration/restore.test.ts +0 -274
- package/src/integration/test-permissions.ts +0 -147
- package/src/load-config.ts +0 -46
- package/src/log.ts +0 -96
- package/src/mutex.ts +0 -47
- package/src/pg-proxy-browser.singledb.test.ts +0 -233
- package/src/pg-proxy-browser.ts +0 -2022
- package/src/pg-proxy-do-backend.test.ts +0 -3890
- package/src/pg-proxy-do-backend.ts +0 -7157
- package/src/pg-proxy.ts +0 -1087
- package/src/pglite-ipc.test.ts +0 -116
- package/src/pglite-ipc.ts +0 -266
- package/src/pglite-manager.ts +0 -557
- package/src/pglite-web-proxy.test.ts +0 -57
- package/src/pglite-web-proxy.ts +0 -221
- package/src/pglite-web-worker.ts +0 -152
- package/src/pglite-worker-thread.ts +0 -253
- package/src/port.ts +0 -25
- package/src/process-title.ts +0 -9
- package/src/recovery.ts +0 -155
- package/src/replication/change-tracker.test.ts +0 -357
- package/src/replication/change-tracker.ts +0 -279
- package/src/replication/handler.test.ts +0 -511
- package/src/replication/handler.ts +0 -1190
- package/src/replication/pgoutput-encoder.test.ts +0 -697
- package/src/replication/pgoutput-encoder.ts +0 -373
- package/src/replication/tcp-replication.test.ts +0 -876
- package/src/replication/zero-compat.test.ts +0 -1150
- package/src/restore-stress.test.ts +0 -188
- package/src/s3-local.ts +0 -203
- package/src/shim/hooks.mjs +0 -120
- package/src/shim/register.mjs +0 -4
- package/src/sqlite-mode/apply-mode.ts +0 -224
- package/src/sqlite-mode/index.ts +0 -15
- package/src/sqlite-mode/native-binary.ts +0 -89
- package/src/sqlite-mode/package-resolve.ts +0 -17
- package/src/sqlite-mode/resolve-mode.ts +0 -80
- package/src/sqlite-mode/shim-template.ts +0 -159
- package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
- package/src/sqlite-mode/types.ts +0 -30
- package/src/vite-plugin.ts +0 -67
- package/src/wasm-sqlite.test.ts +0 -537
- package/src/worker/browser-admin.ts +0 -52
- package/src/worker/browser-build-config.test.ts +0 -71
- package/src/worker/browser-build-config.ts +0 -109
- package/src/worker/browser-embed-admin.test.ts +0 -75
- package/src/worker/browser-embed.ts +0 -345
- package/src/worker/cf-patches.ts +0 -384
- package/src/worker/embed-integration.test.ts +0 -321
- package/src/worker/index.ts +0 -138
- package/src/worker/shims/fastify.test.ts +0 -255
- package/src/worker/shims/fastify.ts +0 -306
- package/src/worker/shims/http-service.test.ts +0 -355
- package/src/worker/shims/http-service.ts +0 -293
- package/src/worker/shims/node-stub.ts +0 -290
- package/src/worker/shims/oxfmt.ts +0 -3
- package/src/worker/shims/postgres-browser.ts +0 -59
- package/src/worker/shims/postgres-socket.test.ts +0 -576
- package/src/worker/shims/postgres-socket.ts +0 -310
- package/src/worker/shims/postgres.test.ts +0 -364
- package/src/worker/shims/postgres.ts +0 -1454
- package/src/worker/shims/sqlite-browser.test.ts +0 -233
- package/src/worker/shims/sqlite-browser.ts +0 -175
- package/src/worker/shims/sqlite.test.ts +0 -786
- package/src/worker/shims/sqlite.ts +0 -978
- package/src/worker/shims/stream-browser.ts +0 -15
- package/src/worker/shims/ws-browser.test.ts +0 -205
- package/src/worker/shims/ws-browser.ts +0 -248
- package/src/worker/shims/ws.test.ts +0 -288
- package/src/worker/shims/ws.ts +0 -467
- package/src/worker/shims/zero-process-env.ts +0 -11
- package/src/worker/types.ts +0 -75
- package/src/worker/worker-integration.test.ts +0 -223
- package/src/worker/worker.test.ts +0 -136
- package/src/worker/zero-cache-embed-cf.ts +0 -463
- package/src/worker/zero-cache-embed.ts +0 -277
package/src/pglite-ipc.test.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { PGliteWorkerProxy } from './pglite-ipc.js'
|
|
4
|
-
|
|
5
|
-
describe('PGliteWorkerProxy', () => {
|
|
6
|
-
let proxy: PGliteWorkerProxy
|
|
7
|
-
|
|
8
|
-
beforeAll(async () => {
|
|
9
|
-
proxy = new PGliteWorkerProxy({
|
|
10
|
-
dataDir: 'memory://',
|
|
11
|
-
name: 'test',
|
|
12
|
-
withExtensions: false,
|
|
13
|
-
debug: 0,
|
|
14
|
-
pgliteOptions: {},
|
|
15
|
-
})
|
|
16
|
-
await proxy.waitReady
|
|
17
|
-
}, 30_000)
|
|
18
|
-
|
|
19
|
-
afterAll(async () => {
|
|
20
|
-
await proxy.close()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('exec creates table', async () => {
|
|
24
|
-
await proxy.exec(`
|
|
25
|
-
CREATE TABLE test_items (
|
|
26
|
-
id SERIAL PRIMARY KEY,
|
|
27
|
-
name TEXT NOT NULL
|
|
28
|
-
)
|
|
29
|
-
`)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('query returns rows', async () => {
|
|
33
|
-
await proxy.exec(`INSERT INTO test_items (name) VALUES ('hello')`)
|
|
34
|
-
await proxy.exec(`INSERT INTO test_items (name) VALUES ('world')`)
|
|
35
|
-
|
|
36
|
-
const result = await proxy.query<{ id: number; name: string }>(
|
|
37
|
-
'SELECT * FROM test_items ORDER BY id'
|
|
38
|
-
)
|
|
39
|
-
expect(result.rows).toHaveLength(2)
|
|
40
|
-
expect(result.rows[0].name).toBe('hello')
|
|
41
|
-
expect(result.rows[1].name).toBe('world')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('query with params', async () => {
|
|
45
|
-
const result = await proxy.query<{ name: string }>(
|
|
46
|
-
'SELECT name FROM test_items WHERE name = $1',
|
|
47
|
-
['world']
|
|
48
|
-
)
|
|
49
|
-
expect(result.rows).toHaveLength(1)
|
|
50
|
-
expect(result.rows[0].name).toBe('world')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('exec returns affectedRows', async () => {
|
|
54
|
-
const result = await proxy.exec(`DELETE FROM test_items WHERE name = 'hello'`)
|
|
55
|
-
expect(result[0].affectedRows).toBe(1)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('execProtocolRaw handles wire protocol', async () => {
|
|
59
|
-
// simple query message: SELECT 1 as num
|
|
60
|
-
const query = 'SELECT 1 as num\0'
|
|
61
|
-
const encoder = new TextEncoder()
|
|
62
|
-
const queryBytes = encoder.encode(query)
|
|
63
|
-
const buf = new Uint8Array(5 + queryBytes.length)
|
|
64
|
-
buf[0] = 0x51 // 'Q' simple query
|
|
65
|
-
new DataView(buf.buffer).setInt32(1, 4 + queryBytes.length)
|
|
66
|
-
buf.set(queryBytes, 5)
|
|
67
|
-
|
|
68
|
-
const result = await proxy.execProtocolRaw(buf)
|
|
69
|
-
expect(result).toBeInstanceOf(Uint8Array)
|
|
70
|
-
expect(result.length).toBeGreaterThan(0)
|
|
71
|
-
// should contain a ReadyForQuery message (0x5a)
|
|
72
|
-
let hasRfq = false
|
|
73
|
-
for (let i = 0; i < result.length; i++) {
|
|
74
|
-
if (result[i] === 0x5a) {
|
|
75
|
-
hasRfq = true
|
|
76
|
-
break
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
expect(hasRfq).toBe(true)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('listen receives notifications', async () => {
|
|
83
|
-
const received: string[] = []
|
|
84
|
-
const unsub = await proxy.listen('test_channel', (payload) => {
|
|
85
|
-
received.push(payload)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
await proxy.exec(`NOTIFY test_channel, 'hello'`)
|
|
89
|
-
// give notification time to propagate
|
|
90
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
91
|
-
|
|
92
|
-
expect(received).toContain('hello')
|
|
93
|
-
await unsub()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('error propagation with SQL code', async () => {
|
|
97
|
-
await expect(proxy.exec('SELECT * FROM nonexistent_table')).rejects.toThrow()
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('rejects requests after worker exits', async () => {
|
|
101
|
-
const local = new PGliteWorkerProxy({
|
|
102
|
-
dataDir: 'memory://',
|
|
103
|
-
name: 'exit-test',
|
|
104
|
-
withExtensions: false,
|
|
105
|
-
debug: 0,
|
|
106
|
-
pgliteOptions: {},
|
|
107
|
-
})
|
|
108
|
-
await local.waitReady
|
|
109
|
-
|
|
110
|
-
await (local as any).worker.terminate()
|
|
111
|
-
|
|
112
|
-
await expect(local.query('SELECT 1')).rejects.toThrow(
|
|
113
|
-
/worker exited|worker is closed/
|
|
114
|
-
)
|
|
115
|
-
})
|
|
116
|
-
})
|
package/src/pglite-ipc.ts
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PGlite worker proxy — runs in the main thread, proxies calls to a
|
|
3
|
-
* worker thread running the actual PGlite instance.
|
|
4
|
-
*
|
|
5
|
-
* implements the PGlite interface surface used throughout orez:
|
|
6
|
-
* execProtocolRaw, query, exec, listen, close.
|
|
7
|
-
*
|
|
8
|
-
* ArrayBuffers are transferred (not copied) for execProtocolRaw to
|
|
9
|
-
* keep IPC overhead near-zero for wire protocol data.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { existsSync } from 'node:fs'
|
|
13
|
-
import { resolve } from 'node:path'
|
|
14
|
-
import { Worker } from 'node:worker_threads'
|
|
15
|
-
|
|
16
|
-
import { log } from './log.js'
|
|
17
|
-
import { signalReplicationChange } from './replication/handler.js'
|
|
18
|
-
|
|
19
|
-
import type { WorkerInitConfig } from './pglite-worker-thread.js'
|
|
20
|
-
|
|
21
|
-
interface PendingRequest {
|
|
22
|
-
resolve: (value: any) => void
|
|
23
|
-
reject: (error: Error) => void
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const WRITE_PREFIXES = ['insert', 'update', 'delete', 'copy', 'truncate']
|
|
27
|
-
// shard-internal tables that the replication handler filters out.
|
|
28
|
-
// signaling for these just causes spurious wakeups + mutex contention.
|
|
29
|
-
// pre-lowercased so we don't call toLowerCase() per iteration
|
|
30
|
-
const SHARD_INTERNAL_TABLES = ['"replicas"', '"mutations"', '"replicationstate"']
|
|
31
|
-
function isReplicatedWrite(sql: string): boolean {
|
|
32
|
-
const q = sql.trimStart().toLowerCase()
|
|
33
|
-
if (!WRITE_PREFIXES.some((p) => q.startsWith(p))) return false
|
|
34
|
-
// skip shard-internal writes (zero-cache manages these, not replicated)
|
|
35
|
-
for (const t of SHARD_INTERNAL_TABLES) {
|
|
36
|
-
if (q.includes(t)) return false
|
|
37
|
-
}
|
|
38
|
-
return true
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// resolve worker file path — .ts in dev/test (vitest), .js when compiled
|
|
42
|
-
function resolveWorkerPath(): string {
|
|
43
|
-
const dir = import.meta.dirname
|
|
44
|
-
const tsPath = resolve(dir, 'pglite-worker-thread.ts')
|
|
45
|
-
if (existsSync(tsPath)) return tsPath
|
|
46
|
-
return resolve(dir, 'pglite-worker-thread.js')
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export class PGliteWorkerProxy {
|
|
50
|
-
private worker: Worker
|
|
51
|
-
private pending = new Map<number, PendingRequest>()
|
|
52
|
-
private nextId = 1
|
|
53
|
-
private notificationCallbacks = new Map<string, Set<(payload: string) => void>>()
|
|
54
|
-
private closed = false
|
|
55
|
-
private failure: Error | null = null
|
|
56
|
-
readonly name: string
|
|
57
|
-
|
|
58
|
-
/** resolves when the worker's PGlite instance is ready */
|
|
59
|
-
readonly waitReady: Promise<void>
|
|
60
|
-
|
|
61
|
-
constructor(config: WorkerInitConfig) {
|
|
62
|
-
this.name = config.name
|
|
63
|
-
const workerPath = resolveWorkerPath()
|
|
64
|
-
|
|
65
|
-
this.worker = new Worker(workerPath, {
|
|
66
|
-
workerData: config,
|
|
67
|
-
name: `pglite-${config.name}`,
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
// set up waitReady promise, then install message handler once ready
|
|
71
|
-
let onReady: () => void
|
|
72
|
-
this.waitReady = new Promise<void>((resolveReady, rejectReady) => {
|
|
73
|
-
onReady = () => {
|
|
74
|
-
log.debug.pglite(`worker ${config.name} ready`)
|
|
75
|
-
resolveReady()
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const onMessage = (msg: { type: string; id?: number; message?: string }) => {
|
|
79
|
-
if (msg.type === 'ready') {
|
|
80
|
-
this.worker.off('message', onMessage)
|
|
81
|
-
this.installMessageHandler()
|
|
82
|
-
onReady()
|
|
83
|
-
} else if (msg.type === 'error' && msg.id === 0) {
|
|
84
|
-
rejectReady(new Error(msg.message))
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.worker.on('message', onMessage)
|
|
89
|
-
this.worker.once('error', rejectReady)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
// handle unexpected worker crashes
|
|
93
|
-
this.worker.on('error', (err) => {
|
|
94
|
-
const failure = new Error(`worker crashed: ${err.message}`)
|
|
95
|
-
log.pglite(`worker ${config.name} error: ${err.message}`)
|
|
96
|
-
this.failPending(failure)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
this.worker.on('exit', (code) => {
|
|
100
|
-
if (this.closed) return
|
|
101
|
-
if (code !== 0) {
|
|
102
|
-
const failure = new Error(`worker exited with code ${code}`)
|
|
103
|
-
log.pglite(`worker ${config.name} exited with code ${code}`)
|
|
104
|
-
this.failPending(failure)
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
this.failPending(new Error('worker exited unexpectedly'))
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private failPending(error: Error) {
|
|
112
|
-
if (!this.failure) this.failure = error
|
|
113
|
-
for (const [, req] of this.pending) {
|
|
114
|
-
req.reject(error)
|
|
115
|
-
}
|
|
116
|
-
this.pending.clear()
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private installMessageHandler() {
|
|
120
|
-
this.worker.on(
|
|
121
|
-
'message',
|
|
122
|
-
(msg: { type: string; id?: number; [key: string]: any }) => {
|
|
123
|
-
if (msg.type === 'notification') {
|
|
124
|
-
const callbacks = this.notificationCallbacks.get(msg.channel)
|
|
125
|
-
if (callbacks) {
|
|
126
|
-
for (const cb of callbacks) {
|
|
127
|
-
try {
|
|
128
|
-
cb(msg.payload)
|
|
129
|
-
} catch {}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const req = this.pending.get(msg.id!)
|
|
136
|
-
if (!req) return
|
|
137
|
-
this.pending.delete(msg.id!)
|
|
138
|
-
|
|
139
|
-
if (msg.type === 'error') {
|
|
140
|
-
const err = new Error(msg.message) as Error & { code?: string }
|
|
141
|
-
if (msg.code) err.code = msg.code
|
|
142
|
-
req.reject(err)
|
|
143
|
-
} else {
|
|
144
|
-
req.resolve(msg)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private send(msg: Record<string, unknown>, transfer?: ArrayBuffer[]): Promise<any> {
|
|
151
|
-
if (this.failure) return Promise.reject(this.failure)
|
|
152
|
-
if (this.closed) return Promise.reject(new Error('worker is closed'))
|
|
153
|
-
|
|
154
|
-
const id = this.nextId++
|
|
155
|
-
msg.id = id
|
|
156
|
-
return new Promise((resolve, reject) => {
|
|
157
|
-
this.pending.set(id, { resolve, reject })
|
|
158
|
-
try {
|
|
159
|
-
if (transfer?.length) {
|
|
160
|
-
this.worker.postMessage(msg, transfer)
|
|
161
|
-
} else {
|
|
162
|
-
this.worker.postMessage(msg)
|
|
163
|
-
}
|
|
164
|
-
} catch (err) {
|
|
165
|
-
this.pending.delete(id)
|
|
166
|
-
reject(err instanceof Error ? err : new Error(String(err)))
|
|
167
|
-
}
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async execProtocolRaw(
|
|
172
|
-
data: Uint8Array,
|
|
173
|
-
options?: { syncToFs?: boolean; throwOnError?: boolean }
|
|
174
|
-
): Promise<Uint8Array> {
|
|
175
|
-
// copy to a transferable buffer then transfer (avoids copying in the worker)
|
|
176
|
-
const buf = new ArrayBuffer(data.byteLength)
|
|
177
|
-
new Uint8Array(buf).set(data)
|
|
178
|
-
const result = await this.send({ type: 'execProtocolRaw', data: buf, options }, [buf])
|
|
179
|
-
return new Uint8Array(result.data)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* execute multiple wire protocol messages in a single IPC round-trip.
|
|
184
|
-
* each message is executed sequentially in the worker, and all results
|
|
185
|
-
* are concatenated and returned. eliminates N-1 postMessage round-trips
|
|
186
|
-
* for extended protocol pipelines (Parse→Bind→Execute→Sync).
|
|
187
|
-
*/
|
|
188
|
-
async execProtocolRawBatch(
|
|
189
|
-
messages: Uint8Array[],
|
|
190
|
-
options?: { syncToFs?: boolean; throwOnError?: boolean }
|
|
191
|
-
): Promise<Uint8Array> {
|
|
192
|
-
const buffers: ArrayBuffer[] = []
|
|
193
|
-
for (const msg of messages) {
|
|
194
|
-
const buf = new ArrayBuffer(msg.byteLength)
|
|
195
|
-
new Uint8Array(buf).set(msg)
|
|
196
|
-
buffers.push(buf)
|
|
197
|
-
}
|
|
198
|
-
const result = await this.send(
|
|
199
|
-
{ type: 'execProtocolRawBatch', buffers, options },
|
|
200
|
-
buffers
|
|
201
|
-
)
|
|
202
|
-
return new Uint8Array(result.data)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async query<T = any>(
|
|
206
|
-
sql: string,
|
|
207
|
-
params?: any[]
|
|
208
|
-
): Promise<{ rows: T[]; affectedRows?: number }> {
|
|
209
|
-
const result = await this.send({ type: 'query', sql, params })
|
|
210
|
-
if (this.name === 'postgres' && isReplicatedWrite(sql)) {
|
|
211
|
-
signalReplicationChange()
|
|
212
|
-
}
|
|
213
|
-
return { rows: result.rows ?? [], affectedRows: result.affectedRows }
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async exec(sql: string): Promise<{ affectedRows?: number }[]> {
|
|
217
|
-
const result = await this.send({ type: 'exec', sql })
|
|
218
|
-
if (this.name === 'postgres' && isReplicatedWrite(sql)) {
|
|
219
|
-
signalReplicationChange()
|
|
220
|
-
}
|
|
221
|
-
return result.results ?? []
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async listen(
|
|
225
|
-
channel: string,
|
|
226
|
-
callback: (payload: string) => void
|
|
227
|
-
): Promise<() => Promise<void>> {
|
|
228
|
-
let callbacks = this.notificationCallbacks.get(channel)
|
|
229
|
-
if (!callbacks) {
|
|
230
|
-
callbacks = new Set()
|
|
231
|
-
this.notificationCallbacks.set(channel, callbacks)
|
|
232
|
-
}
|
|
233
|
-
callbacks.add(callback)
|
|
234
|
-
|
|
235
|
-
const result = await this.send({ type: 'listen', channel })
|
|
236
|
-
const listenId = result.id
|
|
237
|
-
|
|
238
|
-
return async () => {
|
|
239
|
-
callbacks!.delete(callback)
|
|
240
|
-
if (callbacks!.size === 0) {
|
|
241
|
-
this.notificationCallbacks.delete(channel)
|
|
242
|
-
}
|
|
243
|
-
await this.send({ type: 'unlisten', listenId }).catch(() => {})
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* dump the PGlite data directory as a tar blob.
|
|
249
|
-
* used to create read replicas from an existing instance.
|
|
250
|
-
*/
|
|
251
|
-
async dumpDataDir(): Promise<ArrayBuffer> {
|
|
252
|
-
const result = await this.send({ type: 'dumpDataDir' })
|
|
253
|
-
return result.data as ArrayBuffer
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async close(): Promise<void> {
|
|
257
|
-
try {
|
|
258
|
-
await this.send({ type: 'close' })
|
|
259
|
-
} catch {
|
|
260
|
-
// worker may already be gone
|
|
261
|
-
}
|
|
262
|
-
this.closed = true
|
|
263
|
-
this.failPending(new Error('worker is closed'))
|
|
264
|
-
await this.worker.terminate()
|
|
265
|
-
}
|
|
266
|
-
}
|