@singhak/nodeui-core 0.3.1 → 0.5.0

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 CHANGED
@@ -1,111 +1,113 @@
1
- # @singhak/nodeui-core
2
-
3
- Framework-neutral engine for the NodeUI developer console: observability
4
- providers, the REST contract, the safety gate, and the static console server.
5
- The Express, Fastify and NestJS adapters build on this package; you normally
6
- consume those instead of using `@singhak/nodeui-core` directly. Use core
7
- directly to integrate a framework without an adapter (Koa, Hono, plain `http`).
8
-
9
- ## Providers
10
-
11
- Each provider exposes one panel through `GET {path}/api/{id}`:
12
-
13
- | id | Panel | Notes |
14
- | --------------- | -------------- | ---------------------------------------------------------- |
15
- | `health` | Health | Event-loop + memory status, plus your `healthChecks`. |
16
- | `memory` | Memory | Samples process + OS memory on start. |
17
- | `cpu` | CPU | Process CPU percent from `process.cpuUsage()`. |
18
- | `event-loop` | Event-loop lag | Drift vs. a 1ms `setInterval`, last 600 samples. |
19
- | `heap-snapshot` | Heap snapshot | Writes `nodeui-heap-<pid>-<ts>.heapsnapshot` (owner-only). |
20
- | `startup` | Startup | Timing marks recorded via `server.mark(name)`. |
21
- | `requests` | Requests | Ring buffer of app HTTP requests (default 500). |
22
- | `metrics` | Metrics | Requests/errors per second for the last minute. |
23
- | `env` | Environment | `process.env` + your `config`, masked. |
24
- | `routes` | Routes | Express router introspection, or `server.setRoutes()`. |
25
- | `logs` | Logs | `console.*` capture plus `server.addLogSource()`. |
26
- | `outgoing` | Outgoing HTTP | `http`/`https`/`fetch` calls made by the app. |
27
- | _your id_ | _your title_ | Custom panels via the `plugins` option (see below). |
28
-
29
- ## API
30
-
31
- All endpoints live under `{path}/api` and return
32
- `{ ok: true, data } | { ok: false, error: { code, message } }`:
33
-
34
- - `GET /config` — effective configuration, panel list and plugin titles.
35
- - `GET /{panel-id}` — panel data for every id above.
36
- - `GET /live?panels=a,b` — Server-Sent Events stream (capped by `maxSseClients`).
37
- - `POST /confirmations` — issue a single-use nonce.
38
- - `POST /heap-snapshot` — capture a snapshot; must send
39
- `x-nodeui-confirm: <nonce>` from a fresh confirmation. A missing, expired, or
40
- replayed nonce returns `409` with error code `confirmation-required`.
41
-
42
- `GET /` serves the bundled React console with an SPA fallback to `index.html`.
43
-
44
- ## Safety
45
-
46
- - **Activation:** active when `NODE_ENV` is non-production, or when
47
- `NODEUI_ENABLED=true` forces it; fail-closed in production (a warning is logged if forced on).
48
- - **Loopback-only:** remote hosts are rejected with `403`. Extra clients can be allow-listed
49
- (`allowedRemoteAddresses`, exact IPs or IPv4 CIDRs, e.g. the Docker bridge).
50
- - **Host / Origin validation:** blocks DNS-rebinding and cross-site requests. Extra names via
51
- `allowedHosts` / `allowedOrigins`. `X-Forwarded-*` requests are rejected unless `trustProxy`.
52
- - **Access token (optional):** `authToken` / `NODEUI_TOKEN`; send `Authorization: Bearer <token>`,
53
- or open `{path}/?token=<token>` once to get an HttpOnly cookie.
54
- - **Secret masking:** values under keys such as `token`, `key`, `secret`, `password`, `auth`,
55
- `cookie`, `dsn`, `database_url` are replaced with `[REDACTED]`; credentials inside text
56
- (URLs, bearer tokens, JWTs, `password=...`) are scrubbed too, in REST and SSE. Disable with
57
- `maskSecrets: false`.
58
- - **Headers:** CSP, `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy` on every response.
59
- - **Read-only default:** the heap snapshot is the only mutating action and is
60
- gated behind a fresh nonce.
61
- - **Zero-cost when disabled:** the middleware is a pass-through; no timers or
62
- hooks are created.
63
-
64
- ## Configuration
65
-
66
- Environment variables are read at `createNodeUI()` time (overridable via the
67
- `options.env` map for tests); each also has a typed option of the same meaning.
68
-
69
- | Variable | Default | Description |
70
- | ------------------------------ | ------------------- | ---------------------------------------- |
71
- | `NODEUI_ENABLED` | unset | Force activation (`true`) / disable. |
72
- | `NODEUI_HOST` | `127.0.0.1` | Loopback host the console trusts. |
73
- | `NODEUI_PATH` | `/nodeui` | URL prefix for console + API. |
74
- | `NODEUI_REQUEST_LOG_SIZE` | `500` | Request ring-buffer capacity. |
75
- | `NODEUI_LOG_SIZE` | `500` | Log ring-buffer capacity. |
76
- | `NODEUI_POLL_INTERVAL_MS` | `2000` | Sampling interval. |
77
- | `NODEUI_INACTIVITY_TIMEOUT_MS` | `60000` | Provider idle timeout. |
78
- | `NODEUI_CONFIRM_TTL_MS` | `60000` | Nonce lifetime. |
79
- | `NODEUI_HEAP_SNAPSHOT_DIR` | `<tmp>/nodeui-heap` | Snapshot output directory. |
80
- | `NODEUI_TOKEN` | unset | Require an access token. |
81
- | `NODEUI_ALLOWED_HOSTS` | unset | Comma-separated extra `Host` names. |
82
- | `NODEUI_ALLOWED_ORIGINS` | unset | Comma-separated extra `Origin` values. |
83
- | `NODEUI_ALLOWED_REMOTE` | unset | Comma-separated client IPs / IPv4 CIDRs. |
84
- | `NODEUI_TRUST_PROXY` | `false` | Accept `X-Forwarded-*` requests. |
85
- | `NODEUI_MAX_SSE_CLIENTS` | `10` | Concurrent live streams. |
86
-
87
- ## Usage
88
-
89
- ```ts
90
- import { createNodeUI, type NodeUIServer } from '@singhak/nodeui-core';
91
-
92
- const server: NodeUIServer = createNodeUI({
93
- plugins: [{ id: 'queues', title: 'Queues', get: async () => ({ ok: true, data: await jobs() }) }],
94
- healthChecks: { db: () => pool.query('select 1') },
95
- });
96
- const middleware = server.middleware();
97
- // middleware is (req, res, next) => void; mount it before your routes.
98
- server.mark('listening');
99
- server.shutdown();
100
- ```
101
-
102
- Plugin ids are lowercase letters, digits and `-`, and must not collide with a built-in panel.
103
- Without an Express router, feed the routes panel with `server.setRoutes([...])`.
104
-
105
- ## Development
106
-
107
- ```bash
108
- npm run typecheck # tsc --noEmit
109
- npm test # vitest run (unit + e2e)
110
- npm run build # emit dist/
111
- ```
1
+ # @singhak/nodeui-core
2
+
3
+ Framework-neutral engine for the NodeUI developer console: observability
4
+ providers, the REST contract, the safety gate, and the static console server.
5
+ The Express, Fastify, NestJS, Koa, Hapi, Hono and `node:http` adapters build on
6
+ this package; you normally consume those instead of using `@singhak/nodeui-core`
7
+ directly. Use core directly to integrate a framework that has no adapter.
8
+
9
+ ## Providers
10
+
11
+ Each provider exposes one panel through `GET {path}/api/{id}`:
12
+
13
+ | id | Panel | Notes |
14
+ | --------------- | -------------- | ---------------------------------------------------------- |
15
+ | `health` | Health | Event-loop + memory status, plus your `healthChecks`. |
16
+ | `memory` | Memory | Samples process + OS memory on start. |
17
+ | `cpu` | CPU | Process CPU percent from `process.cpuUsage()`. |
18
+ | `event-loop` | Event-loop lag | Drift vs. a 1ms `setInterval`, last 600 samples. |
19
+ | `heap-snapshot` | Heap snapshot | Writes `nodeui-heap-<pid>-<ts>.heapsnapshot` (owner-only). |
20
+ | `startup` | Startup | Timing marks recorded via `server.mark(name)`. |
21
+ | `requests` | Requests | Ring buffer of app HTTP requests (default 500). |
22
+ | `metrics` | Metrics | Requests/errors per second for the last minute. |
23
+ | `env` | Environment | `process.env` + your `config`, masked. |
24
+ | `routes` | Routes | Express router introspection, or `server.setRoutes()`. |
25
+ | `logs` | Logs | `console.*` capture plus `server.addLogSource()`. |
26
+ | `outgoing` | Outgoing HTTP | `http`/`https`/`fetch` calls made by the app. |
27
+ | _your id_ | _your title_ | Custom panels via the `plugins` option (see below). |
28
+
29
+ ## API
30
+
31
+ All endpoints live under `{path}/api` and return
32
+ `{ ok: true, data } | { ok: false, error: { code, message } }`:
33
+
34
+ - `GET /config` — effective configuration, panel list and plugin titles.
35
+ - `GET /{panel-id}` — panel data for every id above.
36
+ - `GET /live?panels=a,b` — Server-Sent Events stream (capped by `maxSseClients`).
37
+ - `POST /confirmations` — issue a single-use nonce.
38
+ - `POST /heap-snapshot` — capture a snapshot; must send
39
+ `x-nodeui-confirm: <nonce>` from a fresh confirmation. A missing, expired, or
40
+ replayed nonce returns `409` with error code `confirmation-required`.
41
+
42
+ `GET /` serves the bundled React console with an SPA fallback to `index.html`.
43
+
44
+ ## Safety
45
+
46
+ - **Activation:** active when `NODE_ENV` is non-production, or when
47
+ `NODEUI_ENABLED=true` forces it; fail-closed in production (a warning is logged if forced on).
48
+ - **Loopback-only:** remote hosts are rejected with `403`. Extra clients can be allow-listed
49
+ (`allowedRemoteAddresses`, exact IPs or IPv4 CIDRs, e.g. the Docker bridge).
50
+ - **Host / Origin validation:** blocks DNS-rebinding and cross-site requests. Extra names via
51
+ `allowedHosts` / `allowedOrigins`. `X-Forwarded-*` requests are rejected unless `trustProxy`.
52
+ - **Access token (optional):** `authToken` / `NODEUI_TOKEN`; send `Authorization: Bearer <token>`,
53
+ or open `{path}/?token=<token>` once to get an HttpOnly cookie.
54
+ - **Secret masking:** values under keys such as `token`, `key`, `secret`, `password`, `auth`,
55
+ `cookie`, `dsn`, `database_url` are replaced with `[REDACTED]`; credentials inside text
56
+ (URLs, bearer tokens, JWTs, `password=...`) are scrubbed too, in REST and SSE. Disable with
57
+ `maskSecrets: false`.
58
+ - **Headers:** CSP, `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy` on every response.
59
+ - **Read-only default:** the heap snapshot is the only mutating action and is
60
+ gated behind a fresh nonce.
61
+ - **Zero-cost when disabled:** the middleware is a pass-through; no timers or
62
+ hooks are created.
63
+
64
+ ## Configuration
65
+
66
+ Environment variables are read at `createNodeUI()` time (overridable via the
67
+ `options.env` map for tests); each also has a typed option of the same meaning.
68
+
69
+ | Variable | Default | Description |
70
+ | ------------------------------ | ------------------- | ---------------------------------------- |
71
+ | `NODEUI_ENABLED` | unset | Force activation (`true`) / disable. |
72
+ | `NODEUI_HOST` | `127.0.0.1` | Loopback host the console trusts. |
73
+ | `NODEUI_PATH` | `/nodeui` | URL prefix for console + API. |
74
+ | `NODEUI_REQUEST_LOG_SIZE` | `500` | Request ring-buffer capacity. |
75
+ | `NODEUI_LOG_SIZE` | `500` | Log ring-buffer capacity. |
76
+ | `NODEUI_POLL_INTERVAL_MS` | `2000` | Sampling interval. |
77
+ | `NODEUI_INACTIVITY_TIMEOUT_MS` | `60000` | Provider idle timeout. |
78
+ | `NODEUI_CONFIRM_TTL_MS` | `60000` | Nonce lifetime. |
79
+ | `NODEUI_HEAP_SNAPSHOT_DIR` | `<tmp>/nodeui-heap` | Snapshot output directory. |
80
+ | `NODEUI_TOKEN` | unset | Require an access token. |
81
+ | `NODEUI_ALLOWED_HOSTS` | unset | Comma-separated extra `Host` names. |
82
+ | `NODEUI_ALLOWED_ORIGINS` | unset | Comma-separated extra `Origin` values. |
83
+ | `NODEUI_ALLOWED_REMOTE` | unset | Comma-separated client IPs / IPv4 CIDRs. |
84
+ | `NODEUI_TRUST_PROXY` | `false` | Accept `X-Forwarded-*` requests. |
85
+ | `NODEUI_MAX_SSE_CLIENTS` | `10` | Concurrent live streams. |
86
+
87
+ ## Usage
88
+
89
+ ```ts
90
+ import { createNodeUI, type NodeUIServer } from '@singhak/nodeui-core';
91
+
92
+ const server: NodeUIServer = createNodeUI({
93
+ plugins: [{ id: 'queues', title: 'Queues', get: async () => ({ ok: true, data: await jobs() }) }],
94
+ healthChecks: { db: () => pool.query('select 1') },
95
+ });
96
+ const middleware = server.middleware();
97
+ // middleware is (req, res, next) => void; mount it before your routes.
98
+ server.mark('listening');
99
+ server.shutdown();
100
+ ```
101
+
102
+ Plugin ids are lowercase letters, digits and `-`, and must not collide with a built-in panel.
103
+ Express routes are discovered automatically, and the Fastify, Hapi and Hono adapters feed
104
+ the panel for you. For anything else (Koa, plain `http`, a custom router), feed it with
105
+ `server.setRoutes([...])`.
106
+
107
+ ## Development
108
+
109
+ ```bash
110
+ npm run typecheck # tsc --noEmit
111
+ npm test # vitest run (unit + e2e)
112
+ npm run build # emit dist/
113
+ ```