@karmaniverous/jeeves-server 3.3.0 → 3.4.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/CHANGELOG.md CHANGED
@@ -2,10 +2,30 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. Dates are displayed in UTC.
4
4
 
5
- #### [3.3.0](https://github.com/karmaniverous/jeeves-server/compare/service/3.2.1...3.3.0)
5
+ #### [3.4.0](https://github.com/karmaniverous/jeeves-server/compare/service/3.3.1...3.4.0)
6
+
7
+ - Bump core to v0.3.0 and consolidate status endpoint [`#119`](https://github.com/karmaniverous/jeeves-server/pull/119)
8
+ - [117] feat: bump core to v0.3.0 and consolidate status endpoint (#117) [`c80be62`](https://github.com/karmaniverous/jeeves-server/commit/c80be62a3f512f7524c917b153ca6ecb053a6ce4)
9
+ - chore: release @karmaniverous/jeeves-server-openclaw v0.4.1 [`01a64b8`](https://github.com/karmaniverous/jeeves-server/commit/01a64b8693ffedb307022ed6d48ebd515aef10ab)
10
+ - [117] refactor(openclaw): use resolveOptionalPluginSetting for getPluginKey (#112) [`6b36937`](https://github.com/karmaniverous/jeeves-server/commit/6b3693725b3e6211fab250cdd935aa9e4a0091cc)
11
+
12
+ #### [service/3.3.1](https://github.com/karmaniverous/jeeves-server/compare/service/3.3.0...service/3.3.1)
13
+
14
+ > 22 March 2026
15
+
16
+ - Add configurable host bind + metaUrl service probe [`#114`](https://github.com/karmaniverous/jeeves-server/pull/114)
17
+ - chore: release @karmaniverous/jeeves-server-openclaw v0.4.0 [`566e438`](https://github.com/karmaniverous/jeeves-server/commit/566e438a5262e5f2e80db4690c9907b6658e5519)
18
+ - [113] feat: add host bind and metaUrl config options [`798d133`](https://github.com/karmaniverous/jeeves-server/commit/798d133825f99f5a5fc19bb0ba9093b757f62f0f)
19
+ - chore: release @karmaniverous/jeeves-server v3.3.1 [`bf01414`](https://github.com/karmaniverous/jeeves-server/commit/bf01414184cc7b1b64a46f955f3bb850ab8d6e92)
20
+ - npm audit fix [`a07adac`](https://github.com/karmaniverous/jeeves-server/commit/a07adac906ca032bedeef25b16b9e0c05231b4b0)
21
+
22
+ #### [service/3.3.0](https://github.com/karmaniverous/jeeves-server/compare/service/3.2.1...service/3.3.0)
23
+
24
+ > 21 March 2026
6
25
 
7
26
  - feat: core v0.2.0 SDK adoption [`#111`](https://github.com/karmaniverous/jeeves-server/pull/111)
8
27
  - chore: release @karmaniverous/jeeves-server-openclaw v0.3.1 [`11309c1`](https://github.com/karmaniverous/jeeves-server/commit/11309c1c3d82f6950b3d0291546206b523df83fa)
28
+ - chore: release @karmaniverous/jeeves-server v3.3.0 [`1b1aec6`](https://github.com/karmaniverous/jeeves-server/commit/1b1aec644106ce05576e608d278a37860a47de61)
9
29
 
10
30
  #### [service/3.2.1](https://github.com/karmaniverous/jeeves-server/compare/service/3.2.0...service/3.2.1)
11
31
 
@@ -20,6 +20,7 @@ export function registerConfigCommand(cli) {
20
20
  const cfg = await loadConfig(options.config);
21
21
  console.log('\u2713 Configuration valid');
22
22
  console.log(` Port: ${String(cfg.port)}`);
23
+ console.log(` Host: ${cfg.host}`);
23
24
  console.log(` Auth modes: ${cfg.authModes.join(', ')}`);
24
25
  console.log(` Keys: ${String(cfg.resolvedKeys.length)}`);
25
26
  console.log(` Insiders: ${String(cfg.resolvedInsiders.length)}`);
@@ -28,6 +29,8 @@ export function registerConfigCommand(cli) {
28
29
  console.log(` Watcher: ${cfg.watcherUrl}`);
29
30
  if (cfg.runnerUrl)
30
31
  console.log(` Runner: ${cfg.runnerUrl}`);
32
+ if (cfg.metaUrl)
33
+ console.log(` Meta: ${cfg.metaUrl}`);
31
34
  }
32
35
  catch (error) {
33
36
  console.error('\u2717 Configuration invalid');
@@ -46,6 +49,7 @@ export function registerConfigCommand(cli) {
46
49
  console.log('');
47
50
  console.log('Server:');
48
51
  console.log(` port: ${String(cfg.port)}`);
52
+ console.log(` host: ${cfg.host}`);
49
53
  console.log(` chromePath: ${cfg.chromePath}`);
50
54
  if (cfg.roots) {
51
55
  console.log(` roots: ${JSON.stringify(cfg.roots)}`);
@@ -69,6 +73,7 @@ export function registerConfigCommand(cli) {
69
73
  console.log('Integrations:');
70
74
  console.log(` watcherUrl: ${cfg.watcherUrl ?? 'not configured'}`);
71
75
  console.log(` runnerUrl: ${cfg.runnerUrl ?? 'not configured'}`);
76
+ console.log(` metaUrl: ${cfg.metaUrl ?? 'not configured'}`);
72
77
  console.log('');
73
78
  console.log('Events:');
74
79
  const eventNames = Object.keys(cfg.events);
@@ -186,6 +186,7 @@ export function buildRuntimeConfig(config, rootDir, configPath) {
186
186
  const resolvedInsiders = resolveInsiders(config.insiders, config.scopes, stateFile);
187
187
  return {
188
188
  port: config.port,
189
+ host: config.host,
189
190
  eventTimeoutMs: config.eventTimeoutMs,
190
191
  eventLogPurgeMs: config.eventLogPurgeMs,
191
192
  maxZipSizeMb: config.maxZipSizeMb,
@@ -216,6 +217,7 @@ export function buildRuntimeConfig(config, rootDir, configPath) {
216
217
  internalInsiderKey: deriveInternalKey(resolvedKeys),
217
218
  runnerUrl: config.runnerUrl,
218
219
  watcherUrl: config.watcherUrl,
220
+ metaUrl: config.metaUrl,
219
221
  diagramCachePath: config.diagramCachePath,
220
222
  configPath,
221
223
  eventsLog: path.join(rootDir, 'logs', 'webhook-events.jsonl'),
@@ -187,6 +187,8 @@ describe('buildRuntimeConfig', () => {
187
187
  it('constructs correct path fields', () => {
188
188
  const config = {
189
189
  port: 1934,
190
+ host: '0.0.0.0',
191
+ metaUrl: 'http://127.0.0.1:1938',
190
192
  eventTimeoutMs: 30000,
191
193
  eventLogPurgeMs: 2592000000,
192
194
  maxZipSizeMb: 100,
@@ -89,6 +89,12 @@ function getScopeRefs(scopes) {
89
89
  export const jeevesConfigSchema = z
90
90
  .object({
91
91
  port: z.number().int().positive().default(1934),
92
+ /**
93
+ * Network interface to bind the server to.
94
+ * Default: '0.0.0.0' (all interfaces — required for external access by insiders, share links, etc.)
95
+ * Set to '127.0.0.1' to restrict to loopback only.
96
+ */
97
+ host: z.string().min(1).default('0.0.0.0'),
92
98
  chromePath: z.string().min(1),
93
99
  auth: authSchema,
94
100
  /** Named scope definitions, referenced by insiders/keys/outsiderPolicy */
@@ -139,6 +145,11 @@ export const jeevesConfigSchema = z
139
145
  * When set, the search UI appears in the header. Example: 'http://localhost:3458'
140
146
  */
141
147
  watcherUrl: z.url().optional(),
148
+ /**
149
+ * URL of the jeeves-meta API for synthesis engine health checks.
150
+ * Default: 'http://127.0.0.1:1938'
151
+ */
152
+ metaUrl: z.url().default('http://127.0.0.1:1938'),
142
153
  /**
143
154
  * Global outsider policy â€" constrains which paths are eligible for outsider sharing.
144
155
  * Uses the same allow/deny model as insider scopes.
@@ -13,7 +13,6 @@ import { rawRoutes } from './raw.js';
13
13
  import { runnerRoutes } from './runner.js';
14
14
  import { searchRoutes } from './search.js';
15
15
  import { sharingRoutes } from './sharing.js';
16
- import { statusRoutes } from './status.js';
17
16
  export const apiRoute = async (fastify) => {
18
17
  // Add auth hook directly to this context (not as a child plugin)
19
18
  // so it applies to all routes registered below.
@@ -29,5 +28,4 @@ export const apiRoute = async (fastify) => {
29
28
  await fastify.register(searchRoutes);
30
29
  await fastify.register(sharingRoutes);
31
30
  await fastify.register(authStatusRoutes);
32
- await fastify.register(statusRoutes);
33
31
  };
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Uses the core SDK's `createConfigQueryHandler()` for JSONPath support.
5
5
  *
6
- * @module routes/config
6
+ * @packageDocumentation
7
7
  */
8
8
  import { createConfigQueryHandler } from '@karmaniverous/jeeves';
9
9
  import { getConfig } from '../config/index.js';
@@ -7,6 +7,7 @@ import { sanitizeConfig } from './config.js';
7
7
  function makeConfig(overrides = {}) {
8
8
  return {
9
9
  port: 1934,
10
+ host: '0.0.0.0',
10
11
  eventTimeoutMs: 30_000,
11
12
  eventLogPurgeMs: 604_800_000,
12
13
  maxZipSizeMb: 100,
@@ -4,9 +4,9 @@
4
4
  * Returns version, uptime, port, connected services reachability,
5
5
  * event schemas, insider count (no PII), and export capabilities.
6
6
  */
7
- import { getConfig } from '../../config/index.js';
8
- import { getRecentEvents } from '../../services/eventLog.js';
9
- import { packageVersion } from '../../util/packageVersion.js';
7
+ import { getConfig } from '../config/index.js';
8
+ import { getRecentEvents } from '../services/eventLog.js';
9
+ import { packageVersion } from '../util/packageVersion.js';
10
10
  const startTime = Date.now();
11
11
  async function checkService(url) {
12
12
  // Try /status first (watcher), then /health (runner)
@@ -28,11 +28,12 @@ async function checkService(url) {
28
28
  }
29
29
  // eslint-disable-next-line @typescript-eslint/require-await
30
30
  export const statusRoutes = async (fastify) => {
31
- fastify.get('/api/status', async (request) => {
31
+ fastify.get('/status', async (request) => {
32
32
  const config = getConfig();
33
- const [watcher, runner] = await Promise.all([
33
+ const [watcher, runner, meta] = await Promise.all([
34
34
  config.watcherUrl ? checkService(config.watcherUrl) : null,
35
35
  config.runnerUrl ? checkService(config.runnerUrl) : null,
36
+ config.metaUrl ? checkService(config.metaUrl) : null,
36
37
  ]);
37
38
  return {
38
39
  version: packageVersion,
@@ -67,6 +68,7 @@ export const statusRoutes = async (fastify) => {
67
68
  services: {
68
69
  watcher,
69
70
  runner,
71
+ meta,
70
72
  },
71
73
  ...(request.query.events
72
74
  ? {
@@ -2,6 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
2
2
  // Mock config
3
3
  const mockConfig = {
4
4
  port: 1934,
5
+ host: '0.0.0.0',
5
6
  chromePath: '/usr/bin/chromium',
6
7
  authModes: ['keys'],
7
8
  resolvedInsiders: [{ email: 'a@b.com' }, { email: 'c@d.com' }],
@@ -17,14 +18,15 @@ const mockConfig = {
17
18
  },
18
19
  watcherUrl: null,
19
20
  runnerUrl: null,
21
+ metaUrl: null,
20
22
  exportFormats: ['pdf', 'docx', 'zip'],
21
23
  };
22
- vi.mock('../../config/index.js', () => ({
24
+ vi.mock('../config/index.js', () => ({
23
25
  getConfig: () => mockConfig,
24
26
  }));
25
27
  // Must import AFTER mock
26
28
  const { statusRoutes } = await import('./status.js');
27
- describe('GET /api/status', () => {
29
+ describe('GET /status', () => {
28
30
  it('returns structured status', async () => {
29
31
  // Create a minimal Fastify-like test harness
30
32
  const routes = {};
@@ -34,7 +36,7 @@ describe('GET /api/status', () => {
34
36
  },
35
37
  };
36
38
  await statusRoutes(fakeFastify, {});
37
- const handler = routes['/api/status'];
39
+ const handler = routes['/status'];
38
40
  expect(handler).toBeDefined();
39
41
  const result = await handler({ accessMode: 'insider', query: {} });
40
42
  const status = result;
@@ -13,10 +13,10 @@ import { apiRoute } from './routes/api/index.js';
13
13
  import { authRoute } from './routes/auth.js';
14
14
  import { registerConfigRoute } from './routes/config.js';
15
15
  import { eventRoute } from './routes/event.js';
16
- import { healthRoute } from './routes/health.js';
17
16
  import { keysRoute } from './routes/keys.js';
18
17
  import { pathRoute } from './routes/path/index.js';
19
18
  import { staticRoutes } from './routes/static.js';
19
+ import { statusRoutes } from './routes/status.js';
20
20
  import { initDiagramCache } from './services/diagramCache.js';
21
21
  import { startQueueProcessor } from './services/eventQueue.js';
22
22
  import { initExportCache } from './services/exportCache.js';
@@ -35,8 +35,8 @@ async function start() {
35
35
  });
36
36
  // Register routes
37
37
  await fastify.register(staticRoutes);
38
- await fastify.register(healthRoute);
39
38
  registerConfigRoute(fastify);
39
+ await fastify.register(statusRoutes);
40
40
  await fastify.register(authRoute);
41
41
  await fastify.register(keysRoute);
42
42
  await fastify.register(eventRoute);
@@ -71,15 +71,15 @@ async function start() {
71
71
  initExportCache();
72
72
  // Start queue processor
73
73
  startQueueProcessor();
74
- await fastify.listen({ port: config.port, host: '0.0.0.0' });
75
- console.log(`Jeeves server listening on port ${String(config.port)}`);
74
+ await fastify.listen({ port: config.port, host: config.host });
75
+ console.log(`Jeeves server listening on ${config.host}:${String(config.port)}`);
76
76
  console.log(`Endpoints:`);
77
77
  console.log(` GET /browse/* - File browser SPA`);
78
78
  console.log(` GET /api/raw/* - Raw file serving`);
79
79
  console.log(` GET /api/export/* - PDF/DOCX/ZIP export`);
80
80
  console.log(` POST /event - Event Gateway (key auth)`);
81
81
  console.log(` GET /key - Compute path key (X-API-Key auth)`);
82
- console.log(` GET /health - Health check (no auth)`);
82
+ console.log(` GET /status - Server status (no auth)`);
83
83
  }
84
84
  catch (err) {
85
85
  console.error('Fatal startup error:', err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/jeeves-server",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Secure file browser, markdown viewer, and webhook gateway with PDF/DOCX export and expiring share links",
5
5
  "keywords": [
6
6
  "fastify",
@@ -47,9 +47,9 @@
47
47
  "license": "MIT",
48
48
  "dependencies": {
49
49
  "@commander-js/extra-typings": "^14.0.0",
50
- "@karmaniverous/jeeves": "^0.2.0",
51
50
  "@fastify/cookie": "^11.0.2",
52
51
  "@fastify/static": "^8.3.0",
52
+ "@karmaniverous/jeeves": "^0.3.0",
53
53
  "@karmaniverous/jsonmap": "^0.3.1",
54
54
  "@mermaid-js/mermaid-cli": "^11.12.0",
55
55
  "@turbodocx/html-to-docx": "^1.1.0",
@@ -27,6 +27,7 @@ export function registerConfigCommand(cli: Command): void {
27
27
  const cfg = await loadConfig(options.config);
28
28
  console.log('\u2713 Configuration valid');
29
29
  console.log(` Port: ${String(cfg.port)}`);
30
+ console.log(` Host: ${cfg.host}`);
30
31
  console.log(` Auth modes: ${cfg.authModes.join(', ')}`);
31
32
  console.log(` Keys: ${String(cfg.resolvedKeys.length)}`);
32
33
  console.log(` Insiders: ${String(cfg.resolvedInsiders.length)}`);
@@ -35,6 +36,7 @@ export function registerConfigCommand(cli: Command): void {
35
36
  );
36
37
  if (cfg.watcherUrl) console.log(` Watcher: ${cfg.watcherUrl}`);
37
38
  if (cfg.runnerUrl) console.log(` Runner: ${cfg.runnerUrl}`);
39
+ if (cfg.metaUrl) console.log(` Meta: ${cfg.metaUrl}`);
38
40
  } catch (error) {
39
41
  console.error('\u2717 Configuration invalid');
40
42
  console.error(error instanceof Error ? error.message : String(error));
@@ -53,6 +55,7 @@ export function registerConfigCommand(cli: Command): void {
53
55
  console.log('');
54
56
  console.log('Server:');
55
57
  console.log(` port: ${String(cfg.port)}`);
58
+ console.log(` host: ${cfg.host}`);
56
59
  console.log(` chromePath: ${cfg.chromePath}`);
57
60
  if (cfg.roots) {
58
61
  console.log(` roots: ${JSON.stringify(cfg.roots)}`);
@@ -78,6 +81,7 @@ export function registerConfigCommand(cli: Command): void {
78
81
  console.log('Integrations:');
79
82
  console.log(` watcherUrl: ${cfg.watcherUrl ?? 'not configured'}`);
80
83
  console.log(` runnerUrl: ${cfg.runnerUrl ?? 'not configured'}`);
84
+ console.log(` metaUrl: ${cfg.metaUrl ?? 'not configured'}`);
81
85
  console.log('');
82
86
  console.log('Events:');
83
87
  const eventNames = Object.keys(cfg.events);
@@ -236,6 +236,8 @@ describe('buildRuntimeConfig', () => {
236
236
  it('constructs correct path fields', () => {
237
237
  const config = {
238
238
  port: 1934,
239
+ host: '0.0.0.0',
240
+ metaUrl: 'http://127.0.0.1:1938',
239
241
  eventTimeoutMs: 30000,
240
242
  eventLogPurgeMs: 2592000000,
241
243
  maxZipSizeMb: 100,
@@ -250,6 +250,7 @@ export function buildRuntimeConfig(
250
250
 
251
251
  return {
252
252
  port: config.port,
253
+ host: config.host,
253
254
  eventTimeoutMs: config.eventTimeoutMs,
254
255
  eventLogPurgeMs: config.eventLogPurgeMs,
255
256
  maxZipSizeMb: config.maxZipSizeMb,
@@ -285,6 +286,7 @@ export function buildRuntimeConfig(
285
286
  internalInsiderKey: deriveInternalKey(resolvedKeys),
286
287
  runnerUrl: config.runnerUrl,
287
288
  watcherUrl: config.watcherUrl,
289
+ metaUrl: config.metaUrl,
288
290
  diagramCachePath: config.diagramCachePath,
289
291
  configPath,
290
292
  eventsLog: path.join(rootDir, 'logs', 'webhook-events.jsonl'),
@@ -100,6 +100,12 @@ function getScopeRefs(scopes: unknown): string[] {
100
100
  export const jeevesConfigSchema = z
101
101
  .object({
102
102
  port: z.number().int().positive().default(1934),
103
+ /**
104
+ * Network interface to bind the server to.
105
+ * Default: '0.0.0.0' (all interfaces — required for external access by insiders, share links, etc.)
106
+ * Set to '127.0.0.1' to restrict to loopback only.
107
+ */
108
+ host: z.string().min(1).default('0.0.0.0'),
103
109
  chromePath: z.string().min(1),
104
110
  auth: authSchema,
105
111
  /** Named scope definitions, referenced by insiders/keys/outsiderPolicy */
@@ -150,6 +156,11 @@ export const jeevesConfigSchema = z
150
156
  * When set, the search UI appears in the header. Example: 'http://localhost:3458'
151
157
  */
152
158
  watcherUrl: z.url().optional(),
159
+ /**
160
+ * URL of the jeeves-meta API for synthesis engine health checks.
161
+ * Default: 'http://127.0.0.1:1938'
162
+ */
163
+ metaUrl: z.url().default('http://127.0.0.1:1938'),
153
164
  /**
154
165
  * Global outsider policy â€" constrains which paths are eligible for outsider sharing.
155
166
  * Uses the same allow/deny model as insider scopes.
@@ -50,6 +50,7 @@ export interface ResolvedInsider {
50
50
  */
51
51
  export interface RuntimeConfig {
52
52
  port: number;
53
+ host: string;
53
54
  eventTimeoutMs: number;
54
55
  eventLogPurgeMs: number;
55
56
  maxZipSizeMb: number;
@@ -64,6 +65,7 @@ export interface RuntimeConfig {
64
65
  diagramCachePath?: string;
65
66
  runnerUrl?: string;
66
67
  watcherUrl?: string;
68
+ metaUrl?: string;
67
69
  outsiderPolicy: NormalizedScopes | null;
68
70
  events: JeevesConfig['events'];
69
71
  authModes: AuthMode[];
@@ -16,8 +16,6 @@ import { rawRoutes } from './raw.js';
16
16
  import { runnerRoutes } from './runner.js';
17
17
  import { searchRoutes } from './search.js';
18
18
  import { sharingRoutes } from './sharing.js';
19
- import { statusRoutes } from './status.js';
20
-
21
19
  export const apiRoute: FastifyPluginAsync = async (fastify) => {
22
20
  // Add auth hook directly to this context (not as a child plugin)
23
21
  // so it applies to all routes registered below.
@@ -33,5 +31,4 @@ export const apiRoute: FastifyPluginAsync = async (fastify) => {
33
31
  await fastify.register(searchRoutes);
34
32
  await fastify.register(sharingRoutes);
35
33
  await fastify.register(authStatusRoutes);
36
- await fastify.register(statusRoutes);
37
34
  };
@@ -11,6 +11,7 @@ import { sanitizeConfig } from './config.js';
11
11
  function makeConfig(overrides: Partial<RuntimeConfig> = {}): RuntimeConfig {
12
12
  return {
13
13
  port: 1934,
14
+ host: '0.0.0.0',
14
15
  eventTimeoutMs: 30_000,
15
16
  eventLogPurgeMs: 604_800_000,
16
17
  maxZipSizeMb: 100,
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Uses the core SDK's `createConfigQueryHandler()` for JSONPath support.
5
5
  *
6
- * @module routes/config
6
+ * @packageDocumentation
7
7
  */
8
8
 
9
9
  import { createConfigQueryHandler } from '@karmaniverous/jeeves';
@@ -3,6 +3,7 @@ import { describe, expect, it, vi } from 'vitest';
3
3
  // Mock config
4
4
  const mockConfig = {
5
5
  port: 1934,
6
+ host: '0.0.0.0',
6
7
  chromePath: '/usr/bin/chromium',
7
8
  authModes: ['keys'],
8
9
  resolvedInsiders: [{ email: 'a@b.com' }, { email: 'c@d.com' }],
@@ -18,17 +19,18 @@ const mockConfig = {
18
19
  },
19
20
  watcherUrl: null,
20
21
  runnerUrl: null,
22
+ metaUrl: null,
21
23
  exportFormats: ['pdf', 'docx', 'zip'],
22
24
  };
23
25
 
24
- vi.mock('../../config/index.js', () => ({
26
+ vi.mock('../config/index.js', () => ({
25
27
  getConfig: () => mockConfig,
26
28
  }));
27
29
 
28
30
  // Must import AFTER mock
29
31
  const { statusRoutes } = await import('./status.js');
30
32
 
31
- describe('GET /api/status', () => {
33
+ describe('GET /status', () => {
32
34
  it('returns structured status', async () => {
33
35
  // Create a minimal Fastify-like test harness
34
36
  const routes: Record<string, (req: unknown) => Promise<unknown>> = {};
@@ -40,7 +42,7 @@ describe('GET /api/status', () => {
40
42
 
41
43
  await statusRoutes(fakeFastify as never, {});
42
44
 
43
- const handler = routes['/api/status'];
45
+ const handler = routes['/status'];
44
46
  expect(handler).toBeDefined();
45
47
 
46
48
  const result = await handler({ accessMode: 'insider', query: {} });
@@ -7,9 +7,9 @@
7
7
 
8
8
  import type { FastifyPluginAsync } from 'fastify';
9
9
 
10
- import { getConfig } from '../../config/index.js';
11
- import { getRecentEvents } from '../../services/eventLog.js';
12
- import { packageVersion } from '../../util/packageVersion.js';
10
+ import { getConfig } from '../config/index.js';
11
+ import { getRecentEvents } from '../services/eventLog.js';
12
+ import { packageVersion } from '../util/packageVersion.js';
13
13
 
14
14
  const startTime = Date.now();
15
15
 
@@ -40,13 +40,14 @@ async function checkService(url: string): Promise<ServiceStatus> {
40
40
  // eslint-disable-next-line @typescript-eslint/require-await
41
41
  export const statusRoutes: FastifyPluginAsync = async (fastify) => {
42
42
  fastify.get<{ Querystring: { events?: string } }>(
43
- '/api/status',
43
+ '/status',
44
44
  async (request) => {
45
45
  const config = getConfig();
46
46
 
47
- const [watcher, runner] = await Promise.all([
47
+ const [watcher, runner, meta] = await Promise.all([
48
48
  config.watcherUrl ? checkService(config.watcherUrl) : null,
49
49
  config.runnerUrl ? checkService(config.runnerUrl) : null,
50
+ config.metaUrl ? checkService(config.metaUrl) : null,
50
51
  ]);
51
52
 
52
53
  return {
@@ -82,6 +83,7 @@ export const statusRoutes: FastifyPluginAsync = async (fastify) => {
82
83
  services: {
83
84
  watcher,
84
85
  runner,
86
+ meta,
85
87
  },
86
88
  ...(request.query.events
87
89
  ? {
package/src/server.ts CHANGED
@@ -16,10 +16,10 @@ import { apiRoute } from './routes/api/index.js';
16
16
  import { authRoute } from './routes/auth.js';
17
17
  import { registerConfigRoute } from './routes/config.js';
18
18
  import { eventRoute } from './routes/event.js';
19
- import { healthRoute } from './routes/health.js';
20
19
  import { keysRoute } from './routes/keys.js';
21
20
  import { pathRoute } from './routes/path/index.js';
22
21
  import { staticRoutes } from './routes/static.js';
22
+ import { statusRoutes } from './routes/status.js';
23
23
  import { initDiagramCache } from './services/diagramCache.js';
24
24
  import { startQueueProcessor } from './services/eventQueue.js';
25
25
  import { initExportCache } from './services/exportCache.js';
@@ -44,8 +44,8 @@ async function start() {
44
44
 
45
45
  // Register routes
46
46
  await fastify.register(staticRoutes);
47
- await fastify.register(healthRoute);
48
47
  registerConfigRoute(fastify);
48
+ await fastify.register(statusRoutes);
49
49
  await fastify.register(authRoute);
50
50
  await fastify.register(keysRoute);
51
51
  await fastify.register(eventRoute);
@@ -85,15 +85,17 @@ async function start() {
85
85
  // Start queue processor
86
86
  startQueueProcessor();
87
87
 
88
- await fastify.listen({ port: config.port, host: '0.0.0.0' });
89
- console.log(`Jeeves server listening on port ${String(config.port)}`);
88
+ await fastify.listen({ port: config.port, host: config.host });
89
+ console.log(
90
+ `Jeeves server listening on ${config.host}:${String(config.port)}`,
91
+ );
90
92
  console.log(`Endpoints:`);
91
93
  console.log(` GET /browse/* - File browser SPA`);
92
94
  console.log(` GET /api/raw/* - Raw file serving`);
93
95
  console.log(` GET /api/export/* - PDF/DOCX/ZIP export`);
94
96
  console.log(` POST /event - Event Gateway (key auth)`);
95
97
  console.log(` GET /key - Compute path key (X-API-Key auth)`);
96
- console.log(` GET /health - Health check (no auth)`);
98
+ console.log(` GET /status - Server status (no auth)`);
97
99
  } catch (err) {
98
100
  console.error('Fatal startup error:', err);
99
101
  process.exit(1);
@@ -1,10 +0,0 @@
1
- /**
2
- * Health check endpoint
3
- */
4
- // eslint-disable-next-line @typescript-eslint/require-await
5
- export const healthRoute = async (fastify) => {
6
- // eslint-disable-next-line @typescript-eslint/require-await
7
- fastify.get('/health', async () => {
8
- return { ok: true, uptime: process.uptime() };
9
- });
10
- };
@@ -1,13 +0,0 @@
1
- /**
2
- * Health check endpoint
3
- */
4
-
5
- import type { FastifyPluginAsync } from 'fastify';
6
-
7
- // eslint-disable-next-line @typescript-eslint/require-await
8
- export const healthRoute: FastifyPluginAsync = async (fastify) => {
9
- // eslint-disable-next-line @typescript-eslint/require-await
10
- fastify.get('/health', async () => {
11
- return { ok: true, uptime: process.uptime() };
12
- });
13
- };