orez 0.0.45 → 0.0.47
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/README.md +8 -12
- package/dist/admin/http-proxy.d.ts +31 -0
- package/dist/admin/http-proxy.d.ts.map +1 -0
- package/dist/admin/http-proxy.js +140 -0
- package/dist/admin/http-proxy.js.map +1 -0
- package/dist/admin/log-store.d.ts +22 -0
- package/dist/admin/log-store.d.ts.map +1 -0
- package/dist/admin/log-store.js +86 -0
- package/dist/admin/log-store.js.map +1 -0
- package/dist/admin/server.d.ts +19 -0
- package/dist/admin/server.d.ts.map +1 -0
- package/dist/admin/server.js +110 -0
- package/dist/admin/server.js.map +1 -0
- package/dist/admin/ui.d.ts +2 -0
- package/dist/admin/ui.d.ts.map +1 -0
- package/dist/admin/ui.js +683 -0
- package/dist/admin/ui.js.map +1 -0
- package/dist/cli.js +48 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +191 -33
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +9 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +24 -1
- package/dist/log.js.map +1 -1
- package/dist/pg-proxy.d.ts.map +1 -1
- package/dist/pg-proxy.js +19 -4
- package/dist/pg-proxy.js.map +1 -1
- package/dist/pglite-manager.d.ts +1 -0
- package/dist/pglite-manager.d.ts.map +1 -1
- package/dist/pglite-manager.js +1 -1
- package/dist/pglite-manager.js.map +1 -1
- package/dist/replication/handler.d.ts.map +1 -1
- package/dist/replication/handler.js +20 -2
- package/dist/replication/handler.js.map +1 -1
- package/dist/vite-plugin.d.ts +3 -0
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +24 -0
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +4 -2
- package/src/admin/http-proxy.ts +186 -0
- package/src/admin/log-store.ts +111 -0
- package/src/admin/server.ts +148 -0
- package/src/admin/ui.ts +682 -0
- package/src/cli.ts +49 -1
- package/src/config.ts +8 -0
- package/src/index.ts +207 -32
- package/src/log.ts +25 -1
- package/src/pg-proxy.ts +26 -6
- package/src/pglite-manager.ts +1 -1
- package/src/replication/handler.ts +21 -2
- package/src/shim/hooks.mjs +11 -8
- package/src/shim/register.mjs +2 -2
- package/src/vite-plugin.ts +28 -0
package/README.md
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
# orez
|
|
2
2
|
|
|
3
|
-
[Zero](https://zero.rocicorp.dev)
|
|
3
|
+
[Zero](https://zero.rocicorp.dev) is amazing, but setting it up alongside Postgres requires effort, native dependencies, and oftentimes Docker.
|
|
4
|
+
|
|
5
|
+
orez makes [PGlite](https://pglite.dev) work with Zero with a few things - a proxy that adds logical replication to PGLite, and then a bunch of iterations figuring out setup and setting that make them both happy together. To remove all native dependences, orez also ships a custom WASM fork of the same SQLite [bedrock branch](https://sqlite.org/src/timeline?t=begin-concurrent) that Zero uses. Inlcudes a CLI, programmatic API, and Vite plugin.
|
|
4
6
|
|
|
5
7
|
```
|
|
6
8
|
bunx orez
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Auto-configures Node heap size based on system memory, adaptively polls for replication changes (~500x faster catch-up after large restores), purges consumed WAL changes to prevent WASM OOM, and auto-tracks tables created at runtime via DDL event triggers.
|
|
12
|
-
|
|
13
|
-
<p align="center">
|
|
14
|
-
<img src="logo.svg" alt="orez is hebrew for rice — zero, pglite, and sqlite-wasm hanging out" width="320" />
|
|
15
|
-
</p>
|
|
11
|
+
orez auto-configures Node heap size based on system memory, adaptively polls for replication changes (~500x faster catch-up after large restores), purges consumed WAL changes to prevent WASM OOM, and auto-tracks tables created at runtime via DDL event triggers. Includes `pg_dump` and `pg_restore` subcommands that can restore production Postgres dumps directly into PGlite — handling COPY→INSERT conversion, unsupported extension filtering, idempotent DDL rewriting, and WASM memory management automatically. It uses [pgsql-parser](https://www.npmjs.com/package/pgsql-parser) (the real PostgreSQL C parser, compiled to WASM) for SQL analysis. Comes with PGlite extensions `pgvector` and `pg_trgm` enabled by default.
|
|
16
12
|
|
|
17
13
|
## CLI
|
|
18
14
|
|
|
@@ -208,9 +204,9 @@ The mutex uses `setImmediate`/`setTimeout` between releases instead of resolving
|
|
|
208
204
|
|
|
209
205
|
When `execProtocolRaw` throws (PGlite internal error), the proxy sends a proper ErrorResponse + ReadyForQuery over the wire instead of destroying the socket. The client sees an error message and continues working.
|
|
210
206
|
|
|
211
|
-
### SQLite shim via
|
|
207
|
+
### SQLite shim via ESM loader hooks
|
|
212
208
|
|
|
213
|
-
zero-cache imports `@rocicorp/zero-sqlite3` (a native C addon)
|
|
209
|
+
zero-cache imports `@rocicorp/zero-sqlite3` (a native C addon) via ESM `import`. orez uses Node's `module.register()` API with `--import` to intercept resolution — ESM `resolve` and `load` hooks redirect `@rocicorp/zero-sqlite3` to bedrock-sqlite WASM at runtime. The hook templates live in `src/shim/` and are written to tmpdir with the resolved bedrock-sqlite path substituted.
|
|
214
210
|
|
|
215
211
|
The shim also polyfills the better-sqlite3 API surface zero-cache expects: `unsafeMode()`, `defaultSafeIntegers()`, `serialize()`, `backup()`, and `scanStatus`/`scanStatusV2`/`scanStatusReset` on Statement prototypes (zero-cache's query planner calls these for scan statistics, which WASM doesn't support).
|
|
216
212
|
|
|
@@ -234,9 +230,9 @@ Columns with types zero-cache can't handle (`tsvector`, `tsquery`, `USER-DEFINED
|
|
|
234
230
|
|
|
235
231
|
If `ZERO_APP_PUBLICATIONS` is set, only tables in that publication get change-tracking triggers. This prevents streaming changes for private tables (user sessions, accounts) that zero-cache doesn't know about. Stale triggers from previous installs (before the publication existed) are cleaned up automatically.
|
|
236
232
|
|
|
237
|
-
### Stale
|
|
233
|
+
### Stale lock file cleanup on startup
|
|
238
234
|
|
|
239
|
-
|
|
235
|
+
Only the SQLite replica's lock files (`-wal`, `-shm`, `-wal2`) are deleted on startup — not the replica itself. The replica is a cache of PGlite data; keeping it lets zero-cache catch up via replication (nearly instant) instead of doing a full initial sync (COPY of all tables). If the replica is too stale, `ZERO_AUTO_RESET=true` makes zero-cache wipe and resync automatically. Lock files from a previous crash are cleaned to prevent startup failures.
|
|
240
236
|
|
|
241
237
|
### Data directory migration
|
|
242
238
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Server } from 'node:http';
|
|
2
|
+
export interface HttpLogEntry {
|
|
3
|
+
id: number;
|
|
4
|
+
ts: number;
|
|
5
|
+
method: string;
|
|
6
|
+
path: string;
|
|
7
|
+
status: number;
|
|
8
|
+
duration: number;
|
|
9
|
+
reqSize: number;
|
|
10
|
+
resSize: number;
|
|
11
|
+
reqHeaders: Record<string, string>;
|
|
12
|
+
resHeaders: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export interface HttpLogStore {
|
|
15
|
+
push(entry: Omit<HttpLogEntry, 'id'>): void;
|
|
16
|
+
query(opts?: {
|
|
17
|
+
since?: number;
|
|
18
|
+
path?: string;
|
|
19
|
+
}): {
|
|
20
|
+
entries: HttpLogEntry[];
|
|
21
|
+
cursor: number;
|
|
22
|
+
};
|
|
23
|
+
clear(): void;
|
|
24
|
+
}
|
|
25
|
+
export declare function createHttpLogStore(): HttpLogStore;
|
|
26
|
+
export declare function startHttpProxy(opts: {
|
|
27
|
+
listenPort: number;
|
|
28
|
+
targetPort: number;
|
|
29
|
+
httpLog: HttpLogStore;
|
|
30
|
+
}): Promise<Server>;
|
|
31
|
+
//# sourceMappingURL=http-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-proxy.d.ts","sourceRoot":"","sources":["../../src/admin/http-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,MAAM,EAGZ,MAAM,WAAW,CAAA;AAGlB,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,IAAI,CAAA;IAC3C,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,YAAY,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5F,KAAK,IAAI,IAAI,CAAA;CACd;AAID,wBAAgB,kBAAkB,IAAI,YAAY,CAsCjD;AAUD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,YAAY,CAAA;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuGlB"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createServer, request as httpRequest, } from 'node:http';
|
|
2
|
+
const MAX_ENTRIES = 10_000;
|
|
3
|
+
export function createHttpLogStore() {
|
|
4
|
+
const entries = [];
|
|
5
|
+
let nextId = 1;
|
|
6
|
+
function push(entry) {
|
|
7
|
+
const full = { ...entry, id: nextId++ };
|
|
8
|
+
entries.push(full);
|
|
9
|
+
if (entries.length > MAX_ENTRIES)
|
|
10
|
+
entries.splice(0, entries.length - MAX_ENTRIES);
|
|
11
|
+
}
|
|
12
|
+
function query(opts) {
|
|
13
|
+
let result = entries;
|
|
14
|
+
if (opts?.since) {
|
|
15
|
+
const since = opts.since;
|
|
16
|
+
let lo = 0;
|
|
17
|
+
let hi = result.length;
|
|
18
|
+
while (lo < hi) {
|
|
19
|
+
const mid = (lo + hi) >>> 1;
|
|
20
|
+
if (result[mid].id <= since)
|
|
21
|
+
lo = mid + 1;
|
|
22
|
+
else
|
|
23
|
+
hi = mid;
|
|
24
|
+
}
|
|
25
|
+
result = result.slice(lo);
|
|
26
|
+
}
|
|
27
|
+
if (opts?.path) {
|
|
28
|
+
const p = opts.path;
|
|
29
|
+
result = result.filter((e) => e.path.includes(p));
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
entries: result,
|
|
33
|
+
cursor: entries.length > 0 ? entries[entries.length - 1].id : 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function clear() {
|
|
37
|
+
entries.length = 0;
|
|
38
|
+
}
|
|
39
|
+
return { push, query, clear };
|
|
40
|
+
}
|
|
41
|
+
function flatHeaders(headers) {
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
44
|
+
out[k] = Array.isArray(v) ? v.join(', ') : String(v ?? '');
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
export function startHttpProxy(opts) {
|
|
49
|
+
const { listenPort, targetPort, httpLog } = opts;
|
|
50
|
+
const server = createServer((req, res) => {
|
|
51
|
+
const start = Date.now();
|
|
52
|
+
let reqSize = 0;
|
|
53
|
+
const reqChunks = [];
|
|
54
|
+
req.on('data', (chunk) => {
|
|
55
|
+
reqSize += chunk.length;
|
|
56
|
+
reqChunks.push(chunk);
|
|
57
|
+
});
|
|
58
|
+
req.on('end', () => {
|
|
59
|
+
const proxyReq = httpRequest({
|
|
60
|
+
hostname: '127.0.0.1',
|
|
61
|
+
port: targetPort,
|
|
62
|
+
path: req.url,
|
|
63
|
+
method: req.method,
|
|
64
|
+
headers: req.headers,
|
|
65
|
+
}, (proxyRes) => {
|
|
66
|
+
let resSize = 0;
|
|
67
|
+
proxyRes.on('data', (chunk) => {
|
|
68
|
+
resSize += chunk.length;
|
|
69
|
+
});
|
|
70
|
+
proxyRes.on('end', () => {
|
|
71
|
+
httpLog.push({
|
|
72
|
+
ts: start,
|
|
73
|
+
method: req.method || 'GET',
|
|
74
|
+
path: req.url || '/',
|
|
75
|
+
status: proxyRes.statusCode || 0,
|
|
76
|
+
duration: Date.now() - start,
|
|
77
|
+
reqSize,
|
|
78
|
+
resSize,
|
|
79
|
+
reqHeaders: flatHeaders(req.headers),
|
|
80
|
+
resHeaders: flatHeaders(proxyRes.headers),
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
|
|
84
|
+
proxyRes.pipe(res);
|
|
85
|
+
});
|
|
86
|
+
proxyReq.on('error', (err) => {
|
|
87
|
+
res.writeHead(502);
|
|
88
|
+
res.end('proxy error: ' + err.message);
|
|
89
|
+
});
|
|
90
|
+
for (const chunk of reqChunks)
|
|
91
|
+
proxyReq.write(chunk);
|
|
92
|
+
proxyReq.end();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
// websocket upgrade passthrough
|
|
96
|
+
server.on('upgrade', (req, socket, head) => {
|
|
97
|
+
const start = Date.now();
|
|
98
|
+
const proxyReq = httpRequest({
|
|
99
|
+
hostname: '127.0.0.1',
|
|
100
|
+
port: targetPort,
|
|
101
|
+
path: req.url,
|
|
102
|
+
method: req.method,
|
|
103
|
+
headers: req.headers,
|
|
104
|
+
});
|
|
105
|
+
proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
|
|
106
|
+
httpLog.push({
|
|
107
|
+
ts: start,
|
|
108
|
+
method: 'WS',
|
|
109
|
+
path: req.url || '/',
|
|
110
|
+
status: 101,
|
|
111
|
+
duration: Date.now() - start,
|
|
112
|
+
reqSize: 0,
|
|
113
|
+
resSize: 0,
|
|
114
|
+
reqHeaders: flatHeaders(req.headers),
|
|
115
|
+
resHeaders: flatHeaders(proxyRes.headers),
|
|
116
|
+
});
|
|
117
|
+
// forward the 101 response
|
|
118
|
+
let rawHeaders = 'HTTP/1.1 101 Switching Protocols\r\n';
|
|
119
|
+
for (const [k, v] of Object.entries(proxyRes.headers)) {
|
|
120
|
+
rawHeaders += `${k}: ${Array.isArray(v) ? v.join(', ') : v}\r\n`;
|
|
121
|
+
}
|
|
122
|
+
rawHeaders += '\r\n';
|
|
123
|
+
socket.write(rawHeaders);
|
|
124
|
+
if (proxyHead.length)
|
|
125
|
+
socket.write(proxyHead);
|
|
126
|
+
proxySocket.pipe(socket);
|
|
127
|
+
socket.pipe(proxySocket);
|
|
128
|
+
proxySocket.on('error', () => socket.destroy());
|
|
129
|
+
socket.on('error', () => proxySocket.destroy());
|
|
130
|
+
});
|
|
131
|
+
proxyReq.on('error', () => socket.destroy());
|
|
132
|
+
proxyReq.write(head);
|
|
133
|
+
proxyReq.end();
|
|
134
|
+
});
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
server.listen(listenPort, '127.0.0.1', () => resolve(server));
|
|
137
|
+
server.on('error', reject);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=http-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-proxy.js","sourceRoot":"","sources":["../../src/admin/http-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface LogEntry {
|
|
2
|
+
id: number;
|
|
3
|
+
ts: number;
|
|
4
|
+
source: string;
|
|
5
|
+
level: string;
|
|
6
|
+
msg: string;
|
|
7
|
+
}
|
|
8
|
+
export interface LogStore {
|
|
9
|
+
push(source: string, level: string, msg: string): void;
|
|
10
|
+
query(opts?: {
|
|
11
|
+
source?: string;
|
|
12
|
+
level?: string;
|
|
13
|
+
since?: number;
|
|
14
|
+
}): {
|
|
15
|
+
entries: LogEntry[];
|
|
16
|
+
cursor: number;
|
|
17
|
+
};
|
|
18
|
+
getAll(): LogEntry[];
|
|
19
|
+
clear(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare function createLogStore(dataDir: string, writeToDisk?: boolean): LogStore;
|
|
22
|
+
//# sourceMappingURL=log-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-store.d.ts","sourceRoot":"","sources":["../../src/admin/log-store.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACtD,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QACjE,OAAO,EAAE,QAAQ,EAAE,CAAA;QACnB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,MAAM,IAAI,QAAQ,EAAE,CAAA;IACpB,KAAK,IAAI,IAAI,CAAA;CACd;AAOD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,UAAO,GAAG,QAAQ,CAoF5E"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, appendFileSync, statSync, renameSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
4
|
+
const MAX_ENTRIES = 50_000;
|
|
5
|
+
const MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
6
|
+
const LEVEL_PRIORITY = { error: 0, warn: 1, info: 2, debug: 3 };
|
|
7
|
+
export function createLogStore(dataDir, writeToDisk = true) {
|
|
8
|
+
const entries = [];
|
|
9
|
+
let nextId = 1;
|
|
10
|
+
const logsDir = join(dataDir, 'logs');
|
|
11
|
+
const logFile = join(logsDir, 'orez.log');
|
|
12
|
+
const backupFile = join(logsDir, 'orez.log.1');
|
|
13
|
+
if (writeToDisk) {
|
|
14
|
+
mkdirSync(logsDir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
function rotateIfNeeded() {
|
|
17
|
+
if (!writeToDisk)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
if (!existsSync(logFile))
|
|
21
|
+
return;
|
|
22
|
+
const stat = statSync(logFile);
|
|
23
|
+
if (stat.size > MAX_FILE_SIZE) {
|
|
24
|
+
renameSync(logFile, backupFile);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch { }
|
|
28
|
+
}
|
|
29
|
+
function push(source, level, msg) {
|
|
30
|
+
const entry = {
|
|
31
|
+
id: nextId++,
|
|
32
|
+
ts: Date.now(),
|
|
33
|
+
source,
|
|
34
|
+
level,
|
|
35
|
+
msg: msg.replace(ANSI_RE, ''),
|
|
36
|
+
};
|
|
37
|
+
entries.push(entry);
|
|
38
|
+
if (entries.length > MAX_ENTRIES) {
|
|
39
|
+
entries.splice(0, entries.length - MAX_ENTRIES);
|
|
40
|
+
}
|
|
41
|
+
if (writeToDisk) {
|
|
42
|
+
try {
|
|
43
|
+
const ts = new Date(entry.ts).toISOString();
|
|
44
|
+
appendFileSync(logFile, '[' + ts + '] [' + source + '] [' + level + '] ' + entry.msg + '\n');
|
|
45
|
+
rotateIfNeeded();
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function query(opts) {
|
|
51
|
+
let result = entries;
|
|
52
|
+
if (opts?.since) {
|
|
53
|
+
const since = opts.since;
|
|
54
|
+
let lo = 0;
|
|
55
|
+
let hi = result.length;
|
|
56
|
+
while (lo < hi) {
|
|
57
|
+
const mid = (lo + hi) >>> 1;
|
|
58
|
+
if (result[mid].id <= since)
|
|
59
|
+
lo = mid + 1;
|
|
60
|
+
else
|
|
61
|
+
hi = mid;
|
|
62
|
+
}
|
|
63
|
+
result = result.slice(lo);
|
|
64
|
+
}
|
|
65
|
+
if (opts?.source) {
|
|
66
|
+
const source = opts.source;
|
|
67
|
+
result = result.filter((e) => e.source === source);
|
|
68
|
+
}
|
|
69
|
+
if (opts?.level) {
|
|
70
|
+
const maxPriority = LEVEL_PRIORITY[opts.level] ?? 3;
|
|
71
|
+
result = result.filter((e) => (LEVEL_PRIORITY[e.level] ?? 3) <= maxPriority);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
entries: result,
|
|
75
|
+
cursor: entries.length > 0 ? entries[entries.length - 1].id : 0,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function getAll() {
|
|
79
|
+
return [...entries];
|
|
80
|
+
}
|
|
81
|
+
function clear() {
|
|
82
|
+
entries.length = 0;
|
|
83
|
+
}
|
|
84
|
+
return { push, query, getAll, clear };
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=log-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-store.js","sourceRoot":"","sources":["../../src/admin/log-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Server } from 'node:http';
|
|
2
|
+
import type { LogStore } from './log-store.js';
|
|
3
|
+
import type { HttpLogStore } from './http-proxy.js';
|
|
4
|
+
import type { ZeroLiteConfig } from '../config.js';
|
|
5
|
+
export interface AdminActions {
|
|
6
|
+
restartZero?: () => Promise<void>;
|
|
7
|
+
resetZero?: () => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export interface AdminServerOpts {
|
|
10
|
+
port: number;
|
|
11
|
+
logStore: LogStore;
|
|
12
|
+
config: ZeroLiteConfig;
|
|
13
|
+
zeroEnv: Record<string, string>;
|
|
14
|
+
actions?: AdminActions;
|
|
15
|
+
startTime: number;
|
|
16
|
+
httpLog?: HttpLogStore;
|
|
17
|
+
}
|
|
18
|
+
export declare function startAdminServer(opts: AdminServerOpts): Promise<Server>;
|
|
19
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/admin/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAGZ,MAAM,WAAW,CAAA;AAGlB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,EAAE,cAAc,CAAA;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAgBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA0GvE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createServer, } from 'node:http';
|
|
2
|
+
import { log } from '../log.js';
|
|
3
|
+
import { getAdminHtml } from './ui.js';
|
|
4
|
+
function corsHeaders() {
|
|
5
|
+
return {
|
|
6
|
+
'Access-Control-Allow-Origin': '*',
|
|
7
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
8
|
+
'Access-Control-Allow-Headers': '*',
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function json(res, data, status = 200) {
|
|
12
|
+
const headers = { ...corsHeaders(), 'Content-Type': 'application/json' };
|
|
13
|
+
res.writeHead(status, headers);
|
|
14
|
+
res.end(JSON.stringify(data));
|
|
15
|
+
}
|
|
16
|
+
export function startAdminServer(opts) {
|
|
17
|
+
const { logStore, config, zeroEnv, actions, startTime } = opts;
|
|
18
|
+
const html = getAdminHtml();
|
|
19
|
+
const server = createServer(async (req, res) => {
|
|
20
|
+
const headers = corsHeaders();
|
|
21
|
+
if (req.method === 'OPTIONS') {
|
|
22
|
+
res.writeHead(200, headers);
|
|
23
|
+
res.end();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const url = new URL(req.url || '/', 'http://localhost:' + opts.port);
|
|
27
|
+
try {
|
|
28
|
+
if (req.method === 'GET' && url.pathname === '/') {
|
|
29
|
+
res.writeHead(200, { ...headers, 'Content-Type': 'text/html' });
|
|
30
|
+
res.end(html);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (req.method === 'GET' && url.pathname === '/api/logs') {
|
|
34
|
+
const source = url.searchParams.get('source') || undefined;
|
|
35
|
+
const level = url.searchParams.get('level') || undefined;
|
|
36
|
+
const sinceStr = url.searchParams.get('since');
|
|
37
|
+
const since = sinceStr ? Number(sinceStr) : undefined;
|
|
38
|
+
json(res, logStore.query({ source, level, since }));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (req.method === 'GET' && url.pathname === '/api/env') {
|
|
42
|
+
const filtered = Object.entries(zeroEnv)
|
|
43
|
+
.filter(([k]) => k.startsWith('ZERO_') || k === 'NODE_ENV' || k === 'NODE_OPTIONS')
|
|
44
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
45
|
+
json(res, { env: Object.fromEntries(filtered) });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (req.method === 'GET' && url.pathname === '/api/status') {
|
|
49
|
+
json(res, {
|
|
50
|
+
pgPort: config.pgPort,
|
|
51
|
+
zeroPort: config.zeroPort,
|
|
52
|
+
adminPort: opts.port,
|
|
53
|
+
uptime: Math.floor((Date.now() - startTime) / 1000),
|
|
54
|
+
logLevel: config.logLevel,
|
|
55
|
+
skipZeroCache: config.skipZeroCache,
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (req.method === 'POST' && url.pathname === '/api/actions/restart-zero') {
|
|
60
|
+
if (!actions?.restartZero) {
|
|
61
|
+
json(res, { ok: false, message: 'zero-cache not running' }, 400);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
log.orez('admin: restarting zero-cache');
|
|
65
|
+
await actions.restartZero();
|
|
66
|
+
json(res, { ok: true, message: 'zero-cache restarted' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (req.method === 'POST' && url.pathname === '/api/actions/reset-zero') {
|
|
70
|
+
if (!actions?.resetZero) {
|
|
71
|
+
json(res, { ok: false, message: 'zero-cache not running' }, 400);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
log.orez('admin: resetting zero-cache');
|
|
75
|
+
await actions.resetZero();
|
|
76
|
+
json(res, { ok: true, message: 'zero-cache reset and restarted' });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (req.method === 'POST' && url.pathname === '/api/actions/clear-logs') {
|
|
80
|
+
logStore.clear();
|
|
81
|
+
json(res, { ok: true, message: 'logs cleared' });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (req.method === 'GET' && url.pathname === '/api/http-log') {
|
|
85
|
+
const sinceStr = url.searchParams.get('since');
|
|
86
|
+
const path = url.searchParams.get('path') || undefined;
|
|
87
|
+
const since = sinceStr ? Number(sinceStr) : undefined;
|
|
88
|
+
json(res, opts.httpLog?.query({ since, path }) || { entries: [], cursor: 0 });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (req.method === 'POST' && url.pathname === '/api/actions/clear-http') {
|
|
92
|
+
opts.httpLog?.clear();
|
|
93
|
+
json(res, { ok: true, message: 'http log cleared' });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
res.writeHead(404, headers);
|
|
97
|
+
res.end('not found');
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
json(res, { error: err?.message ?? 'internal error' }, 500);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
server.listen(opts.port, '127.0.0.1', () => {
|
|
105
|
+
resolve(server);
|
|
106
|
+
});
|
|
107
|
+
server.on('error', reject);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/admin/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/admin/ui.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,IAAI,MAAM,CAyqBrC"}
|