orez 0.2.27 → 0.2.30

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 (157) hide show
  1. package/dist/cf-do/worker.d.ts +3 -0
  2. package/dist/cf-do/worker.d.ts.map +1 -1
  3. package/dist/cf-do/worker.js +37 -15
  4. package/dist/cf-do/worker.js.map +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +8 -0
  7. package/dist/index.js.map +1 -1
  8. package/package.json +3 -4
  9. package/src/admin/admin-data.test.ts +0 -348
  10. package/src/admin/http-proxy.ts +0 -252
  11. package/src/admin/log-store.ts +0 -192
  12. package/src/admin/server.ts +0 -471
  13. package/src/admin/ui.ts +0 -1322
  14. package/src/bench/proxy-throughput.bench.ts +0 -343
  15. package/src/bench/serial-mutations.bench.ts +0 -270
  16. package/src/browser.ts +0 -203
  17. package/src/cf-do/.wrangler/cache/cf.json +0 -1
  18. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  19. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  20. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  21. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0ffaabee41a60e04dd0eb7db3073f0a40139e6a97ccd26823967acb652b89a7b.sqlite +0 -0
  22. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
  23. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
  24. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
  25. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-insertion-facade.js +0 -11
  26. package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-loader.entry.ts +0 -134
  27. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-insertion-facade.js +0 -11
  28. package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-loader.entry.ts +0 -134
  29. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js +0 -1059
  30. package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js.map +0 -8
  31. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js +0 -1059
  32. package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js.map +0 -8
  33. package/src/cf-do/ARCHITECTURE.md +0 -93
  34. package/src/cf-do/CHAT_E2E.md +0 -213
  35. package/src/cf-do/watermark.test.ts +0 -103
  36. package/src/cf-do/watermark.ts +0 -118
  37. package/src/cf-do/worker.ts +0 -1041
  38. package/src/cf-do/wrangler.toml +0 -11
  39. package/src/cf-pglite/README.md +0 -19
  40. package/src/change-tracking.ts +0 -25
  41. package/src/child-process.test.ts +0 -147
  42. package/src/child-process.ts +0 -90
  43. package/src/cli-entry.ts +0 -72
  44. package/src/cli.test.ts +0 -40
  45. package/src/cli.ts +0 -1214
  46. package/src/config.ts +0 -150
  47. package/src/do-sql-tracking.test.ts +0 -19
  48. package/src/do-sql-tracking.ts +0 -19
  49. package/src/index.ts +0 -1215
  50. package/src/integration/integration.test.ts +0 -517
  51. package/src/integration/native-binary.guard.test.ts +0 -13
  52. package/src/integration/native-startup.test.ts +0 -44
  53. package/src/integration/replication-latency.test.ts +0 -428
  54. package/src/integration/restore-live-stress.test.ts +0 -433
  55. package/src/integration/restore-reset.test.ts +0 -400
  56. package/src/integration/restore.test.ts +0 -274
  57. package/src/integration/test-permissions.ts +0 -147
  58. package/src/load-config.ts +0 -46
  59. package/src/log.ts +0 -96
  60. package/src/mutex.ts +0 -47
  61. package/src/pg-proxy-browser.singledb.test.ts +0 -233
  62. package/src/pg-proxy-browser.ts +0 -2022
  63. package/src/pg-proxy-do-backend.test.ts +0 -3890
  64. package/src/pg-proxy-do-backend.ts +0 -7191
  65. package/src/pg-proxy.ts +0 -1087
  66. package/src/pg-sqlite-compiler/README.md +0 -53
  67. package/src/pg-sqlite-compiler/catalog/seed.ts +0 -524
  68. package/src/pg-sqlite-compiler/fixtures/pgsqlite/arithmetic.json +0 -307
  69. package/src/pg-sqlite-compiler/fixtures/pgsqlite/array.json +0 -377
  70. package/src/pg-sqlite-compiler/fixtures/pgsqlite/cast.json +0 -12
  71. package/src/pg-sqlite-compiler/fixtures/pgsqlite/catalog.json +0 -447
  72. package/src/pg-sqlite-compiler/fixtures/pgsqlite/create-table.json +0 -32
  73. package/src/pg-sqlite-compiler/fixtures/pgsqlite/datetime.json +0 -397
  74. package/src/pg-sqlite-compiler/fixtures/pgsqlite/enum.json +0 -337
  75. package/src/pg-sqlite-compiler/fixtures/pgsqlite/insert.json +0 -337
  76. package/src/pg-sqlite-compiler/fixtures/pgsqlite/json.json +0 -537
  77. package/src/pg-sqlite-compiler/fixtures/pgsqlite/misc.json +0 -1837
  78. package/src/pg-sqlite-compiler/index.ts +0 -73
  79. package/src/pg-sqlite-compiler/integration.test.ts +0 -136
  80. package/src/pg-sqlite-compiler/passes/ast-utils.ts +0 -113
  81. package/src/pg-sqlite-compiler/passes/catalog.ts +0 -65
  82. package/src/pg-sqlite-compiler/passes/datetime.ts +0 -74
  83. package/src/pg-sqlite-compiler/passes/index.ts +0 -49
  84. package/src/pg-sqlite-compiler/passes/types.ts +0 -156
  85. package/src/pg-sqlite-compiler/smoke.test.ts +0 -69
  86. package/src/pg-sqlite-compiler/test/catalog.test.ts +0 -171
  87. package/src/pg-sqlite-compiler/test/corpus.test.ts +0 -161
  88. package/src/pg-sqlite-compiler/test/datetime.oracle.test.ts +0 -102
  89. package/src/pg-sqlite-compiler/test/oracle.ts +0 -237
  90. package/src/pg-sqlite-compiler/test/types.test.ts +0 -109
  91. package/src/pg-sqlite-compiler/types.ts +0 -63
  92. package/src/pglite-ipc.test.ts +0 -116
  93. package/src/pglite-ipc.ts +0 -266
  94. package/src/pglite-manager.ts +0 -557
  95. package/src/pglite-web-proxy.test.ts +0 -57
  96. package/src/pglite-web-proxy.ts +0 -221
  97. package/src/pglite-web-worker.ts +0 -152
  98. package/src/pglite-worker-thread.ts +0 -253
  99. package/src/port.ts +0 -25
  100. package/src/process-title.ts +0 -9
  101. package/src/recovery.ts +0 -155
  102. package/src/replication/change-tracker.test.ts +0 -357
  103. package/src/replication/change-tracker.ts +0 -279
  104. package/src/replication/handler.test.ts +0 -511
  105. package/src/replication/handler.ts +0 -1190
  106. package/src/replication/pgoutput-encoder.test.ts +0 -697
  107. package/src/replication/pgoutput-encoder.ts +0 -373
  108. package/src/replication/tcp-replication.test.ts +0 -876
  109. package/src/replication/zero-compat.test.ts +0 -1150
  110. package/src/restore-stress.test.ts +0 -188
  111. package/src/s3-local.ts +0 -203
  112. package/src/shim/hooks.mjs +0 -120
  113. package/src/shim/register.mjs +0 -4
  114. package/src/sqlite-mode/apply-mode.ts +0 -224
  115. package/src/sqlite-mode/index.ts +0 -15
  116. package/src/sqlite-mode/native-binary.ts +0 -89
  117. package/src/sqlite-mode/package-resolve.ts +0 -17
  118. package/src/sqlite-mode/resolve-mode.ts +0 -80
  119. package/src/sqlite-mode/shim-template.ts +0 -159
  120. package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
  121. package/src/sqlite-mode/types.ts +0 -30
  122. package/src/vite-plugin.ts +0 -67
  123. package/src/wasm-sqlite.test.ts +0 -537
  124. package/src/worker/browser-admin.ts +0 -52
  125. package/src/worker/browser-build-config.test.ts +0 -71
  126. package/src/worker/browser-build-config.ts +0 -109
  127. package/src/worker/browser-embed-admin.test.ts +0 -75
  128. package/src/worker/browser-embed.ts +0 -345
  129. package/src/worker/cf-patches.ts +0 -384
  130. package/src/worker/embed-integration.test.ts +0 -321
  131. package/src/worker/index.ts +0 -138
  132. package/src/worker/shims/fastify.test.ts +0 -255
  133. package/src/worker/shims/fastify.ts +0 -306
  134. package/src/worker/shims/http-service.test.ts +0 -355
  135. package/src/worker/shims/http-service.ts +0 -293
  136. package/src/worker/shims/node-stub.ts +0 -290
  137. package/src/worker/shims/oxfmt.ts +0 -3
  138. package/src/worker/shims/postgres-browser.ts +0 -59
  139. package/src/worker/shims/postgres-socket.test.ts +0 -576
  140. package/src/worker/shims/postgres-socket.ts +0 -310
  141. package/src/worker/shims/postgres.test.ts +0 -364
  142. package/src/worker/shims/postgres.ts +0 -1454
  143. package/src/worker/shims/sqlite-browser.test.ts +0 -233
  144. package/src/worker/shims/sqlite-browser.ts +0 -175
  145. package/src/worker/shims/sqlite.test.ts +0 -786
  146. package/src/worker/shims/sqlite.ts +0 -978
  147. package/src/worker/shims/stream-browser.ts +0 -15
  148. package/src/worker/shims/ws-browser.test.ts +0 -205
  149. package/src/worker/shims/ws-browser.ts +0 -248
  150. package/src/worker/shims/ws.test.ts +0 -288
  151. package/src/worker/shims/ws.ts +0 -467
  152. package/src/worker/shims/zero-process-env.ts +0 -11
  153. package/src/worker/types.ts +0 -75
  154. package/src/worker/worker-integration.test.ts +0 -223
  155. package/src/worker/worker.test.ts +0 -136
  156. package/src/worker/zero-cache-embed-cf.ts +0 -463
  157. 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
- }