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.
- package/dist/cf-do/worker.d.ts +3 -0
- package/dist/cf-do/worker.d.ts.map +1 -1
- package/dist/cf-do/worker.js +37 -15
- package/dist/cf-do/worker.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -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/0ffaabee41a60e04dd0eb7db3073f0a40139e6a97ccd26823967acb652b89a7b.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/.wrangler/tmp/bundle-0z4CpE/middleware-insertion-facade.js +0 -11
- package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-loader.entry.ts +0 -134
- package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-insertion-facade.js +0 -11
- package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-loader.entry.ts +0 -134
- package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js +0 -1059
- package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js.map +0 -8
- package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js +0 -1059
- package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js.map +0 -8
- package/src/cf-do/ARCHITECTURE.md +0 -93
- package/src/cf-do/CHAT_E2E.md +0 -213
- package/src/cf-do/watermark.test.ts +0 -103
- package/src/cf-do/watermark.ts +0 -118
- package/src/cf-do/worker.ts +0 -1041
- 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 -40
- 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 -7191
- package/src/pg-proxy.ts +0 -1087
- package/src/pg-sqlite-compiler/README.md +0 -53
- package/src/pg-sqlite-compiler/catalog/seed.ts +0 -524
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/arithmetic.json +0 -307
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/array.json +0 -377
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/cast.json +0 -12
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/catalog.json +0 -447
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/create-table.json +0 -32
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/datetime.json +0 -397
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/enum.json +0 -337
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/insert.json +0 -337
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/json.json +0 -537
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/misc.json +0 -1837
- package/src/pg-sqlite-compiler/index.ts +0 -73
- package/src/pg-sqlite-compiler/integration.test.ts +0 -136
- package/src/pg-sqlite-compiler/passes/ast-utils.ts +0 -113
- package/src/pg-sqlite-compiler/passes/catalog.ts +0 -65
- package/src/pg-sqlite-compiler/passes/datetime.ts +0 -74
- package/src/pg-sqlite-compiler/passes/index.ts +0 -49
- package/src/pg-sqlite-compiler/passes/types.ts +0 -156
- package/src/pg-sqlite-compiler/smoke.test.ts +0 -69
- package/src/pg-sqlite-compiler/test/catalog.test.ts +0 -171
- package/src/pg-sqlite-compiler/test/corpus.test.ts +0 -161
- package/src/pg-sqlite-compiler/test/datetime.oracle.test.ts +0 -102
- package/src/pg-sqlite-compiler/test/oracle.ts +0 -237
- package/src/pg-sqlite-compiler/test/types.test.ts +0 -109
- package/src/pg-sqlite-compiler/types.ts +0 -63
- 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
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { writeFileSync, unlinkSync } from 'node:fs'
|
|
2
|
-
import { tmpdir } from 'node:os'
|
|
3
|
-
import { join } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { PGlite } from '@electric-sql/pglite'
|
|
6
|
-
import { loadModule } from 'pgsql-parser'
|
|
7
|
-
import postgres from 'postgres'
|
|
8
|
-
import { describe, it, expect, beforeAll, afterEach } from 'vitest'
|
|
9
|
-
|
|
10
|
-
import { execDumpFile } from './cli.js'
|
|
11
|
-
import { getConfig } from './config.js'
|
|
12
|
-
import { startPgProxy } from './pg-proxy.js'
|
|
13
|
-
|
|
14
|
-
import type { Server } from 'node:net'
|
|
15
|
-
import type { AddressInfo } from 'node:net'
|
|
16
|
-
|
|
17
|
-
// generate a pg_dump-style SQL file with COPY data
|
|
18
|
-
function generateDump(opts: {
|
|
19
|
-
tables: number
|
|
20
|
-
rowsPerTable: number
|
|
21
|
-
columnsPerTable: number
|
|
22
|
-
}): string {
|
|
23
|
-
const lines: string[] = []
|
|
24
|
-
lines.push('-- pg_dump style output')
|
|
25
|
-
lines.push('SET statement_timeout = 0;')
|
|
26
|
-
lines.push("SET client_encoding = 'UTF8';")
|
|
27
|
-
lines.push('')
|
|
28
|
-
|
|
29
|
-
for (let t = 0; t < opts.tables; t++) {
|
|
30
|
-
const tableName = `test_table_${t}`
|
|
31
|
-
const cols = Array.from({ length: opts.columnsPerTable }, (_, i) => `col_${i} TEXT`)
|
|
32
|
-
lines.push(`CREATE TABLE ${tableName} (id SERIAL PRIMARY KEY, ${cols.join(', ')});`)
|
|
33
|
-
lines.push('')
|
|
34
|
-
|
|
35
|
-
// COPY block
|
|
36
|
-
const colNames = Array.from({ length: opts.columnsPerTable }, (_, i) => `col_${i}`)
|
|
37
|
-
lines.push(`COPY ${tableName} (id, ${colNames.join(', ')}) FROM stdin;`)
|
|
38
|
-
|
|
39
|
-
for (let r = 0; r < opts.rowsPerTable; r++) {
|
|
40
|
-
const vals = Array.from({ length: opts.columnsPerTable }, (_, i) => {
|
|
41
|
-
if (r % 17 === 0 && i === 0) return '\\N'
|
|
42
|
-
if (r % 13 === 0 && i === 1) return `value with tab\\there`
|
|
43
|
-
if (r % 11 === 0 && i === 2) return `O'Brien's "quoted" value\\nwith newline`
|
|
44
|
-
return `row_${r}_col_${i}_${'x'.repeat(20)}`
|
|
45
|
-
})
|
|
46
|
-
lines.push(`${r + 1}\t${vals.join('\t')}`)
|
|
47
|
-
}
|
|
48
|
-
lines.push('\\.')
|
|
49
|
-
lines.push('')
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return lines.join('\n')
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
describe('restore stress', () => {
|
|
56
|
-
let tmpFile: string
|
|
57
|
-
|
|
58
|
-
beforeAll(async () => {
|
|
59
|
-
await loadModule()
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
afterEach(() => {
|
|
63
|
-
try {
|
|
64
|
-
unlinkSync(tmpFile)
|
|
65
|
-
} catch {}
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('direct: 5 tables x 500 rows', async () => {
|
|
69
|
-
const dump = generateDump({ tables: 5, rowsPerTable: 500, columnsPerTable: 5 })
|
|
70
|
-
tmpFile = join(tmpdir(), `orez-stress-${Date.now()}.sql`)
|
|
71
|
-
writeFileSync(tmpFile, dump)
|
|
72
|
-
|
|
73
|
-
const db = new PGlite({ relaxedDurability: true })
|
|
74
|
-
await db.waitReady
|
|
75
|
-
|
|
76
|
-
const { executed, skipped } = await execDumpFile(db, tmpFile)
|
|
77
|
-
|
|
78
|
-
for (let t = 0; t < 5; t++) {
|
|
79
|
-
const result = await db.query(`SELECT count(*) as cnt FROM test_table_${t}`)
|
|
80
|
-
expect(Number(result.rows[0].cnt)).toBe(500)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
console.log(`direct: ${executed} executed, ${skipped} skipped`)
|
|
84
|
-
await db.close()
|
|
85
|
-
}, 60_000)
|
|
86
|
-
|
|
87
|
-
it('direct: 2 tables x 5000 rows (memory pressure)', async () => {
|
|
88
|
-
const dump = generateDump({ tables: 2, rowsPerTable: 5000, columnsPerTable: 5 })
|
|
89
|
-
tmpFile = join(tmpdir(), `orez-stress-large-${Date.now()}.sql`)
|
|
90
|
-
writeFileSync(tmpFile, dump)
|
|
91
|
-
|
|
92
|
-
const db = new PGlite({ relaxedDurability: true })
|
|
93
|
-
await db.waitReady
|
|
94
|
-
|
|
95
|
-
const { executed, skipped } = await execDumpFile(db, tmpFile)
|
|
96
|
-
|
|
97
|
-
for (let t = 0; t < 2; t++) {
|
|
98
|
-
const result = await db.query(`SELECT count(*) as cnt FROM test_table_${t}`)
|
|
99
|
-
expect(Number(result.rows[0].cnt)).toBe(5000)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
console.log(`large direct: ${executed} executed, ${skipped} skipped`)
|
|
103
|
-
await db.close()
|
|
104
|
-
}, 120_000)
|
|
105
|
-
|
|
106
|
-
it('wire: 3 tables x 1000 rows through pg proxy', async () => {
|
|
107
|
-
const dump = generateDump({ tables: 3, rowsPerTable: 1000, columnsPerTable: 5 })
|
|
108
|
-
tmpFile = join(tmpdir(), `orez-stress-wire-${Date.now()}.sql`)
|
|
109
|
-
writeFileSync(tmpFile, dump)
|
|
110
|
-
|
|
111
|
-
const db = new PGlite({ relaxedDurability: true })
|
|
112
|
-
await db.waitReady
|
|
113
|
-
|
|
114
|
-
const config = { ...getConfig(), pgPort: 0 }
|
|
115
|
-
const server: Server = await startPgProxy(db, config)
|
|
116
|
-
const port = (server.address() as AddressInfo).port
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const sql = postgres({
|
|
120
|
-
host: '127.0.0.1',
|
|
121
|
-
port,
|
|
122
|
-
user: 'user',
|
|
123
|
-
password: 'password',
|
|
124
|
-
database: 'postgres',
|
|
125
|
-
max: 1,
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
const wireDb = { exec: (query: string) => sql.unsafe(query) as Promise<unknown> }
|
|
129
|
-
const { executed, skipped } = await execDumpFile(wireDb, tmpFile)
|
|
130
|
-
|
|
131
|
-
for (let t = 0; t < 3; t++) {
|
|
132
|
-
const result =
|
|
133
|
-
await sql`SELECT count(*) as cnt FROM test_table_${sql.unsafe(String(t))}`
|
|
134
|
-
// use direct db to verify
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// verify via direct PGlite
|
|
138
|
-
for (let t = 0; t < 3; t++) {
|
|
139
|
-
const result = await db.query(`SELECT count(*) as cnt FROM test_table_${t}`)
|
|
140
|
-
expect(Number(result.rows[0].cnt)).toBe(1000)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log(`wire: ${executed} executed, ${skipped} skipped`)
|
|
144
|
-
await sql.end()
|
|
145
|
-
} finally {
|
|
146
|
-
server.close()
|
|
147
|
-
await db.close()
|
|
148
|
-
}
|
|
149
|
-
}, 120_000)
|
|
150
|
-
|
|
151
|
-
it('wire: 2 tables x 3000 rows (memory pressure via proxy)', async () => {
|
|
152
|
-
const dump = generateDump({ tables: 2, rowsPerTable: 3000, columnsPerTable: 8 })
|
|
153
|
-
tmpFile = join(tmpdir(), `orez-stress-wire-large-${Date.now()}.sql`)
|
|
154
|
-
writeFileSync(tmpFile, dump)
|
|
155
|
-
|
|
156
|
-
const db = new PGlite({ relaxedDurability: true })
|
|
157
|
-
await db.waitReady
|
|
158
|
-
|
|
159
|
-
const config = { ...getConfig(), pgPort: 0 }
|
|
160
|
-
const server: Server = await startPgProxy(db, config)
|
|
161
|
-
const port = (server.address() as AddressInfo).port
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const sql = postgres({
|
|
165
|
-
host: '127.0.0.1',
|
|
166
|
-
port,
|
|
167
|
-
user: 'user',
|
|
168
|
-
password: 'password',
|
|
169
|
-
database: 'postgres',
|
|
170
|
-
max: 1,
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
const wireDb = { exec: (query: string) => sql.unsafe(query) as Promise<unknown> }
|
|
174
|
-
const { executed, skipped } = await execDumpFile(wireDb, tmpFile)
|
|
175
|
-
|
|
176
|
-
for (let t = 0; t < 2; t++) {
|
|
177
|
-
const result = await db.query(`SELECT count(*) as cnt FROM test_table_${t}`)
|
|
178
|
-
expect(Number(result.rows[0].cnt)).toBe(3000)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
console.log(`wire large: ${executed} executed, ${skipped} skipped`)
|
|
182
|
-
await sql.end()
|
|
183
|
-
} finally {
|
|
184
|
-
server.close()
|
|
185
|
-
await db.close()
|
|
186
|
-
}
|
|
187
|
-
}, 180_000)
|
|
188
|
-
})
|
package/src/s3-local.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* minimal local s3-compatible server.
|
|
3
|
-
* handles GET/PUT/DELETE/HEAD for object storage.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
existsSync,
|
|
8
|
-
mkdirSync,
|
|
9
|
-
readFileSync,
|
|
10
|
-
readdirSync,
|
|
11
|
-
writeFileSync,
|
|
12
|
-
unlinkSync,
|
|
13
|
-
statSync,
|
|
14
|
-
} from 'node:fs'
|
|
15
|
-
import {
|
|
16
|
-
createServer,
|
|
17
|
-
type Server,
|
|
18
|
-
type IncomingMessage,
|
|
19
|
-
type ServerResponse,
|
|
20
|
-
} from 'node:http'
|
|
21
|
-
import { join, dirname, extname } from 'node:path'
|
|
22
|
-
|
|
23
|
-
import { log } from './log.js'
|
|
24
|
-
|
|
25
|
-
export interface S3LocalConfig {
|
|
26
|
-
port: number
|
|
27
|
-
dataDir: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const MIME_TYPES: Record<string, string> = {
|
|
31
|
-
'.jpg': 'image/jpeg',
|
|
32
|
-
'.jpeg': 'image/jpeg',
|
|
33
|
-
'.png': 'image/png',
|
|
34
|
-
'.gif': 'image/gif',
|
|
35
|
-
'.webp': 'image/webp',
|
|
36
|
-
'.svg': 'image/svg+xml',
|
|
37
|
-
'.json': 'application/json',
|
|
38
|
-
'.txt': 'text/plain',
|
|
39
|
-
'.pdf': 'application/pdf',
|
|
40
|
-
'.mp4': 'video/mp4',
|
|
41
|
-
'.mp3': 'audio/mpeg',
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function corsHeaders(): Record<string, string> {
|
|
45
|
-
return {
|
|
46
|
-
'Access-Control-Allow-Origin': '*',
|
|
47
|
-
'Access-Control-Allow-Methods': 'GET, PUT, DELETE, HEAD, OPTIONS',
|
|
48
|
-
'Access-Control-Allow-Headers': '*',
|
|
49
|
-
'Access-Control-Expose-Headers': 'ETag, Content-Length',
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function startS3Local(config: S3LocalConfig): Promise<Server> {
|
|
54
|
-
const storageDir = join(config.dataDir, 's3')
|
|
55
|
-
mkdirSync(storageDir, { recursive: true })
|
|
56
|
-
|
|
57
|
-
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
|
58
|
-
const headers = corsHeaders()
|
|
59
|
-
|
|
60
|
-
if (req.method === 'OPTIONS') {
|
|
61
|
-
res.writeHead(200, headers)
|
|
62
|
-
res.end()
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const url = new URL(req.url || '/', `http://localhost:${config.port}`)
|
|
67
|
-
|
|
68
|
-
// sanitize path to prevent traversal
|
|
69
|
-
const normalized = url.pathname
|
|
70
|
-
.split('/')
|
|
71
|
-
.filter((s) => s && s !== '..' && s !== '.')
|
|
72
|
-
.join('/')
|
|
73
|
-
const filePath = join(storageDir, normalized)
|
|
74
|
-
if (!filePath.startsWith(storageDir)) {
|
|
75
|
-
res.writeHead(403, headers)
|
|
76
|
-
res.end()
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
switch (req.method) {
|
|
82
|
-
case 'GET': {
|
|
83
|
-
// S3 ListObjectsV2: GET /?list-type=2&prefix=...&max-keys=...
|
|
84
|
-
if (url.searchParams.get('list-type') === '2') {
|
|
85
|
-
const prefix = url.searchParams.get('prefix') || ''
|
|
86
|
-
const maxKeys = parseInt(url.searchParams.get('max-keys') || '1000')
|
|
87
|
-
const baseDir = join(storageDir, prefix)
|
|
88
|
-
const keys: string[] = []
|
|
89
|
-
|
|
90
|
-
function walkList(dir: string) {
|
|
91
|
-
if (keys.length >= maxKeys) return
|
|
92
|
-
let entries
|
|
93
|
-
try {
|
|
94
|
-
entries = readdirSync(dir, { withFileTypes: true })
|
|
95
|
-
} catch {
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
for (const entry of entries) {
|
|
99
|
-
if (keys.length >= maxKeys) break
|
|
100
|
-
const full = join(dir, entry.name)
|
|
101
|
-
if (entry.isDirectory()) {
|
|
102
|
-
walkList(full)
|
|
103
|
-
} else {
|
|
104
|
-
const rel = full.slice(storageDir.length + 1)
|
|
105
|
-
keys.push(rel)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
walkList(baseDir)
|
|
110
|
-
|
|
111
|
-
const keysXml = keys
|
|
112
|
-
.map((k) => `<Contents><Key>${k}</Key></Contents>`)
|
|
113
|
-
.join('')
|
|
114
|
-
const xml = `<?xml version="1.0" encoding="UTF-8"?><ListBucketResult><KeyCount>${keys.length}</KeyCount>${keysXml}</ListBucketResult>`
|
|
115
|
-
res.writeHead(200, { ...headers, 'Content-Type': 'application/xml' })
|
|
116
|
-
res.end(xml)
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!existsSync(filePath) || statSync(filePath).isDirectory()) {
|
|
121
|
-
res.writeHead(404, {
|
|
122
|
-
...headers,
|
|
123
|
-
'Content-Type': 'application/xml',
|
|
124
|
-
})
|
|
125
|
-
res.end('<Error><Code>NoSuchKey</Code></Error>')
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
const data = readFileSync(filePath)
|
|
129
|
-
const ext = extname(filePath)
|
|
130
|
-
const contentType = MIME_TYPES[ext] || 'application/octet-stream'
|
|
131
|
-
res.writeHead(200, {
|
|
132
|
-
...headers,
|
|
133
|
-
'Content-Type': contentType,
|
|
134
|
-
'Content-Length': data.length.toString(),
|
|
135
|
-
ETag: `"${Buffer.from(data).length}"`,
|
|
136
|
-
})
|
|
137
|
-
res.end(data)
|
|
138
|
-
break
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
case 'PUT': {
|
|
142
|
-
const chunks: Buffer[] = []
|
|
143
|
-
req.on('data', (chunk: Buffer) => chunks.push(chunk))
|
|
144
|
-
req.on('end', () => {
|
|
145
|
-
mkdirSync(dirname(filePath), { recursive: true })
|
|
146
|
-
const body = Buffer.concat(chunks)
|
|
147
|
-
writeFileSync(filePath, body)
|
|
148
|
-
res.writeHead(200, {
|
|
149
|
-
...headers,
|
|
150
|
-
ETag: `"${body.length}"`,
|
|
151
|
-
})
|
|
152
|
-
res.end()
|
|
153
|
-
})
|
|
154
|
-
break
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
case 'DELETE': {
|
|
158
|
-
if (existsSync(filePath)) {
|
|
159
|
-
unlinkSync(filePath)
|
|
160
|
-
}
|
|
161
|
-
res.writeHead(204, headers)
|
|
162
|
-
res.end()
|
|
163
|
-
break
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
case 'HEAD': {
|
|
167
|
-
if (!existsSync(filePath) || statSync(filePath).isDirectory()) {
|
|
168
|
-
res.writeHead(404, headers)
|
|
169
|
-
res.end()
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
const stat = statSync(filePath)
|
|
173
|
-
const ext2 = extname(filePath)
|
|
174
|
-
res.writeHead(200, {
|
|
175
|
-
...headers,
|
|
176
|
-
'Content-Type': MIME_TYPES[ext2] || 'application/octet-stream',
|
|
177
|
-
'Content-Length': stat.size.toString(),
|
|
178
|
-
})
|
|
179
|
-
res.end()
|
|
180
|
-
break
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
default:
|
|
184
|
-
res.writeHead(405, headers)
|
|
185
|
-
res.end()
|
|
186
|
-
}
|
|
187
|
-
} catch {
|
|
188
|
-
res.writeHead(500, {
|
|
189
|
-
...headers,
|
|
190
|
-
'Content-Type': 'application/xml',
|
|
191
|
-
})
|
|
192
|
-
res.end('<Error><Code>InternalError</Code></Error>')
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
return new Promise((resolve, reject) => {
|
|
197
|
-
server.listen(config.port, '127.0.0.1', () => {
|
|
198
|
-
log.s3(`listening on port ${config.port}`)
|
|
199
|
-
resolve(server)
|
|
200
|
-
})
|
|
201
|
-
server.on('error', reject)
|
|
202
|
-
})
|
|
203
|
-
}
|
package/src/shim/hooks.mjs
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// esm loader hooks — intercept @rocicorp/zero-sqlite3 with bedrock-sqlite wasm.
|
|
2
|
-
//
|
|
3
|
-
// NOTE: this file is currently UNUSED. orez uses in-place CJS patching via
|
|
4
|
-
// src/sqlite-mode/apply-mode.ts instead. this file is kept for potential future
|
|
5
|
-
// use with Node.js ESM loader hooks (--import flag).
|
|
6
|
-
//
|
|
7
|
-
// __BEDROCK_PATH__ is replaced at runtime by orez before writing to tmpdir.
|
|
8
|
-
|
|
9
|
-
const SHIM_URL = 'orez-sqlite-shim://shim'
|
|
10
|
-
const BEDROCK_PATH = '__BEDROCK_PATH__'
|
|
11
|
-
// __JOURNAL_MODE__ would be replaced at runtime (delete for wasm, wal2 for native)
|
|
12
|
-
const JOURNAL_MODE = '__JOURNAL_MODE__'
|
|
13
|
-
|
|
14
|
-
export function resolve(specifier, context, nextResolve) {
|
|
15
|
-
if (
|
|
16
|
-
specifier === '@rocicorp/zero-sqlite3' ||
|
|
17
|
-
specifier.startsWith('@rocicorp/zero-sqlite3/')
|
|
18
|
-
) {
|
|
19
|
-
return { url: SHIM_URL, shortCircuit: true }
|
|
20
|
-
}
|
|
21
|
-
return nextResolve(specifier, context)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function load(url, context, nextLoad) {
|
|
25
|
-
if (url === SHIM_URL) {
|
|
26
|
-
// journal mode differs between native and wasm:
|
|
27
|
-
// - native: wal2 for better concurrency
|
|
28
|
-
// - wasm: delete for compatibility (wal2 can corrupt wasm vfs)
|
|
29
|
-
const journalMode = JOURNAL_MODE === '__JOURNAL_MODE__' ? 'delete' : JOURNAL_MODE
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
format: 'module',
|
|
33
|
-
shortCircuit: true,
|
|
34
|
-
source: `
|
|
35
|
-
// orez sqlite shim - wraps bedrock-sqlite for zero-cache compatibility
|
|
36
|
-
// journal_mode: ${journalMode}
|
|
37
|
-
|
|
38
|
-
// catch uncaught exceptions from bedrock-sqlite wasm clearly
|
|
39
|
-
process.on('uncaughtException', (err) => {
|
|
40
|
-
console.error('[orez-shim] UNCAUGHT EXCEPTION:', err?.message || err);
|
|
41
|
-
console.error('[orez-shim] code:', err?.code, 'name:', err?.name);
|
|
42
|
-
console.error('[orez-shim] stack:', err?.stack?.split('\\n').slice(0, 5).join('\\n'));
|
|
43
|
-
process.exit(1);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
import { createRequire } from 'node:module';
|
|
47
|
-
const require = createRequire('${BEDROCK_PATH}');
|
|
48
|
-
const mod = require('${BEDROCK_PATH}');
|
|
49
|
-
const OrigDatabase = mod.Database;
|
|
50
|
-
const SqliteError = mod.SqliteError;
|
|
51
|
-
|
|
52
|
-
function Database(...args) {
|
|
53
|
-
const db = new OrigDatabase(...args);
|
|
54
|
-
try {
|
|
55
|
-
db.pragma('journal_mode = ${journalMode}');
|
|
56
|
-
db.pragma('busy_timeout = 30000');
|
|
57
|
-
db.pragma('synchronous = normal');
|
|
58
|
-
} catch(e) {}
|
|
59
|
-
return db;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
Database.prototype = OrigDatabase.prototype;
|
|
63
|
-
Database.prototype.constructor = Database;
|
|
64
|
-
Object.keys(OrigDatabase).forEach(k => { Database[k] = OrigDatabase[k]; });
|
|
65
|
-
|
|
66
|
-
// api polyfills for better-sqlite3 compatibility
|
|
67
|
-
Database.prototype.unsafeMode = function() { return this; };
|
|
68
|
-
if (!Database.prototype.defaultSafeIntegers) {
|
|
69
|
-
Database.prototype.defaultSafeIntegers = function() { return this; };
|
|
70
|
-
}
|
|
71
|
-
if (!Database.prototype.serialize) {
|
|
72
|
-
Database.prototype.serialize = function() { throw new Error('not supported in wasm'); };
|
|
73
|
-
}
|
|
74
|
-
if (!Database.prototype.backup) {
|
|
75
|
-
Database.prototype.backup = function() { throw new Error('not supported in wasm'); };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// wrap pragma to skip optimize (can corrupt wasm vfs) and swallow sqlite errors
|
|
79
|
-
const origPragma = OrigDatabase.prototype.pragma;
|
|
80
|
-
Database.prototype.pragma = function(str, opts) {
|
|
81
|
-
if (str && str.trim().toLowerCase().startsWith('optimize')) return [];
|
|
82
|
-
try { return origPragma.call(this, str, opts); }
|
|
83
|
-
catch(e) { if (e && (e.code === 'SQLITE_CORRUPT' || e.code === 'SQLITE_IOERR')) return []; throw e; }
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
// wrap close to swallow wasm errors during shutdown
|
|
87
|
-
const origClose = OrigDatabase.prototype.close;
|
|
88
|
-
Database.prototype.close = function() {
|
|
89
|
-
try { return origClose.call(this); }
|
|
90
|
-
catch(e) { console.error('[orez-shim] close error (swallowed):', e?.message || e); }
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// statement prototype polyfills
|
|
94
|
-
const tmpDb = new OrigDatabase(':memory:');
|
|
95
|
-
const tmpStmt = tmpDb.prepare('SELECT 1');
|
|
96
|
-
const SP = Object.getPrototypeOf(tmpStmt);
|
|
97
|
-
if (!SP.safeIntegers) SP.safeIntegers = function() { return this; };
|
|
98
|
-
SP.scanStatus = function() { return undefined; };
|
|
99
|
-
SP.scanStatusV2 = function() { return []; };
|
|
100
|
-
SP.scanStatusReset = function() {};
|
|
101
|
-
tmpDb.close();
|
|
102
|
-
|
|
103
|
-
// scanstat constants for query planner compatibility
|
|
104
|
-
Database.SQLITE_SCANSTAT_NLOOP = 0;
|
|
105
|
-
Database.SQLITE_SCANSTAT_NVISIT = 1;
|
|
106
|
-
Database.SQLITE_SCANSTAT_EST = 2;
|
|
107
|
-
Database.SQLITE_SCANSTAT_NAME = 3;
|
|
108
|
-
Database.SQLITE_SCANSTAT_EXPLAIN = 4;
|
|
109
|
-
Database.SQLITE_SCANSTAT_SELECTID = 5;
|
|
110
|
-
Database.SQLITE_SCANSTAT_PARENTID = 6;
|
|
111
|
-
Database.SQLITE_SCANSTAT_NCYCLE = 7;
|
|
112
|
-
Database.SQLITE_SCANSTAT_COMPLEX = 8;
|
|
113
|
-
|
|
114
|
-
export default Database;
|
|
115
|
-
export { SqliteError };
|
|
116
|
-
`,
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return nextLoad(url, context)
|
|
120
|
-
}
|
package/src/shim/register.mjs
DELETED