orez 0.2.27 → 0.2.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/package.json +3 -4
  2. package/src/admin/admin-data.test.ts +0 -348
  3. package/src/admin/http-proxy.ts +0 -252
  4. package/src/admin/log-store.ts +0 -192
  5. package/src/admin/server.ts +0 -471
  6. package/src/admin/ui.ts +0 -1322
  7. package/src/bench/proxy-throughput.bench.ts +0 -343
  8. package/src/bench/serial-mutations.bench.ts +0 -270
  9. package/src/browser.ts +0 -203
  10. package/src/cf-do/.wrangler/cache/cf.json +0 -1
  11. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  12. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  13. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  14. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0ffaabee41a60e04dd0eb7db3073f0a40139e6a97ccd26823967acb652b89a7b.sqlite +0 -0
  15. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
  16. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
  17. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
  18. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-insertion-facade.js +0 -11
  19. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-loader.entry.ts +0 -134
  20. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-insertion-facade.js +0 -11
  21. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-loader.entry.ts +0 -134
  22. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js +0 -1059
  23. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js.map +0 -8
  24. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js +0 -1059
  25. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js.map +0 -8
  26. package/src/cf-do/ARCHITECTURE.md +0 -93
  27. package/src/cf-do/CHAT_E2E.md +0 -213
  28. package/src/cf-do/watermark.test.ts +0 -103
  29. package/src/cf-do/watermark.ts +0 -118
  30. package/src/cf-do/worker.ts +0 -1041
  31. package/src/cf-do/wrangler.toml +0 -11
  32. package/src/cf-pglite/README.md +0 -19
  33. package/src/change-tracking.ts +0 -25
  34. package/src/child-process.test.ts +0 -147
  35. package/src/child-process.ts +0 -90
  36. package/src/cli-entry.ts +0 -72
  37. package/src/cli.test.ts +0 -40
  38. package/src/cli.ts +0 -1214
  39. package/src/config.ts +0 -150
  40. package/src/do-sql-tracking.test.ts +0 -19
  41. package/src/do-sql-tracking.ts +0 -19
  42. package/src/index.ts +0 -1215
  43. package/src/integration/integration.test.ts +0 -517
  44. package/src/integration/native-binary.guard.test.ts +0 -13
  45. package/src/integration/native-startup.test.ts +0 -44
  46. package/src/integration/replication-latency.test.ts +0 -428
  47. package/src/integration/restore-live-stress.test.ts +0 -433
  48. package/src/integration/restore-reset.test.ts +0 -400
  49. package/src/integration/restore.test.ts +0 -274
  50. package/src/integration/test-permissions.ts +0 -147
  51. package/src/load-config.ts +0 -46
  52. package/src/log.ts +0 -96
  53. package/src/mutex.ts +0 -47
  54. package/src/pg-proxy-browser.singledb.test.ts +0 -233
  55. package/src/pg-proxy-browser.ts +0 -2022
  56. package/src/pg-proxy-do-backend.test.ts +0 -3890
  57. package/src/pg-proxy-do-backend.ts +0 -7191
  58. package/src/pg-proxy.ts +0 -1087
  59. package/src/pg-sqlite-compiler/README.md +0 -53
  60. package/src/pg-sqlite-compiler/catalog/seed.ts +0 -524
  61. package/src/pg-sqlite-compiler/fixtures/pgsqlite/arithmetic.json +0 -307
  62. package/src/pg-sqlite-compiler/fixtures/pgsqlite/array.json +0 -377
  63. package/src/pg-sqlite-compiler/fixtures/pgsqlite/cast.json +0 -12
  64. package/src/pg-sqlite-compiler/fixtures/pgsqlite/catalog.json +0 -447
  65. package/src/pg-sqlite-compiler/fixtures/pgsqlite/create-table.json +0 -32
  66. package/src/pg-sqlite-compiler/fixtures/pgsqlite/datetime.json +0 -397
  67. package/src/pg-sqlite-compiler/fixtures/pgsqlite/enum.json +0 -337
  68. package/src/pg-sqlite-compiler/fixtures/pgsqlite/insert.json +0 -337
  69. package/src/pg-sqlite-compiler/fixtures/pgsqlite/json.json +0 -537
  70. package/src/pg-sqlite-compiler/fixtures/pgsqlite/misc.json +0 -1837
  71. package/src/pg-sqlite-compiler/index.ts +0 -73
  72. package/src/pg-sqlite-compiler/integration.test.ts +0 -136
  73. package/src/pg-sqlite-compiler/passes/ast-utils.ts +0 -113
  74. package/src/pg-sqlite-compiler/passes/catalog.ts +0 -65
  75. package/src/pg-sqlite-compiler/passes/datetime.ts +0 -74
  76. package/src/pg-sqlite-compiler/passes/index.ts +0 -49
  77. package/src/pg-sqlite-compiler/passes/types.ts +0 -156
  78. package/src/pg-sqlite-compiler/smoke.test.ts +0 -69
  79. package/src/pg-sqlite-compiler/test/catalog.test.ts +0 -171
  80. package/src/pg-sqlite-compiler/test/corpus.test.ts +0 -161
  81. package/src/pg-sqlite-compiler/test/datetime.oracle.test.ts +0 -102
  82. package/src/pg-sqlite-compiler/test/oracle.ts +0 -237
  83. package/src/pg-sqlite-compiler/test/types.test.ts +0 -109
  84. package/src/pg-sqlite-compiler/types.ts +0 -63
  85. package/src/pglite-ipc.test.ts +0 -116
  86. package/src/pglite-ipc.ts +0 -266
  87. package/src/pglite-manager.ts +0 -557
  88. package/src/pglite-web-proxy.test.ts +0 -57
  89. package/src/pglite-web-proxy.ts +0 -221
  90. package/src/pglite-web-worker.ts +0 -152
  91. package/src/pglite-worker-thread.ts +0 -253
  92. package/src/port.ts +0 -25
  93. package/src/process-title.ts +0 -9
  94. package/src/recovery.ts +0 -155
  95. package/src/replication/change-tracker.test.ts +0 -357
  96. package/src/replication/change-tracker.ts +0 -279
  97. package/src/replication/handler.test.ts +0 -511
  98. package/src/replication/handler.ts +0 -1190
  99. package/src/replication/pgoutput-encoder.test.ts +0 -697
  100. package/src/replication/pgoutput-encoder.ts +0 -373
  101. package/src/replication/tcp-replication.test.ts +0 -876
  102. package/src/replication/zero-compat.test.ts +0 -1150
  103. package/src/restore-stress.test.ts +0 -188
  104. package/src/s3-local.ts +0 -203
  105. package/src/shim/hooks.mjs +0 -120
  106. package/src/shim/register.mjs +0 -4
  107. package/src/sqlite-mode/apply-mode.ts +0 -224
  108. package/src/sqlite-mode/index.ts +0 -15
  109. package/src/sqlite-mode/native-binary.ts +0 -89
  110. package/src/sqlite-mode/package-resolve.ts +0 -17
  111. package/src/sqlite-mode/resolve-mode.ts +0 -80
  112. package/src/sqlite-mode/shim-template.ts +0 -159
  113. package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
  114. package/src/sqlite-mode/types.ts +0 -30
  115. package/src/vite-plugin.ts +0 -67
  116. package/src/wasm-sqlite.test.ts +0 -537
  117. package/src/worker/browser-admin.ts +0 -52
  118. package/src/worker/browser-build-config.test.ts +0 -71
  119. package/src/worker/browser-build-config.ts +0 -109
  120. package/src/worker/browser-embed-admin.test.ts +0 -75
  121. package/src/worker/browser-embed.ts +0 -345
  122. package/src/worker/cf-patches.ts +0 -384
  123. package/src/worker/embed-integration.test.ts +0 -321
  124. package/src/worker/index.ts +0 -138
  125. package/src/worker/shims/fastify.test.ts +0 -255
  126. package/src/worker/shims/fastify.ts +0 -306
  127. package/src/worker/shims/http-service.test.ts +0 -355
  128. package/src/worker/shims/http-service.ts +0 -293
  129. package/src/worker/shims/node-stub.ts +0 -290
  130. package/src/worker/shims/oxfmt.ts +0 -3
  131. package/src/worker/shims/postgres-browser.ts +0 -59
  132. package/src/worker/shims/postgres-socket.test.ts +0 -576
  133. package/src/worker/shims/postgres-socket.ts +0 -310
  134. package/src/worker/shims/postgres.test.ts +0 -364
  135. package/src/worker/shims/postgres.ts +0 -1454
  136. package/src/worker/shims/sqlite-browser.test.ts +0 -233
  137. package/src/worker/shims/sqlite-browser.ts +0 -175
  138. package/src/worker/shims/sqlite.test.ts +0 -786
  139. package/src/worker/shims/sqlite.ts +0 -978
  140. package/src/worker/shims/stream-browser.ts +0 -15
  141. package/src/worker/shims/ws-browser.test.ts +0 -205
  142. package/src/worker/shims/ws-browser.ts +0 -248
  143. package/src/worker/shims/ws.test.ts +0 -288
  144. package/src/worker/shims/ws.ts +0 -467
  145. package/src/worker/shims/zero-process-env.ts +0 -11
  146. package/src/worker/types.ts +0 -75
  147. package/src/worker/worker-integration.test.ts +0 -223
  148. package/src/worker/worker.test.ts +0 -136
  149. package/src/worker/zero-cache-embed-cf.ts +0 -463
  150. package/src/worker/zero-cache-embed.ts +0 -277
