@karmaniverous/jeeves-server 3.0.0 → 3.1.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.
@@ -2,57 +2,75 @@
2
2
 
3
3
  How to run Jeeves Server in production.
4
4
 
5
- > Jeeves Server runs on **Windows** and **Linux**. Both platforms are tested in CI.
6
-
7
5
  ## Prerequisites
8
6
 
9
- - **Node.js** ≥ 18
7
+ - **Node.js** ≥ 20
10
8
  - **Chrome or Chromium** — for PDF/DOCX export via Puppeteer
11
9
  - **A domain** with HTTPS — required for Google OAuth and secure sharing
12
- - **A reverse proxy** — nginx, Caddy, or similar (recommended)
10
+ - **A reverse proxy** — Caddy, nginx, or similar (recommended)
11
+
12
+ ### Bundled Dependencies
13
13
 
14
- ### Optional Dependencies
14
+ - **Mermaid CLI** — bundled as a direct dependency (`@mermaid-js/mermaid-cli`). No separate install needed.
15
+ - **PlantUML jar** — downloaded automatically during `npm install` (via `postinstall` script). Requires Java (JDK 11+) at runtime for local rendering.
15
16
 
16
- - **Java** (JDK 11+) — required for local PlantUML rendering with `!include` support. Without Java, PlantUML falls back to the community server (no `!include` support).
17
- - **PlantUML jar** — download from [plantuml.com/download](https://plantuml.com/download). Configure the path in `jeeves.config.ts` under `plantuml.jarPath`.
18
- - **Mermaid CLI** — for server-side Mermaid diagram rendering. Install with `npm install @mermaid-js/mermaid-cli` and configure `mermaidCliPath` in `jeeves.config.ts`.
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g @karmaniverous/jeeves-server
21
+ ```
22
+
23
+ Create your config file (see [Setup & Configuration](setup.md)):
24
+
25
+ ```bash
26
+ # Example: JSON config
27
+ cat > /etc/jeeves-server.config.json << 'EOF'
28
+ {
29
+ "chromePath": "/usr/bin/chromium-browser",
30
+ "auth": { "modes": ["keys"] },
31
+ "keys": {
32
+ "_internal": "your-random-hex-seed",
33
+ "primary": "another-random-hex-seed"
34
+ }
35
+ }
36
+ EOF
37
+ ```
19
38
 
20
39
  ## Running the Server
21
40
 
22
41
  ### Direct
23
42
 
24
43
  ```bash
25
- node dist/server.js
44
+ jeeves-server start --config /path/to/jeeves-server.config.json
26
45
  ```
27
46
 
28
- The server listens on the port configured in `jeeves.config.ts` (default: 1934) on all interfaces (`0.0.0.0`).
47
+ The server listens on the configured port (default: 1934) on all interfaces.
29
48
 
30
49
  ### As a Windows Service (NSSM)
31
50
 
32
- [NSSM](https://nssm.cc/) (Non-Sucking Service Manager) turns any executable into a Windows service:
51
+ Use the built-in CLI to generate NSSM install commands:
33
52
 
34
53
  ```bash
35
- # Install the service
36
- nssm install JeevesServer "C:\Program Files\nodejs\node.exe" "E:\jeeves-server\dist\server.js"
37
-
38
- # Configure working directory
39
- nssm set JeevesServer AppDirectory "E:\jeeves-server"
54
+ jeeves-server service install --config "C:\\config\\jeeves-server.config.json"
55
+ ```
40
56
 
41
- # Configure stdout/stderr logging
42
- nssm set JeevesServer AppStdout "E:\jeeves-server\logs\service-stdout.log"
43
- nssm set JeevesServer AppStderr "E:\jeeves-server\logs\service-stderr.log"
57
+ This prints the `nssm install` commands. Run them, then:
44
58
 
45
- # Start the service
46
- nssm start JeevesServer
59
+ ```bash
60
+ jeeves-server service start
61
+ jeeves-server service stop
62
+ jeeves-server service restart
47
63
  ```
48
64
 
49
- **Service management:**
65
+ Or use NSSM directly:
66
+
50
67
  ```bash
68
+ nssm install JeevesServer "C:\\Program Files\\nodejs\\node.exe" "<global-npm-path>\\@karmaniverous\\jeeves-server\\dist\\src\\cli\\index.js" start --config "C:\\config\\jeeves-server.config.json"
69
+ nssm set JeevesServer AppDirectory "<working-dir>"
70
+ nssm set JeevesServer AppStdout "<log-dir>\\service.log"
71
+ nssm set JeevesServer AppStderr "<log-dir>\\service-error.log"
72
+ nssm set JeevesServer Start SERVICE_AUTO_START
51
73
  nssm start JeevesServer
52
- nssm stop JeevesServer
53
- nssm restart JeevesServer
54
- nssm status JeevesServer
55
- nssm remove JeevesServer confirm # Uninstall
56
74
  ```
57
75
 
58
76
  ### As a systemd Service (Linux)
@@ -66,8 +84,7 @@ After=network.target
66
84
  [Service]
67
85
  Type=simple
68
86
  User=jeeves
69
- WorkingDirectory=/opt/jeeves-server
70
- ExecStart=/usr/bin/node /opt/jeeves-server/dist/server.js
87
+ ExecStart=/usr/bin/env jeeves-server start --config /etc/jeeves-server.config.json
71
88
  Restart=on-failure
72
89
  RestartSec=5
73
90
  Environment=NODE_ENV=production
@@ -79,69 +96,11 @@ WantedBy=multi-user.target
79
96
  ```bash
80
97
  sudo systemctl enable jeeves-server
81
98
  sudo systemctl start jeeves-server
82
- sudo systemctl status jeeves-server
83
- ```
84
-
85
- ### Linux Quick Start (Ubuntu/Debian)
86
-
87
- ```bash
88
- # System packages
89
- sudo apt-get update && sudo apt-get install -y curl git build-essential chromium-browser caddy
90
-
91
- # Node.js 22
92
- curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
93
- sudo apt-get install -y nodejs
94
-
95
- # Clone and build
96
- cd /opt
97
- sudo git clone https://github.com/karmaniverous/jeeves-server.git
98
- cd jeeves-server
99
- npm ci
100
- cd client && npm ci && npx vite build --outDir ../dist/client && cd ..
101
- npx tsc
102
-
103
- # Configure
104
- cp jeeves.config.template.ts jeeves.config.ts
105
- # Edit jeeves.config.ts — set chromePath, roots, auth, keys, etc.
106
- echo '{}' > state.json
107
- ```
108
-
109
- **Linux-specific config options:**
110
-
111
- ```typescript
112
- {
113
- // Chromium path (required for PDF/DOCX export)
114
- chromePath: '/usr/bin/chromium-browser',
115
-
116
- // Filesystem roots for the file browser (replaces Windows drive letters)
117
- roots: {
118
- home: '/home',
119
- projects: '/opt/projects',
120
- },
121
-
122
- // Mermaid CLI path (optional, for .mmd diagram rendering)
123
- mermaidCliPath: '/opt/mermaid-cli',
124
- }
125
- ```
126
-
127
- On Windows, `roots` is ignored — the file browser auto-discovers drive letters. On Linux, if `roots` is omitted, it defaults to `{ root: '/' }`.
128
-
129
- **Puppeteer config** (for Chromium on Linux):
130
-
131
- Create `puppeteer.json` in the server root:
132
- ```json
133
- {
134
- "executablePath": "/usr/bin/chromium-browser",
135
- "args": ["--no-sandbox", "--disable-setuid-sandbox"]
136
- }
137
99
  ```
138
100
 
139
101
  ## Reverse Proxy
140
102
 
141
- Running behind a reverse proxy is recommended for:
142
- - **HTTPS termination** — required for Google OAuth and secure key transmission
143
- - **Domain routing** — serve on a clean domain/subdomain
144
- - **Rate limiting** and request filtering
103
+ Running behind a reverse proxy is recommended for HTTPS termination, domain routing, and rate limiting.
145
104
 
146
105
  ### Caddy (simplest)
147
106
 
@@ -169,14 +128,7 @@ server {
169
128
  proxy_set_header X-Real-IP $remote_addr;
170
129
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
171
130
  proxy_set_header X-Forwarded-Proto $scheme;
172
-
173
- # Large file uploads (for webhook bodies)
174
131
  client_max_body_size 10M;
175
-
176
- # WebSocket support (if needed in future)
177
- proxy_http_version 1.1;
178
- proxy_set_header Upgrade $http_upgrade;
179
- proxy_set_header Connection "upgrade";
180
132
  }
181
133
  }
182
134
 
@@ -189,99 +141,43 @@ server {
189
141
 
190
142
  ## HTTPS
191
143
 
192
- **HTTPS is required** when using Google OAuth — Google will not redirect to an HTTP callback URL (except `localhost` for development).
193
-
194
- **HTTPS is strongly recommended** even with key-only auth, because keys appear in URL parameters. Without HTTPS, keys are visible to network observers.
195
-
196
- ### Options
197
-
198
- | Method | Effort | Best For |
199
- |--------|--------|----------|
200
- | **Caddy** | Minimal | Automatic HTTPS, zero config |
201
- | **Let's Encrypt + nginx** | Moderate | Fine-grained control |
202
- | **Cloudflare Tunnel** | Moderate | No port forwarding needed |
203
-
204
- ## Google OAuth Setup for Production
144
+ **HTTPS is required** when using Google OAuth — Google will not redirect to an HTTP callback URL (except `localhost`).
205
145
 
206
- When using Google OAuth in production:
207
-
208
- 1. **Add your domain** to the Google Cloud Console OAuth consent screen
209
- 2. **Set the redirect URI** to `https://your-domain.com/auth/google/callback`
210
- 3. **Update `jeeves.config.ts`** with the production credentials
211
-
212
- > **Dev vs Prod:** You can use different Google OAuth client IDs for development and production. Each `jeeves.config.ts` is gitignored and instance-specific.
213
-
214
- ### Multiple environments
215
-
216
- Run dev and prod on the same machine using different ports:
217
-
218
- ```typescript
219
- // Dev: jeeves.config.ts (port 3457)
220
- port: 3457,
221
- auth: {
222
- google: {
223
- clientId: 'dev-client-id.apps.googleusercontent.com',
224
- clientSecret: 'dev-secret',
225
- },
226
- },
227
-
228
- // Prod: jeeves.config.ts (port 1934)
229
- port: 1934,
230
- auth: {
231
- google: {
232
- clientId: 'prod-client-id.apps.googleusercontent.com',
233
- clientSecret: 'prod-secret',
234
- },
235
- },
236
- ```
237
-
238
- Each needs its own Google OAuth redirect URI registered.
146
+ **HTTPS is strongly recommended** even with key-only auth, because keys appear in URL parameters.
239
147
 
240
148
  ## Health Checks
241
149
 
242
- The `/health` endpoint requires no authentication:
243
-
244
150
  ```bash
151
+ # No auth required
245
152
  curl http://localhost:1934/health
246
- # Returns 200 OK
153
+
154
+ # Detailed server status (no auth required)
155
+ curl http://localhost:1934/api/status
247
156
  ```
248
157
 
249
- Use this for:
250
- - Load balancer health checks
251
- - Service monitoring (Uptime Kuma, Prometheus, etc.)
252
- - NSSM/systemd restart triggers
158
+ The `/api/status` endpoint returns version, uptime, connected services, export capabilities, and event schemas. Add `?events=N` to include the N most recent event log entries. Use `/health` for simple load balancer checks and `/api/status` for monitoring dashboards.
253
159
 
254
160
  ## Updating
255
161
 
256
162
  ```bash
257
- cd /path/to/jeeves-server
258
- git pull
259
-
260
- # Full rebuild
261
- npm install
262
- npm run build
263
- cd client && npx vite build --outDir ../dist/client && cd ..
163
+ # Update the global package
164
+ npm install -g @karmaniverous/jeeves-server@latest
264
165
 
265
166
  # Restart the service
266
- nssm restart JeevesServer # Windows
267
- sudo systemctl restart jeeves-server # Linux
167
+ jeeves-server service restart # or: nssm restart JeevesServer / systemctl restart jeeves-server
268
168
  ```
269
169
 
270
- > ⚠️ Remember: `npm run build` deletes `dist/` entirely. Always rebuild the client after the server.
271
-
272
170
  ## File Permissions
273
171
 
274
172
  The server needs:
275
- - **Read access** to any files you want to serve (drives, directories)
276
- - **Write access** to its own directory for `state.json` and `logs/`
173
+ - **Read access** to any files you want to serve
174
+ - **Write access** to its working directory for `state.json` and logs
277
175
  - **Execute access** to Chrome/Chromium for PDF export
278
176
  - **Execute access** to event handler commands
279
177
 
280
178
  ## Backups
281
179
 
282
180
  Key files to back up:
283
- - `jeeves.config.ts` — your configuration (secrets!)
181
+ - Your config file (`jeeves-server.config.json`)contains secrets
284
182
  - `state.json` — insider keys and rotation state
285
- - `logs/event-queue.jsonl` + `logs/event-queue.cursor` — pending events
286
-
287
- The server code itself is in git — no need to back up `dist/` or `node_modules/`.
183
+ - Event queue files — `logs/event-queue.jsonl` + `logs/event-queue.cursor`
@@ -8,37 +8,32 @@ Jeeves Server includes a webhook gateway that receives HTTP POST requests, valid
8
8
 
9
9
  ## Configuration
10
10
 
11
- Events are defined in `jeeves.config.ts`:
12
-
13
- ```typescript
14
- events: {
15
- 'notion-page-update': {
16
- // JSON Schema matched against the incoming POST body
17
- schema: {
18
- type: 'object',
19
- properties: {
20
- type: { const: 'page.content_updated' },
21
- },
22
- required: ['type'],
23
- },
24
-
25
- // Shell command to execute when matched
26
- cmd: 'node /path/to/handler.js',
11
+ Events are defined in your config file:
27
12
 
28
- // Optional: transform the body before passing to the command
29
- map: {
30
- pageId: {
31
- '$': { method: '$.lib._.get', params: ['$.input', 'data.page_id'] },
13
+ ```json
14
+ {
15
+ "events": {
16
+ "notion-page-update": {
17
+ "schema": {
18
+ "type": "object",
19
+ "properties": {
20
+ "type": { "const": "page.content_updated" }
21
+ },
22
+ "required": ["type"]
32
23
  },
33
- type: {
34
- '$': { method: '$.lib._.get', params: ['$.input', 'type'] },
24
+ "cmd": "node /path/to/handler.js",
25
+ "map": {
26
+ "pageId": {
27
+ "$": { "method": "$.lib._.get", "params": ["$.input", "data.page_id"] }
28
+ },
29
+ "type": {
30
+ "$": { "method": "$.lib._.get", "params": ["$.input", "type"] }
31
+ }
35
32
  },
36
- },
37
-
38
- // Optional: override default timeout (ms)
39
- timeoutMs: 60000,
40
- },
41
- },
33
+ "timeoutMs": 60000
34
+ }
35
+ }
36
+ }
42
37
  ```
43
38
 
44
39
  ### Schema matching
@@ -68,15 +63,15 @@ When `map` is omitted, the full webhook body is passed as-is.
68
63
 
69
64
  **Example — Notion sends a large payload, we extract just two fields:**
70
65
 
71
- ```typescript
72
- map: {
73
- pageId: {
74
- '$': { method: '$.lib._.get', params: ['$.input', 'data.page_id'] },
75
- },
76
- type: {
77
- '$': { method: '$.lib._.get', params: ['$.input', 'type'] },
66
+ ```json
67
+ {
68
+ "pageId": {
69
+ "$": { "method": "$.lib._.get", "params": ["$.input", "data.page_id"] }
78
70
  },
79
- },
71
+ "type": {
72
+ "$": { "method": "$.lib._.get", "params": ["$.input", "type"] }
73
+ }
74
+ }
80
75
  ```
81
76
 
82
77
  Input: `{ type: "page.content_updated", data: { page_id: "abc123", ... } }`
@@ -86,13 +81,15 @@ Output to command: `{ pageId: "abc123", type: "page.content_updated" }`
86
81
 
87
82
  Webhook callers must authenticate with a key that has scope access to `/event`:
88
83
 
89
- ```typescript
90
- keys: {
91
- 'webhook-notion': {
92
- key: 'random-seed-string',
93
- scopes: ['/event'],
94
- },
95
- },
84
+ ```json
85
+ {
86
+ "keys": {
87
+ "webhook-notion": {
88
+ "key": "random-seed-string",
89
+ "scopes": ["/event"]
90
+ }
91
+ }
92
+ }
96
93
  ```
97
94
 
98
95
  Your config contains a **seed** — a secret string that never leaves the server. The actual URL key is **derived** from the seed by the server. To get it:
@@ -171,16 +168,26 @@ process.stdin.on('end', () => {
171
168
 
172
169
  ## Global Settings
173
170
 
174
- ```typescript
175
- // Default timeout for all event commands (ms)
176
- eventTimeoutMs: 30_000,
177
-
178
- // Purge log entries older than this (ms). Default: 30 days
179
- eventLogPurgeMs: 2_592_000_000,
171
+ ```json
172
+ {
173
+ "eventTimeoutMs": 30000,
174
+ "eventLogPurgeMs": 2592000000
175
+ }
180
176
  ```
181
177
 
182
178
  ## Monitoring
183
179
 
180
+ ### Via API
181
+
182
+ ```bash
183
+ # Get 20 most recent event log entries (no auth required)
184
+ curl http://localhost:1934/api/status?events=20
185
+ ```
186
+
187
+ The `eventLog` array in the response contains entries newest-first, each with `ts`, `event`, `matched`, `exitCode`, and `durationMs`.
188
+
189
+ ### Via log files
190
+
184
191
  Check the event log for failures:
185
192
 
186
193
  ```bash
@@ -193,7 +200,7 @@ grep '"matched":false' logs/event-log.jsonl
193
200
 
194
201
  ## Example: Notion Webhook Integration
195
202
 
196
- 1. **Configure the event** in `jeeves.config.ts` (see Configuration above)
203
+ 1. **Configure the event** in `your config file` (see Configuration above)
197
204
  2. **Create a scoped key** for the webhook
198
205
  3. **Register the webhook URL** in Notion:
199
206
  - Settings → Connections → Add a connection
package/guides/exports.md CHANGED
@@ -62,14 +62,16 @@ PDF generation uses [**Puppeteer**](https://github.com/puppeteer/puppeteer) with
62
62
  ### Requirements
63
63
 
64
64
  - **Chrome/Chromium** must be installed on the server
65
- - **`chromePath`** must point to the executable in `jeeves.config.ts`
65
+ - **`chromePath`** must point to the executable in `your config file`
66
66
  - **`_internal` key** must be configured (Puppeteer uses it to authenticate)
67
67
 
68
- ```typescript
69
- chromePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
70
- keys: {
71
- _internal: 'random-seed-string', // Required for PDF/DOCX export
72
- },
68
+ ```json
69
+ {
70
+ "chromePath": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
71
+ "keys": {
72
+ "_internal": "random-seed-string"
73
+ }
74
+ }
73
75
  ```
74
76
 
75
77
  ### What you see is what you get
@@ -111,13 +113,7 @@ Mermaid diagrams (`.mmd` files) can be exported as SVG, PNG, or PDF via the [Mer
111
113
 
112
114
  ### Requirements
113
115
 
114
- - **Mermaid CLI** must be installed (via npm)
115
- - **`mermaidCliPath`** must point to the `mmdc` binary in `jeeves.config.ts`
116
- - **Puppeteer/Chrome** is required by Mermaid CLI for rendering
117
-
118
- ```typescript
119
- mermaidCliPath: '/usr/local/bin/mmdc',
120
- ```
116
+ Mermaid CLI is bundled as a direct dependency (`@mermaid-js/mermaid-cli`) — no separate installation or configuration needed. Chrome/Chromium is required for rendering.
121
117
 
122
118
  ### Export endpoint
123
119
 
@@ -139,12 +135,14 @@ PlantUML uses a **fallback rendering pipeline** — each method is tried in orde
139
135
 
140
136
  ### Configuration
141
137
 
142
- ```typescript
143
- plantuml: {
144
- jarPath: '/opt/plantuml/plantuml.jar', // Local jar path (optional)
145
- javaPath: '/usr/bin/java', // Java binary (optional, defaults to 'java')
146
- servers: ['https://internal.plantuml.example.com/plantuml'], // Private servers (optional)
147
- },
138
+ ```json
139
+ {
140
+ "plantuml": {
141
+ "jarPath": "/opt/plantuml/plantuml.jar",
142
+ "javaPath": "/usr/bin/java",
143
+ "servers": ["https://internal.plantuml.example.com/plantuml"]
144
+ }
145
+ }
148
146
  ```
149
147
 
150
148
  If `plantuml` is omitted entirely, only the public community server is used.
@@ -219,7 +217,7 @@ Directories can be downloaded as ZIP archives. The header shows a ZIP download o
219
217
 
220
218
  The `maxZipSizeMb` config setting (default: 100 MB) prevents accidentally zipping enormous directories:
221
219
 
222
- ```typescript
220
+ ```
223
221
  maxZipSizeMb: 100, // Refuse ZIP for directories larger than this
224
222
  ```
225
223
 
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Service Guides
3
+ children:
4
+ - ./setup.md
5
+ - ./sharing.md
6
+ - ./exports.md
7
+ - ./event-gateway.md
8
+ - ./deployment.md
9
+ - ./api-integration.md
10
+ - ../CHANGELOG.md
11
+ ---
12
+
13
+ # Service Guides
14
+
15
+ - [Setup & Configuration](./setup.md) — Installation, auth modes, cosmiconfig, named scopes, and config reference.
16
+ - [Insiders, Outsiders & Sharing](./sharing.md) — The access model, HMAC key derivation, expiring links, and key rotation.
17
+ - [Exporting & Downloads](./exports.md) — PDF, DOCX, SVG, PNG, and ZIP export via Puppeteer and bundled Mermaid/PlantUML.
18
+ - [Event Gateway](./event-gateway.md) — Webhook receiving, JSON Schema matching, JsonMap body transforms, and durable queue processing.
19
+ - [Deployment](./deployment.md) — Running as a service (NSSM/systemd), reverse proxy setup, HTTPS, and updates.
20
+ - [API & Integration](./api-integration.md) — Endpoint reference, Windows path conversion, share link generation, and AI assistant usage.
21
+ - [Changelog](../CHANGELOG.md) — Release history for `@karmaniverous/jeeves-server`.