@karmaniverous/jeeves-meta 0.5.0 → 0.6.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.
@@ -2943,15 +2943,39 @@ async function checkDependency(url, path) {
2943
2943
  return { url, status: 'unreachable', checkedAt };
2944
2944
  }
2945
2945
  }
2946
+ /** Check watcher, surfacing initialScan.active as indexing state. */
2947
+ async function checkWatcher(url) {
2948
+ const checkedAt = new Date().toISOString();
2949
+ try {
2950
+ const res = await fetch(new URL('/status', url), {
2951
+ signal: AbortSignal.timeout(3000),
2952
+ });
2953
+ if (!res.ok)
2954
+ return { url, status: 'error', checkedAt };
2955
+ const data = (await res.json());
2956
+ const indexing = data.initialScan?.active === true;
2957
+ return {
2958
+ url,
2959
+ status: indexing ? 'indexing' : 'ok',
2960
+ checkedAt,
2961
+ indexing,
2962
+ };
2963
+ }
2964
+ catch {
2965
+ return { url, status: 'unreachable', checkedAt };
2966
+ }
2967
+ }
2946
2968
  function registerStatusRoute(app, deps) {
2947
2969
  app.get('/status', async () => {
2948
2970
  const { config, queue, scheduler, stats } = deps;
2949
2971
  // On-demand dependency checks
2950
2972
  const [watcherHealth, gatewayHealth] = await Promise.all([
2951
- checkDependency(config.watcherUrl, '/status'),
2973
+ checkWatcher(config.watcherUrl),
2952
2974
  checkDependency(config.gatewayUrl, '/api/status'),
2953
2975
  ]);
2954
- const degraded = watcherHealth.status !== 'ok' || gatewayHealth.status !== 'ok';
2976
+ const degraded = (watcherHealth.status !== 'ok' && watcherHealth.status !== 'indexing') ||
2977
+ gatewayHealth.status !== 'ok';
2978
+ const indexing = watcherHealth.status === 'indexing';
2955
2979
  // Determine status
2956
2980
  let status;
2957
2981
  if (deps.shuttingDown) {
@@ -2963,6 +2987,9 @@ function registerStatusRoute(app, deps) {
2963
2987
  else if (degraded) {
2964
2988
  status = 'degraded';
2965
2989
  }
2990
+ else if (indexing) {
2991
+ status = 'waiting';
2992
+ }
2966
2993
  else {
2967
2994
  status = 'idle';
2968
2995
  }
@@ -3357,14 +3384,7 @@ function createServer(options) {
3357
3384
  const app = Fastify({
3358
3385
  loggerInstance: options.logger,
3359
3386
  });
3360
- registerRoutes(app, {
3361
- config: options.config,
3362
- logger: options.logger,
3363
- queue: options.queue,
3364
- watcher: options.watcher,
3365
- scheduler: options.scheduler,
3366
- stats: options.stats,
3367
- });
3387
+ registerRoutes(app, options.deps);
3368
3388
  return app;
3369
3389
  }
3370
3390
 
@@ -3553,6 +3573,12 @@ class WatcherHealthCheck {
3553
3573
  return;
3554
3574
  }
3555
3575
  const data = (await res.json());
3576
+ // If rules were never successfully registered (startup failure),
3577
+ // attempt registration now that the watcher is reachable.
3578
+ if (!this.registrar.isRegistered) {
3579
+ this.logger.info('Rules not registered — attempting registration');
3580
+ await this.registrar.register();
3581
+ }
3556
3582
  await this.registrar.checkAndReregister(data.uptime);
3557
3583
  }
3558
3584
  catch (err) {
@@ -3607,11 +3633,7 @@ async function startService(config, configPath) {
3607
3633
  };
3608
3634
  const server = createServer({
3609
3635
  logger,
3610
- config,
3611
- queue,
3612
- watcher,
3613
- scheduler,
3614
- stats,
3636
+ deps: routeDeps,
3615
3637
  });
3616
3638
  // Start HTTP server
3617
3639
  try {
package/dist/index.d.ts CHANGED
@@ -1310,16 +1310,8 @@ declare function sleep(ms: number): Promise<void>;
1310
1310
  interface ServerOptions {
1311
1311
  /** Pino logger instance. */
1312
1312
  logger: Logger;
1313
- /** Synthesis queue instance. */
1314
- queue: SynthesisQueue;
1315
- /** Validated service configuration. */
1316
- config: ServiceConfig;
1317
- /** Watcher client for data queries. */
1318
- watcher: HttpWatcherClient;
1319
- /** Scheduler instance (null during tests). */
1320
- scheduler: Scheduler | null;
1321
- /** Mutable runtime stats. */
1322
- stats: ServiceStats;
1313
+ /** Shared route dependencies (mutable — late-bound properties like registrar are set after creation). */
1314
+ deps: RouteDeps;
1323
1315
  }
1324
1316
  /**
1325
1317
  * Create and configure the Fastify server.
package/dist/index.js CHANGED
@@ -2939,15 +2939,39 @@ async function checkDependency(url, path) {
2939
2939
  return { url, status: 'unreachable', checkedAt };
2940
2940
  }
2941
2941
  }
2942
+ /** Check watcher, surfacing initialScan.active as indexing state. */
2943
+ async function checkWatcher(url) {
2944
+ const checkedAt = new Date().toISOString();
2945
+ try {
2946
+ const res = await fetch(new URL('/status', url), {
2947
+ signal: AbortSignal.timeout(3000),
2948
+ });
2949
+ if (!res.ok)
2950
+ return { url, status: 'error', checkedAt };
2951
+ const data = (await res.json());
2952
+ const indexing = data.initialScan?.active === true;
2953
+ return {
2954
+ url,
2955
+ status: indexing ? 'indexing' : 'ok',
2956
+ checkedAt,
2957
+ indexing,
2958
+ };
2959
+ }
2960
+ catch {
2961
+ return { url, status: 'unreachable', checkedAt };
2962
+ }
2963
+ }
2942
2964
  function registerStatusRoute(app, deps) {
2943
2965
  app.get('/status', async () => {
2944
2966
  const { config, queue, scheduler, stats } = deps;
2945
2967
  // On-demand dependency checks
2946
2968
  const [watcherHealth, gatewayHealth] = await Promise.all([
2947
- checkDependency(config.watcherUrl, '/status'),
2969
+ checkWatcher(config.watcherUrl),
2948
2970
  checkDependency(config.gatewayUrl, '/api/status'),
2949
2971
  ]);
2950
- const degraded = watcherHealth.status !== 'ok' || gatewayHealth.status !== 'ok';
2972
+ const degraded = (watcherHealth.status !== 'ok' && watcherHealth.status !== 'indexing') ||
2973
+ gatewayHealth.status !== 'ok';
2974
+ const indexing = watcherHealth.status === 'indexing';
2951
2975
  // Determine status
2952
2976
  let status;
2953
2977
  if (deps.shuttingDown) {
@@ -2959,6 +2983,9 @@ function registerStatusRoute(app, deps) {
2959
2983
  else if (degraded) {
2960
2984
  status = 'degraded';
2961
2985
  }
2986
+ else if (indexing) {
2987
+ status = 'waiting';
2988
+ }
2962
2989
  else {
2963
2990
  status = 'idle';
2964
2991
  }
@@ -3353,14 +3380,7 @@ function createServer(options) {
3353
3380
  const app = Fastify({
3354
3381
  loggerInstance: options.logger,
3355
3382
  });
3356
- registerRoutes(app, {
3357
- config: options.config,
3358
- logger: options.logger,
3359
- queue: options.queue,
3360
- watcher: options.watcher,
3361
- scheduler: options.scheduler,
3362
- stats: options.stats,
3363
- });
3383
+ registerRoutes(app, options.deps);
3364
3384
  return app;
3365
3385
  }
3366
3386
 
@@ -3549,6 +3569,12 @@ class WatcherHealthCheck {
3549
3569
  return;
3550
3570
  }
3551
3571
  const data = (await res.json());
3572
+ // If rules were never successfully registered (startup failure),
3573
+ // attempt registration now that the watcher is reachable.
3574
+ if (!this.registrar.isRegistered) {
3575
+ this.logger.info('Rules not registered — attempting registration');
3576
+ await this.registrar.register();
3577
+ }
3552
3578
  await this.registrar.checkAndReregister(data.uptime);
3553
3579
  }
3554
3580
  catch (err) {
@@ -3603,11 +3629,7 @@ async function startService(config, configPath) {
3603
3629
  };
3604
3630
  const server = createServer({
3605
3631
  logger,
3606
- config,
3607
- queue,
3608
- watcher,
3609
- scheduler,
3610
- stats,
3632
+ deps: routeDeps,
3611
3633
  });
3612
3634
  // Start HTTP server
3613
3635
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/jeeves-meta",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "author": "Jason Williscroft",
5
5
  "description": "Fastify HTTP service for the Jeeves Meta synthesis engine",
6
6
  "license": "BSD-3-Clause",
@@ -43,24 +43,27 @@
43
43
  "dependencies": {
44
44
  "commander": "^14",
45
45
  "croner": "^10",
46
- "fastify": "^5.7",
46
+ "fastify": "^5.8",
47
47
  "package-directory": "^8.2.0",
48
48
  "pino": "^10",
49
49
  "zod": "^4.3"
50
50
  },
51
51
  "devDependencies": {
52
+ "@dotenvx/dotenvx": "^1.55.1",
52
53
  "@rollup/plugin-commonjs": "^29.0.2",
53
54
  "@rollup/plugin-json": "^6.1.0",
54
55
  "@rollup/plugin-node-resolve": "^16.0.3",
55
56
  "@rollup/plugin-typescript": "^12.3.0",
56
- "@types/node": "^25.3.5",
57
- "@vitest/coverage-v8": "^4.0.18",
57
+ "@types/node": "^25.5.0",
58
+ "@vitest/coverage-v8": "^4.1.0",
59
+ "auto-changelog": "^2.5.0",
58
60
  "cross-env": "^10.1.0",
59
- "knip": "^5.85.0",
61
+ "knip": "^5.87.0",
62
+ "release-it": "^19.2.4",
60
63
  "rollup": "^4.59.0",
61
- "rollup-plugin-dts": "^6.3.0",
64
+ "rollup-plugin-dts": "^6.4.0",
62
65
  "tslib": "^2.8.1",
63
- "vitest": "^4.0.18"
66
+ "vitest": "^4.1.0"
64
67
  },
65
68
  "scripts": {
66
69
  "build": "rimraf dist && cross-env NO_COLOR=1 rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
@@ -106,5 +109,12 @@
106
109
  "npm": {
107
110
  "publish": true
108
111
  }
112
+ },
113
+ "auto-changelog": {
114
+ "output": "CHANGELOG.md",
115
+ "tagPrefix": "service/",
116
+ "unreleased": true,
117
+ "commitLimit": false,
118
+ "hideCredit": true
109
119
  }
110
120
  }