@@ -1,221 +0,0 @@
1
- /**
2
- * PGlite Web Worker proxy — browser equivalent of pglite-ipc.ts.
3
- *
4
- * runs in the zero-cache worker, proxies calls to a Web Worker
5
- * running the actual PGlite instance. mirrors PGliteWorkerProxy
6
- * from pglite-ipc.ts but uses Web Worker postMessage instead of
7
- * node worker_threads.
8
- *
9
- * ArrayBuffers are transferred (not copied) for execProtocolRaw
10
- * to keep IPC overhead near-zero for wire protocol data.
11
- */
12
-
13
- import { signalReplicationChange } from './replication/handler.js'
14
-
15
- interface PendingRequest {
16
- resolve: (value: any) => void
17
- reject: (error: Error) => void
18
- }
19
-
20
- const WRITE_PREFIXES = ['insert', 'update', 'delete', 'copy', 'truncate']
21
- const SHARD_INTERNAL_TABLES = ['"replicas"', '"mutations"', '"replicationState"']
22
-
23
- function isReplicatedWrite(sql: string): boolean {
24
- const q = sql.trimStart().toLowerCase()
25
- if (!WRITE_PREFIXES.some((p) => q.startsWith(p))) return false
26
- for (const t of SHARD_INTERNAL_TABLES) {
27
- if (q.includes(t.toLowerCase())) return false
28
- }
29
- return true
30
- }
31
-
32
- export class PGliteWebProxy {
33
- private worker: Worker
34
- private pending = new Map<number, PendingRequest>()
35
- private nextId = 1
36
- private notificationCallbacks = new Map<string, Set<(payload: string) => void>>()
37
- private failure: Error | null = null
38
- readonly name: string
39
-
40
- readonly waitReady: Promise<void>
41
-
42
- // PGlite compat flags
43
- closed = false
44
- ready = false
45
-
46
- constructor(worker: Worker, name: string) {
47
- this.name = name
48
- this.worker = worker
49
-
50
- let onReady: () => void
51
- this.waitReady = new Promise<void>((resolveReady, rejectReady) => {
52
- onReady = () => {
53
- this.ready = true
54
- resolveReady()
55
- }
56
-
57
- const onMessage = (ev: MessageEvent) => {
58
- const msg = ev.data
59
- if (msg?.type === 'ready') {
60
- this.worker.removeEventListener('message', onMessage)
61
- this.installMessageHandler()
62
- onReady()
63
- } else if (msg?.type === 'error' && msg.id === 0) {
64
- rejectReady(new Error(msg.message))
65
- }
66
- }
67
-
68
- this.worker.addEventListener('message', onMessage)
69
- this.worker.addEventListener('error', (ev) => {
70
- const error = this.errorFromEvent(ev, 'worker failed during startup')
71
- this.failPending(error)
72
- rejectReady(error)
73
- })
74
- this.worker.addEventListener('messageerror', (ev) => {
75
- const error = this.errorFromEvent(ev, 'worker message error during startup')
76
- this.failPending(error)
77
- rejectReady(error)
78
- })
79
- })
80
- }
81
-
82
- private installMessageHandler() {
83
- this.worker.addEventListener('error', (ev) => {
84
- this.failPending(this.errorFromEvent(ev, 'worker failed'))
85
- })
86
- this.worker.addEventListener('messageerror', (ev) => {
87
- this.failPending(this.errorFromEvent(ev, 'worker message error'))
88
- })
89
-
90
- this.worker.addEventListener('message', (ev: MessageEvent) => {
91
- const msg = ev.data
92
- if (!msg || typeof msg !== 'object') return
93
-
94
- if (msg.type === 'notification') {
95
- const callbacks = this.notificationCallbacks.get(msg.channel)
96
- if (callbacks) {
97
- for (const cb of callbacks) {
98
- try {
99
- cb(msg.payload)
100
- } catch {}
101
- }
102
- }
103
- return
104
- }
105
-
106
- const req = this.pending.get(msg.id)
107
- if (!req) return
108
- this.pending.delete(msg.id)
109
-
110
- if (msg.type === 'error') {
111
- const err = new Error(msg.message) as Error & { code?: string }
112
- if (msg.code) err.code = msg.code
113
- req.reject(err)
114
- } else {
115
- req.resolve(msg)
116
- }
117
- })
118
- }
119
-
120
- private errorFromEvent(ev: Event, fallback: string): Error {
121
- const maybeError = ev as ErrorEvent
122
- if (maybeError.error instanceof Error) return maybeError.error
123
- if (maybeError.message) return new Error(maybeError.message)
124
- return new Error(fallback)
125
- }
126
-
127
- private failPending(error: Error) {
128
- if (!this.failure) this.failure = error
129
- this.closed = true
130
- this.ready = false
131
- for (const [, req] of this.pending) {
132
- req.reject(error)
133
- }
134
- this.pending.clear()
135
- }
136
-
137
- private send(msg: Record<string, unknown>, transfer?: Transferable[]): Promise<any> {
138
- if (this.failure) return Promise.reject(this.failure)
139
- if (this.closed) return Promise.reject(new Error('worker is closed'))
140
-
141
- const id = this.nextId++
142
- msg.id = id
143
- return new Promise((resolve, reject) => {
144
- this.pending.set(id, { resolve, reject })
145
- try {
146
- if (transfer?.length) {
147
- this.worker.postMessage(msg, transfer)
148
- } else {
149
- this.worker.postMessage(msg)
150
- }
151
- } catch (err) {
152
- this.pending.delete(id)
153
- reject(err instanceof Error ? err : new Error(String(err)))
154
- }
155
- })
156
- }
157
-
158
- async execProtocolRaw(
159
- data: Uint8Array,
160
- options?: { syncToFs?: boolean; throwOnError?: boolean }
161
- ): Promise<Uint8Array> {
162
- // copy to a transferable buffer then transfer
163
- const buf = new ArrayBuffer(data.byteLength)
164
- new Uint8Array(buf).set(data)
165
- const result = await this.send({ type: 'execProtocolRaw', data: buf, options }, [buf])
166
- return new Uint8Array(result.data)
167
- }
168
-
169
- async query<T = any>(
170
- sql: string,
171
- params?: any[]
172
- ): Promise<{ rows: T[]; affectedRows?: number }> {
173
- const result = await this.send({ type: 'query', sql, params })
174
- // signal replication after writes on postgres instance (like orez-node's PGliteWorkerProxy)
175
- if (this.name === 'postgres' && isReplicatedWrite(sql)) {
176
- signalReplicationChange()
177
- }
178
- return { rows: result.rows ?? [], affectedRows: result.affectedRows }
179
- }
180
-
181
- async exec(sql: string): Promise<{ affectedRows?: number }[]> {
182
- const result = await this.send({ type: 'exec', sql })
183
- if (this.name === 'postgres' && isReplicatedWrite(sql)) {
184
- signalReplicationChange()
185
- }
186
- return result.results ?? []
187
- }
188
-
189
- async listen(
190
- channel: string,
191
- callback: (payload: string) => void
192
- ): Promise<() => Promise<void>> {
193
- let callbacks = this.notificationCallbacks.get(channel)
194
- if (!callbacks) {
195
- callbacks = new Set()
196
- this.notificationCallbacks.set(channel, callbacks)
197
- }
198
- callbacks.add(callback)
199
-
200
- const result = await this.send({ type: 'listen', channel })
201
- const listenId = result.id
202
-
203
- return async () => {
204
- callbacks!.delete(callback)
205
- if (callbacks!.size === 0) {
206
- this.notificationCallbacks.delete(channel)
207
- }
208
- await this.send({ type: 'unlisten', listenId }).catch(() => {})
209
- }
210
- }
211
-
212
- async close(): Promise<void> {
213
- try {
214
- await this.send({ type: 'close' })
215
- } catch {}
216
- this.closed = true
217
- this.ready = false
218
- this.failPending(new Error('worker is closed'))
219
- this.worker.terminate()
220
- }
221
- }
@@ -1,152 +0,0 @@
1
- /**
2
- * PGlite Web Worker — browser equivalent of pglite-worker-thread.ts.
3
- *
4
- * runs a single PGlite instance in a Web Worker. receives commands via
5
- * postMessage, executes on PGlite, sends results back. ArrayBuffers
6
- * are transferred (not copied) for execProtocolRaw.
7
- *
8
- * message protocol (same as pglite-worker-thread.ts):
9
- * init: { type: 'init', dataDir, name, withExtensions, pgliteOptions }
10
- * → { type: 'ready' }
11
- *
12
- * execProtocolRaw: { type: 'execProtocolRaw', id, data: ArrayBuffer, options }
13
- * → { type: 'result', id, data: ArrayBuffer }
14
- *
15
- * query: { type: 'query', id, sql, params }
16
- * → { type: 'result', id, rows, affectedRows }
17
- *
18
- * exec: { type: 'exec', id, sql }
19
- * → { type: 'result', id, results: [{ affectedRows }] }
20
- *
21
- * listen/unlisten/close: same as pglite-worker-thread.ts
22
- */
23
-
24
- // NOTE: this file is meant to be bundled with PGlite as external
25
- // the consumer provides PGlite via importScripts or ESM import
26
-
27
- declare const self: any
28
-
29
- const listeners = new Map<number, () => Promise<void>>()
30
- let db: any // PGlite instance — type depends on how it's loaded
31
-
32
- self.onmessage = async (ev: MessageEvent) => {
33
- const msg = ev.data
34
- if (!msg || typeof msg !== 'object') return
35
- const { type, id } = msg
36
-
37
- try {
38
- switch (type) {
39
- case 'init': {
40
- // dynamically import PGlite (external, provided by consumer's bundler)
41
- const { PGlite } = await import('@electric-sql/pglite')
42
- db = new PGlite({
43
- dataDir: msg.dataDir || 'idb://orez-pglite',
44
- relaxedDurability: true,
45
- initialMemory: 32 * 1024 * 1024,
46
- startParams: [
47
- '--single',
48
- '-F',
49
- '-O',
50
- '-j',
51
- '-c',
52
- 'search_path=public',
53
- '-c',
54
- 'exit_on_error=false',
55
- '-c',
56
- 'log_checkpoints=false',
57
- '-c',
58
- 'shared_buffers=4MB',
59
- '-c',
60
- 'wal_buffers=1MB',
61
- ],
62
- ...(msg.pgliteOptions || {}),
63
- // extensions loaded by consumer if needed
64
- })
65
- await db.waitReady
66
-
67
- // tune postgres internals — modest values for embedded use
68
- await db.exec(`
69
- SET work_mem = '4MB';
70
- SET maintenance_work_mem = '16MB';
71
- SET effective_cache_size = '64MB';
72
- SET random_page_cost = 1.1;
73
- SET jit = off;
74
- `)
75
-
76
- self.postMessage({ type: 'ready' })
77
- break
78
- }
79
-
80
- case 'execProtocolRaw': {
81
- const input = new Uint8Array(msg.data as ArrayBuffer)
82
- const result = await db.execProtocolRaw(input, msg.options)
83
- const buf = new ArrayBuffer(result.byteLength)
84
- new Uint8Array(buf).set(result)
85
- self.postMessage({ type: 'result', id, data: buf }, [buf])
86
- break
87
- }
88
-
89
- case 'query': {
90
- const result = await db.query(msg.sql, msg.params)
91
- self.postMessage({
92
- type: 'result',
93
- id,
94
- rows: result.rows,
95
- affectedRows: result.affectedRows,
96
- })
97
- break
98
- }
99
-
100
- case 'exec': {
101
- const result = await db.exec(msg.sql)
102
- const results = result.map((r: any) => ({ affectedRows: r.affectedRows ?? 0 }))
103
- self.postMessage({ type: 'result', id, results })
104
- break
105
- }
106
-
107
- case 'listen': {
108
- const unsub = await db.listen(msg.channel, (payload: string) => {
109
- self.postMessage({ type: 'notification', channel: msg.channel, payload })
110
- })
111
- listeners.set(id, unsub)
112
- self.postMessage({ type: 'result', id })
113
- break
114
- }
115
-
116
- case 'unlisten': {
117
- const unsub = listeners.get(msg.listenId)
118
- if (unsub) {
119
- await unsub()
120
- listeners.delete(msg.listenId)
121
- }
122
- self.postMessage({ type: 'result', id })
123
- break
124
- }
125
-
126
- case 'close': {
127
- for (const unsub of listeners.values()) {
128
- await unsub().catch(() => {})
129
- }
130
- listeners.clear()
131
- await db.close()
132
- self.postMessage({ type: 'result', id })
133
- break
134
- }
135
-
136
- default:
137
- self.postMessage({
138
- type: 'error',
139
- id,
140
- message: `unknown message type: ${type}`,
141
- })
142
- }
143
- } catch (err: unknown) {
144
- const error = err as { message?: string; code?: string }
145
- self.postMessage({
146
- type: 'error',
147
- id,
148
- message: error?.message || String(err),
149
- code: error?.code,
150
- })
151
- }
152
- }
@@ -1,253 +0,0 @@
1
- /**
2
- * worker thread that runs a single PGlite instance.
3
- *
4
- * receives commands via parentPort messages, executes them on the PGlite
5
- * instance, and sends results back. ArrayBuffers are transferred (not copied)
6
- * for execProtocolRaw to minimize overhead.
7
- */
8
-
9
- import { parentPort, workerData } from 'node:worker_threads'
10
-
11
- import { PGlite } from '@electric-sql/pglite'
12
- import { btree_gin } from '@electric-sql/pglite/contrib/btree_gin'
13
- import { btree_gist } from '@electric-sql/pglite/contrib/btree_gist'
14
- import { citext } from '@electric-sql/pglite/contrib/citext'
15
- import { cube } from '@electric-sql/pglite/contrib/cube'
16
- import { earthdistance } from '@electric-sql/pglite/contrib/earthdistance'
17
- import { fuzzystrmatch } from '@electric-sql/pglite/contrib/fuzzystrmatch'
18
- import { hstore } from '@electric-sql/pglite/contrib/hstore'
19
- import { ltree } from '@electric-sql/pglite/contrib/ltree'
20
- import { pg_trgm } from '@electric-sql/pglite/contrib/pg_trgm'
21
- import { pgcrypto } from '@electric-sql/pglite/contrib/pgcrypto'
22
- import { uuid_ossp } from '@electric-sql/pglite/contrib/uuid_ossp'
23
- import { vector } from '@electric-sql/pglite/vector'
24
-
25
- export interface WorkerInitConfig {
26
- dataDir: string
27
- name: string
28
- withExtensions: boolean
29
- debug: number
30
- pgliteOptions?: Record<string, unknown>
31
- /** tar dump from another instance's dumpDataDir() — used for read replicas */
32
- loadDataDir?: ArrayBuffer
33
- }
34
-
35
- const port = parentPort!
36
- const config = workerData as WorkerInitConfig
37
-
38
- // active listen subscriptions
39
- const listeners = new Map<number, () => Promise<void>>()
40
-
41
- let db: PGlite
42
-
43
- const PGLITE_BASE_FLAGS = [
44
- '--single',
45
- '-F',
46
- '-O',
47
- '-j',
48
- '-c',
49
- 'search_path=public',
50
- '-c',
51
- 'exit_on_error=false',
52
- '-c',
53
- 'log_checkpoints=false',
54
- ]
55
-
56
- const ZERO_START_PARAMS = [
57
- ...PGLITE_BASE_FLAGS,
58
- '-c',
59
- 'shared_buffers=128kB',
60
- '-c',
61
- 'wal_buffers=64kB',
62
- '-c',
63
- 'work_mem=64kB',
64
- '-c',
65
- 'maintenance_work_mem=1MB',
66
- '-c',
67
- 'temp_buffers=800kB',
68
- ]
69
-
70
- async function init() {
71
- const { dataDir: _userDataDir, debug: _dbg, ...userOpts } = config.pgliteOptions || {}
72
- const isMain = config.withExtensions
73
-
74
- db = new PGlite({
75
- dataDir: config.dataDir,
76
- debug: config.debug,
77
- relaxedDurability: true,
78
- ...(config.loadDataDir ? { loadDataDir: new Blob([config.loadDataDir]) } : {}),
79
- initialMemory: isMain ? 32 * 1024 * 1024 : 16 * 1024 * 1024,
80
- ...(isMain ? {} : { startParams: ZERO_START_PARAMS }),
81
- ...(isMain
82
- ? {
83
- startParams: [
84
- ...PGLITE_BASE_FLAGS,
85
- '-c',
86
- 'shared_buffers=4MB',
87
- '-c',
88
- 'wal_buffers=1MB',
89
- ],
90
- ...userOpts,
91
- extensions: userOpts.extensions || {
92
- vector,
93
- pg_trgm,
94
- pgcrypto,
95
- uuid_ossp,
96
- citext,
97
- hstore,
98
- ltree,
99
- fuzzystrmatch,
100
- btree_gin,
101
- btree_gist,
102
- cube,
103
- earthdistance,
104
- },
105
- }
106
- : { extensions: {} }),
107
- } as any)
108
-
109
- await db.waitReady
110
-
111
- if (isMain) {
112
- await db.exec(`
113
- SET work_mem = '4MB';
114
- SET maintenance_work_mem = '16MB';
115
- SET effective_cache_size = '64MB';
116
- SET random_page_cost = 1.1;
117
- SET jit = off;
118
- `)
119
- } else {
120
- await db.exec(`SET jit = off;`)
121
- }
122
-
123
- port.postMessage({ type: 'ready' })
124
- }
125
-
126
- port.on('message', async (msg: { type: string; id: number; [key: string]: unknown }) => {
127
- const { type, id } = msg
128
-
129
- try {
130
- switch (type) {
131
- case 'execProtocolRaw': {
132
- const input = new Uint8Array(msg.data as ArrayBuffer)
133
- const result = await db.execProtocolRaw(input, msg.options as any)
134
- // copy result to a transferable buffer (pglite may reuse wasm memory)
135
- const buf = new ArrayBuffer(result.byteLength)
136
- new Uint8Array(buf).set(result)
137
- port.postMessage({ type: 'result', id, data: buf }, [buf])
138
- break
139
- }
140
-
141
- case 'execProtocolRawBatch': {
142
- // execute multiple wire protocol messages serially, return concatenated result.
143
- // eliminates N-1 IPC round-trips for extended protocol pipelines.
144
- const buffers = msg.buffers as ArrayBuffer[]
145
- const opts = msg.options as any
146
- const resultParts: Uint8Array[] = []
147
- let totalLen = 0
148
- for (const ab of buffers) {
149
- const input = new Uint8Array(ab)
150
- const result = await db.execProtocolRaw(input, opts)
151
- // copy each result (pglite reuses wasm memory between calls)
152
- const copy = new Uint8Array(result.byteLength)
153
- copy.set(result)
154
- resultParts.push(copy)
155
- totalLen += copy.byteLength
156
- }
157
- // concatenate all results into one transferable buffer
158
- const combined = new ArrayBuffer(totalLen)
159
- const view = new Uint8Array(combined)
160
- let offset = 0
161
- for (const part of resultParts) {
162
- view.set(part, offset)
163
- offset += part.byteLength
164
- }
165
- port.postMessage({ type: 'result', id, data: combined }, [combined])
166
- break
167
- }
168
-
169
- case 'query': {
170
- const result = await db.query(msg.sql as string, msg.params as any[])
171
- port.postMessage({
172
- type: 'result',
173
- id,
174
- rows: result.rows,
175
- affectedRows: result.affectedRows,
176
- })
177
- break
178
- }
179
-
180
- case 'exec': {
181
- const result = await db.exec(msg.sql as string)
182
- // serialize exec results (array of { affectedRows })
183
- const results = result.map((r) => ({ affectedRows: r.affectedRows ?? 0 }))
184
- port.postMessage({ type: 'result', id, results })
185
- break
186
- }
187
-
188
- case 'listen': {
189
- const channel = msg.channel as string
190
- const unsub = await db.listen(channel, (payload) => {
191
- port.postMessage({ type: 'notification', channel, payload })
192
- })
193
- listeners.set(id, unsub)
194
- port.postMessage({ type: 'result', id })
195
- break
196
- }
197
-
198
- case 'unlisten': {
199
- const listenId = msg.listenId as number
200
- const unsub = listeners.get(listenId)
201
- if (unsub) {
202
- await unsub()
203
- listeners.delete(listenId)
204
- }
205
- port.postMessage({ type: 'result', id })
206
- break
207
- }
208
-
209
- case 'dumpDataDir': {
210
- const dump = await db.dumpDataDir('none')
211
- // convert Blob/File to ArrayBuffer for transfer
212
- const arrayBuf = await (dump as Blob).arrayBuffer()
213
- port.postMessage({ type: 'result', id, data: arrayBuf }, [arrayBuf])
214
- break
215
- }
216
-
217
- case 'close': {
218
- for (const unsub of listeners.values()) {
219
- await unsub().catch(() => {})
220
- }
221
- listeners.clear()
222
- await db.close()
223
- port.postMessage({ type: 'result', id })
224
- break
225
- }
226
-
227
- default:
228
- port.postMessage({
229
- type: 'error',
230
- id,
231
- message: `unknown message type: ${type}`,
232
- })
233
- }
234
- } catch (err: unknown) {
235
- const error = err as { message?: string; code?: string }
236
- port.postMessage({
237
- type: 'error',
238
- id,
239
- message: error?.message || String(err),
240
- code: error?.code,
241
- })
242
- }
243
- })
244
-
245
- init().catch((err: unknown) => {
246
- const error = err as { message?: string }
247
- port.postMessage({
248
- type: 'error',
249
- id: 0,
250
- message: `worker init failed: ${error?.message || String(err)}`,
251
- })
252
- process.exit(1)
253
- })
package/src/port.ts DELETED
@@ -1,25 +0,0 @@
1
- import { createServer } from 'node:net'
2
-
3
- export function findPort(preferred: number, maxAttempts = 20): Promise<number> {
4
- return new Promise((resolve, reject) => {
5
- let attempt = 0
6
-
7
- function tryPort(port: number) {
8
- const server = createServer()
9
- server.unref()
10
- server.on('error', (err: NodeJS.ErrnoException) => {
11
- if (err.code === 'EADDRINUSE' && attempt < maxAttempts) {
12
- attempt++
13
- tryPort(port + 1)
14
- } else {
15
- reject(err)
16
- }
17
- })
18
- server.listen(port, '127.0.0.1', () => {
19
- server.close(() => resolve(port))
20
- })
21
- }
22
-
23
- tryPort(preferred)
24
- })
25
- }
@@ -1,9 +0,0 @@
1
- export function orezTitle(label = 'orez'): string {
2
- const cwd = process.cwd()
3
- const home = process.env.HOME || ''
4
- const dir =
5
- home && cwd.startsWith(home + '/')
6
- ? '~' + cwd.slice(home.length)
7
- : cwd.split('/').pop()!
8
- return `${label} (${dir})`
9
- }