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