orez 0.2.9 → 0.2.11
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/admin/server.d.ts +7 -0
- package/dist/admin/server.d.ts.map +1 -1
- package/dist/admin/server.js +260 -0
- package/dist/admin/server.js.map +1 -1
- package/dist/admin/ui.d.ts.map +1 -1
- package/dist/admin/ui.js +1320 -725
- package/dist/admin/ui.js.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/pg-proxy-browser.d.ts.map +1 -1
- package/dist/pg-proxy-browser.js +91 -44
- package/dist/pg-proxy-browser.js.map +1 -1
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +1 -0
- package/dist/vite-plugin.js.map +1 -1
- package/dist/worker/shims/ws-browser.d.ts.map +1 -1
- package/dist/worker/shims/ws-browser.js +23 -1
- package/dist/worker/shims/ws-browser.js.map +1 -1
- package/package.json +2 -2
- package/src/admin/admin-data.test.ts +296 -0
- package/src/admin/server.ts +277 -0
- package/src/admin/ui.ts +1320 -727
- package/src/cli.ts +2 -0
- package/src/pg-proxy-browser.ts +98 -52
- package/src/vite-plugin.ts +1 -0
- package/src/worker/shims/ws-browser.ts +25 -1
package/src/cli.ts
CHANGED
|
@@ -1107,6 +1107,7 @@ const main = defineCommand({
|
|
|
1107
1107
|
const {
|
|
1108
1108
|
config,
|
|
1109
1109
|
stop,
|
|
1110
|
+
instances,
|
|
1110
1111
|
zeroEnv,
|
|
1111
1112
|
logStore,
|
|
1112
1113
|
httpLog,
|
|
@@ -1162,6 +1163,7 @@ const main = defineCommand({
|
|
|
1162
1163
|
zeroEnv,
|
|
1163
1164
|
actions: { restartZero, stopZero, resetZero, resetZeroFull },
|
|
1164
1165
|
startTime: Date.now(),
|
|
1166
|
+
db: instances,
|
|
1165
1167
|
})
|
|
1166
1168
|
log.orez(`admin: ${url(`http://localhost:${config.adminPort}`)}`)
|
|
1167
1169
|
}
|
package/src/pg-proxy-browser.ts
CHANGED
|
@@ -29,6 +29,41 @@ import type { PGlite } from '@electric-sql/pglite'
|
|
|
29
29
|
const textEncoder = new TextEncoder()
|
|
30
30
|
const textDecoder = new TextDecoder()
|
|
31
31
|
|
|
32
|
+
// verbose wire-protocol logging. off by default — every postgres message hits
|
|
33
|
+
// the hot path, so unconditional console.debug calls are surprisingly expensive
|
|
34
|
+
// even when devtools is set to hide them (the interpolated strings still get
|
|
35
|
+
// built, and devtools retains them).
|
|
36
|
+
//
|
|
37
|
+
// re-evaluated on every call so you can flip it at runtime from any iframe,
|
|
38
|
+
// worker, or console without restarting. toggle via either:
|
|
39
|
+
// - env: OREZ_DEBUG_WIRE=1 (picked up at process start)
|
|
40
|
+
// - global: globalThis.__OREZ_DEBUG_WIRE__ = true (works anywhere, anytime)
|
|
41
|
+
function isDebugWire(): boolean {
|
|
42
|
+
try {
|
|
43
|
+
if ((globalThis as any).__OREZ_DEBUG_WIRE__ === true) return true
|
|
44
|
+
if (typeof process !== 'undefined' && process.env?.OREZ_DEBUG_WIRE) return true
|
|
45
|
+
} catch {}
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// postgres frontend/backend message type bytes — only used for debug-wire logging
|
|
50
|
+
const PG_MSG_TYPE_NAMES: Record<number, string> = {
|
|
51
|
+
0x50: 'Parse',
|
|
52
|
+
0x42: 'Bind',
|
|
53
|
+
0x44: 'Describe',
|
|
54
|
+
0x45: 'Execute',
|
|
55
|
+
0x43: 'Close',
|
|
56
|
+
0x48: 'Flush',
|
|
57
|
+
0x53: 'Sync',
|
|
58
|
+
0x51: 'Query',
|
|
59
|
+
0x58: 'Terminate',
|
|
60
|
+
0x70: 'Password',
|
|
61
|
+
0x46: 'FunctionCall',
|
|
62
|
+
0x64: 'CopyData',
|
|
63
|
+
0x63: 'CopyDone',
|
|
64
|
+
0x66: 'CopyFail',
|
|
65
|
+
}
|
|
66
|
+
|
|
32
67
|
// schema query cache: identical information_schema/catalog queries from multiple
|
|
33
68
|
// zero-cache clients are deduplicated. first query executes, all others get cached result.
|
|
34
69
|
interface CachedQueryResult {
|
|
@@ -619,7 +654,7 @@ function messagePortToDuplex(port: MessagePort): {
|
|
|
619
654
|
start(controller) {
|
|
620
655
|
port.onmessage = (ev: MessageEvent) => {
|
|
621
656
|
msgCount++
|
|
622
|
-
if (msgCount <= 3) {
|
|
657
|
+
if (isDebugWire() && msgCount <= 3) {
|
|
623
658
|
console.debug(
|
|
624
659
|
`[pg-proxy-duplex] msg#${msgCount} type=${typeof ev.data} isAB=${ev.data instanceof ArrayBuffer} isU8=${ev.data instanceof Uint8Array} len=${ev.data?.byteLength ?? ev.data?.length ?? '?'}`
|
|
625
660
|
)
|
|
@@ -641,7 +676,7 @@ function messagePortToDuplex(port: MessagePort): {
|
|
|
641
676
|
const writable = new WritableStream<Uint8Array>({
|
|
642
677
|
write(chunk) {
|
|
643
678
|
_globalWriteCount++
|
|
644
|
-
if (_globalWriteCount <= 200) {
|
|
679
|
+
if (isDebugWire() && _globalWriteCount <= 200) {
|
|
645
680
|
console.debug(`[pg-proxy-ws-write] #${_globalWriteCount} len=${chunk.byteLength}`)
|
|
646
681
|
}
|
|
647
682
|
// transfer the ArrayBuffer for zero-copy
|
|
@@ -779,7 +814,8 @@ export async function createBrowserProxy(
|
|
|
779
814
|
const params = parseStartupParams(data)
|
|
780
815
|
const dbName = params.database || 'postgres'
|
|
781
816
|
const isRepl = params.replication === 'database'
|
|
782
|
-
|
|
817
|
+
if (isDebugWire())
|
|
818
|
+
console.debug(`[pg-proxy] connection: db=${dbName} repl=${isRepl}`)
|
|
783
819
|
// all connections handled with raw MessagePort (no pg-gateway).
|
|
784
820
|
// pg-gateway uses for-await on ReadableStream which is broken
|
|
785
821
|
// in browser Web Workers (same root cause as patches #9, #18, #20).
|
|
@@ -847,9 +883,11 @@ export async function createBrowserProxy(
|
|
|
847
883
|
port.onmessage = (ev: MessageEvent) => {
|
|
848
884
|
const data2 =
|
|
849
885
|
ev.data instanceof ArrayBuffer ? new Uint8Array(ev.data) : (ev.data as Uint8Array)
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
886
|
+
if (isDebugWire()) {
|
|
887
|
+
console.debug(
|
|
888
|
+
`[pg-proxy-raw-auth] ${dbName} repl=${isReplicationConnection} got msg type=0x${data2?.[0]?.toString(16)} len=${data2?.length}`
|
|
889
|
+
)
|
|
890
|
+
}
|
|
853
891
|
if (!data2 || data2[0] !== 0x70) {
|
|
854
892
|
console.warn(
|
|
855
893
|
'[pg-proxy-raw-auth] expected password, got type=0x' + data2?.[0]?.toString(16)
|
|
@@ -895,7 +933,8 @@ export async function createBrowserProxy(
|
|
|
895
933
|
}
|
|
896
934
|
write(combined)
|
|
897
935
|
|
|
898
|
-
|
|
936
|
+
if (isDebugWire())
|
|
937
|
+
console.debug('[pg-proxy-repl-raw] auth complete, ready for queries')
|
|
899
938
|
|
|
900
939
|
// step 3: handle subsequent messages (queries, replication commands)
|
|
901
940
|
installQueryHandler()
|
|
@@ -962,25 +1001,10 @@ export async function createBrowserProxy(
|
|
|
962
1001
|
async function processMessage(data: Uint8Array) {
|
|
963
1002
|
_pmCount++
|
|
964
1003
|
const msgType = data[0]
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
0x42: 'Bind',
|
|
969
|
-
0x44: 'Describe',
|
|
970
|
-
0x45: 'Execute',
|
|
971
|
-
0x43: 'Close',
|
|
972
|
-
0x48: 'Flush',
|
|
973
|
-
0x53: 'Sync',
|
|
974
|
-
0x51: 'Query',
|
|
975
|
-
0x58: 'Terminate',
|
|
976
|
-
0x70: 'Password',
|
|
977
|
-
0x46: 'FunctionCall',
|
|
978
|
-
0x64: 'CopyData',
|
|
979
|
-
0x63: 'CopyDone',
|
|
980
|
-
0x66: 'CopyFail',
|
|
1004
|
+
if (isDebugWire()) {
|
|
1005
|
+
const name = PG_MSG_TYPE_NAMES[msgType] || `unknown(0x${msgType.toString(16)})`
|
|
1006
|
+
console.debug(`[pg-proxy-pm] #${_pmCount} ${dbName} ${name} len=${data.length}`)
|
|
981
1007
|
}
|
|
982
|
-
const name = typeNames[msgType] || `unknown(0x${msgType.toString(16)})`
|
|
983
|
-
console.debug(`[pg-proxy-pm] #${_pmCount} ${dbName} ${name} len=${data.length}`)
|
|
984
1008
|
|
|
985
1009
|
// replication connection: handle replication commands
|
|
986
1010
|
if (isReplicationConnection && msgType === 0x51) {
|
|
@@ -1049,11 +1073,13 @@ export async function createBrowserProxy(
|
|
|
1049
1073
|
}
|
|
1050
1074
|
|
|
1051
1075
|
// regular query handling (SimpleQuery or extended protocol)
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1076
|
+
if (isDebugWire()) {
|
|
1077
|
+
if (msgType === 0x50) {
|
|
1078
|
+
const q = extractParseQuery(data)
|
|
1079
|
+
if (q) console.debug(`[pg-proxy-raw] ${dbName}: Parse ${q.slice(0, 80)}`)
|
|
1080
|
+
} else if (msgType === 0x51) {
|
|
1081
|
+
console.debug(`[pg-proxy-raw] ${dbName}: SimpleQuery len=${data.length}`)
|
|
1082
|
+
}
|
|
1057
1083
|
}
|
|
1058
1084
|
|
|
1059
1085
|
// extended protocol pipeline: Parse(0x50), Bind(0x42), Describe(0x44),
|
|
@@ -1137,7 +1163,7 @@ export async function createBrowserProxy(
|
|
|
1137
1163
|
return
|
|
1138
1164
|
}
|
|
1139
1165
|
const dt = performance.now() - t0
|
|
1140
|
-
if (dt > 100)
|
|
1166
|
+
if (isDebugWire() && dt > 100)
|
|
1141
1167
|
console.debug(`[pg-proxy-raw] slow query on ${dbName}: ${dt.toFixed(0)}ms`)
|
|
1142
1168
|
|
|
1143
1169
|
// update transaction state
|
|
@@ -1308,7 +1334,7 @@ export async function createBrowserProxy(
|
|
|
1308
1334
|
// but tools like pg_restore also need encoding, datestyle, etc.
|
|
1309
1335
|
// write directly to the port since pg-gateway owns the writable stream
|
|
1310
1336
|
onAuthenticated() {
|
|
1311
|
-
console.debug(`[pg-proxy-conn] authenticated db=${dbName}`)
|
|
1337
|
+
if (isDebugWire()) console.debug(`[pg-proxy-conn] authenticated db=${dbName}`)
|
|
1312
1338
|
for (const [name, value] of SERVER_PARAMS) {
|
|
1313
1339
|
rawWrite(buildParameterStatus(name, value))
|
|
1314
1340
|
}
|
|
@@ -1320,23 +1346,29 @@ export async function createBrowserProxy(
|
|
|
1320
1346
|
isReplicationConnection = true
|
|
1321
1347
|
}
|
|
1322
1348
|
dbName = params?.database || 'postgres'
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1349
|
+
if (isDebugWire()) {
|
|
1350
|
+
console.debug(
|
|
1351
|
+
`[pg-proxy-conn] startup: db=${dbName} user=${params?.user} repl=${params?.replication || 'none'}`
|
|
1352
|
+
)
|
|
1353
|
+
}
|
|
1326
1354
|
const { db } = getDbContext(dbName)
|
|
1327
1355
|
await db.waitReady
|
|
1328
1356
|
},
|
|
1329
1357
|
|
|
1330
1358
|
async onMessage(data, state) {
|
|
1331
1359
|
if (!state.isAuthenticated) {
|
|
1360
|
+
if (isDebugWire()) {
|
|
1361
|
+
console.debug(
|
|
1362
|
+
`[pg-proxy-conn] msg before auth, type=0x${data[0].toString(16)}`
|
|
1363
|
+
)
|
|
1364
|
+
}
|
|
1365
|
+
return
|
|
1366
|
+
}
|
|
1367
|
+
if (isDebugWire()) {
|
|
1332
1368
|
console.debug(
|
|
1333
|
-
`[pg-proxy-conn] msg
|
|
1369
|
+
`[pg-proxy-conn] msg db=${dbName} type=0x${data[0].toString(16)} len=${data.length}`
|
|
1334
1370
|
)
|
|
1335
|
-
return
|
|
1336
1371
|
}
|
|
1337
|
-
console.debug(
|
|
1338
|
-
`[pg-proxy-conn] msg db=${dbName} type=0x${data[0].toString(16)} len=${data.length}`
|
|
1339
|
-
)
|
|
1340
1372
|
|
|
1341
1373
|
// handle replication connections (always go to postgres instance)
|
|
1342
1374
|
if (isReplicationConnection) {
|
|
@@ -1605,17 +1637,25 @@ async function handleReplicationMessageBrowser(
|
|
|
1605
1637
|
mutex: Mutex,
|
|
1606
1638
|
connection: PostgresConnection
|
|
1607
1639
|
): Promise<Uint8Array | undefined> {
|
|
1608
|
-
|
|
1640
|
+
if (isDebugWire()) {
|
|
1641
|
+
console.debug(
|
|
1642
|
+
`[pg-proxy-repl] ENTRY type=0x${data[0].toString(16)} len=${data.length}`
|
|
1643
|
+
)
|
|
1644
|
+
}
|
|
1609
1645
|
|
|
1610
1646
|
// for non-SimpleQuery messages (extended protocol), execute against PGlite directly.
|
|
1611
1647
|
if (data[0] !== 0x51) {
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1648
|
+
if (isDebugWire()) {
|
|
1649
|
+
console.debug(
|
|
1650
|
+
`[pg-proxy-repl] ext protocol msg type=0x${data[0].toString(16)} len=${data.length}`
|
|
1651
|
+
)
|
|
1652
|
+
}
|
|
1615
1653
|
await mutex.acquire()
|
|
1616
1654
|
try {
|
|
1617
1655
|
const result = await db.execProtocolRaw(data, { syncToFs: false })
|
|
1618
|
-
|
|
1656
|
+
if (isDebugWire()) {
|
|
1657
|
+
console.debug(`[pg-proxy-repl] ext protocol result len=${result.length}`)
|
|
1658
|
+
}
|
|
1619
1659
|
return result
|
|
1620
1660
|
} finally {
|
|
1621
1661
|
mutex.release()
|
|
@@ -1667,17 +1707,23 @@ async function handleReplicationMessageBrowser(
|
|
|
1667
1707
|
}
|
|
1668
1708
|
|
|
1669
1709
|
// handle replication queries + fallthrough to pglite, all under mutex
|
|
1670
|
-
|
|
1671
|
-
|
|
1710
|
+
if (isDebugWire()) {
|
|
1711
|
+
console.debug(`[pg-proxy-repl] query: ${query.slice(0, 100)}`)
|
|
1712
|
+
console.debug(`[pg-proxy-repl] acquiring mutex...`)
|
|
1713
|
+
}
|
|
1672
1714
|
await mutex.acquire()
|
|
1673
|
-
console.debug(`[pg-proxy-repl] mutex acquired, testing db access...`)
|
|
1715
|
+
if (isDebugWire()) console.debug(`[pg-proxy-repl] mutex acquired, testing db access...`)
|
|
1674
1716
|
try {
|
|
1675
1717
|
const testResult = await db.query('SELECT 1 as test')
|
|
1676
|
-
|
|
1718
|
+
if (isDebugWire()) {
|
|
1719
|
+
console.debug(`[pg-proxy-repl] db.query works: ${JSON.stringify(testResult.rows)}`)
|
|
1720
|
+
}
|
|
1677
1721
|
const response = await handleReplicationQuery(query, db)
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1722
|
+
if (isDebugWire()) {
|
|
1723
|
+
console.debug(
|
|
1724
|
+
`[pg-proxy-repl] handleReplicationQuery result: ${response ? 'bytes(' + response.length + ')' : 'null'}`
|
|
1725
|
+
)
|
|
1726
|
+
}
|
|
1681
1727
|
if (response) return response
|
|
1682
1728
|
|
|
1683
1729
|
// apply query rewrites before forwarding
|
package/src/vite-plugin.ts
CHANGED
|
@@ -100,8 +100,32 @@ export function messagePortToWs(port: MessagePort): WsCompatible {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// forward port messages → ws 'message' events
|
|
103
|
+
// filter out control messages from sync-ws-patch.js (__close, __open)
|
|
103
104
|
port.onmessage = (event: MessageEvent) => {
|
|
104
|
-
|
|
105
|
+
const data = event.data
|
|
106
|
+
// control messages from sync-ws-patch.js — handle as close/open events
|
|
107
|
+
if (
|
|
108
|
+
data &&
|
|
109
|
+
typeof data === 'object' &&
|
|
110
|
+
!ArrayBuffer.isView(data) &&
|
|
111
|
+
!(data instanceof ArrayBuffer)
|
|
112
|
+
) {
|
|
113
|
+
if (data.__close) {
|
|
114
|
+
closed = true
|
|
115
|
+
port.close()
|
|
116
|
+
emit('close', {
|
|
117
|
+
code: data.code ?? 1000,
|
|
118
|
+
reason: data.reason ?? '',
|
|
119
|
+
wasClean: true,
|
|
120
|
+
})
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
if (data.__open) {
|
|
124
|
+
// already open, ignore
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
emit('message', { data })
|
|
105
129
|
}
|
|
106
130
|
|
|
107
131
|
port.onmessageerror = (event: MessageEvent) => {
|