@mxtommy/kip 4.5.0 → 4.5.2

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/package.json +28 -18
  3. package/plugin/duckdb-parquet-storage.service.js +199 -104
  4. package/plugin/index.js +137 -109
  5. package/public/{chunk-D7VDX7ZF.js → chunk-67V4XHCY.js} +1 -1
  6. package/public/chunk-BTFZS2TW.js +16 -0
  7. package/public/{chunk-UYIJND2R.js → chunk-CD5TQSCS.js} +1 -1
  8. package/public/chunk-FZFDGAQO.js +1 -0
  9. package/public/{chunk-EDNYYQIZ.js → chunk-I4SJ5UNN.js} +1 -1
  10. package/public/{chunk-2ICAVOT2.js → chunk-IH4CEW4C.js} +7 -7
  11. package/public/chunk-ISF5E3CX.js +50 -0
  12. package/public/{chunk-6XFWUUDD.js → chunk-KQEEYPK3.js} +2 -2
  13. package/public/chunk-NFJ4RQSE.js +4 -0
  14. package/public/{chunk-DEM56G4S.js → chunk-OPTBDYBL.js} +1 -1
  15. package/public/{chunk-YCEXTKGG.js → chunk-P4CRTB7N.js} +1 -1
  16. package/public/{chunk-IHURI4IH.js → chunk-P7JKENHI.js} +3 -3
  17. package/public/chunk-Q2ANAJAD.js +1 -0
  18. package/public/{chunk-B75MT7ND.js → chunk-R36UY4Q4.js} +1 -1
  19. package/public/{chunk-CHGXAEKT.js → chunk-RCYOZLZB.js} +1 -1
  20. package/public/{chunk-KPHICV76.js → chunk-SJFJEOSG.js} +1 -1
  21. package/public/{chunk-MGPPVLZ7.js → chunk-TBNKOU7M.js} +1 -1
  22. package/public/chunk-TVNXBPFF.js +6 -0
  23. package/public/{chunk-S72JTJPN.js → chunk-VPF5756E.js} +1 -1
  24. package/public/chunk-VXCYPAWR.js +1 -0
  25. package/public/{chunk-DD4F6F4S.js → chunk-VXTTEFRP.js} +8 -8
  26. package/public/{chunk-R7RQHWKJ.js → chunk-WH5CIUSB.js} +1 -1
  27. package/public/{chunk-LQDSU4WS.js → chunk-WQSJFJLW.js} +1 -1
  28. package/public/{chunk-KZ5DUKAX.js → chunk-XBSU7OGT.js} +1 -1
  29. package/public/{chunk-CEB42O2C.js → chunk-YI3MZWRZ.js} +1 -1
  30. package/public/index.html +1 -1
  31. package/public/main-B6TXB3EB.js +1 -0
  32. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -84
  33. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  34. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -35
  35. package/.github/copilot-instructions.md +0 -218
  36. package/.github/instructions/angular.instructions.md +0 -123
  37. package/.github/instructions/best-practices.instructions.md +0 -59
  38. package/.github/instructions/project.instructions.md +0 -468
  39. package/.github/workflows/ci.yml +0 -37
  40. package/docs/widget-schematic.md +0 -102
  41. package/images/ActionSidenav.png +0 -0
  42. package/images/ChartplotterMode.png +0 -0
  43. package/images/KIPDemo.png +0 -0
  44. package/images/KipBrightness-1024.png +0 -0
  45. package/images/KipConfig-Units-1024.png +0 -0
  46. package/images/KipConfig-display-1024x488.png +0 -0
  47. package/images/KipFreeboard-SK-1024.png +0 -0
  48. package/images/KipGaugeSample1-1024x545.png +0 -0
  49. package/images/KipGaugeSample2-1024x488.png +0 -0
  50. package/images/KipGaugeSample3-1024x508.png +0 -0
  51. package/images/KipNightMode-1024.png +0 -0
  52. package/images/KipWidgetConfig-layout-1024.png +0 -0
  53. package/images/KipWidgetConfig-paths-1024x488.png +0 -0
  54. package/images/Options.png +0 -0
  55. package/images/exterior_user_installs.png +0 -0
  56. package/images/formfactor.png +0 -0
  57. package/plugin-config-data/kip/historicalData/kip-history.duckdb +0 -0
  58. package/plugin-config-data/kip/historicalData/parquet/chart-1/1772344583976-1772344583976.parquet +0 -0
  59. package/plugin-config-data/kip/historicalData/parquet/live-1/1771408800000-1771408890000.parquet +0 -0
  60. package/plugin-config-data/kip/historicalData/parquet/live-1/1771412400000-1771412490000.parquet +0 -0
  61. package/plugin-config-data/kip/historicalData/parquet/live-1/1771419600000-1771419650000.parquet +0 -0
  62. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584154-1772344584154.parquet +0 -0
  63. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584191-1772344584191.parquet +0 -0
  64. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584268-1772344584268.parquet +0 -0
  65. package/plugin-config-data/kip/historicalData/parquet/live-2/1771502400000-1771502400000.parquet +0 -0
  66. package/plugin-config-data/kip/historicalData/parquet/live-3/1771408800000-1771408890000.parquet +0 -0
  67. package/plugin-config-data/kip/historicalData/parquet/live-3/1771412400000-1771412490000.parquet +0 -0
  68. package/plugin-config-data/kip/historicalData/parquet/live-3/1771419600000-1771419650000.parquet +0 -0
  69. package/plugin-config-data/kip/historicalData/parquet/live-3/1772344584268-1772344584268.parquet +0 -0
  70. package/plugin-config-data/kip/historicalData/parquet/live-4/1771408800000-1771408890000.parquet +0 -0
  71. package/plugin-config-data/kip/historicalData/parquet/live-4/1771412400000-1771412490000.parquet +0 -0
  72. package/plugin-config-data/kip/historicalData/parquet/live-4/1771419600000-1771419650000.parquet +0 -0
  73. package/plugin-config-data/kip/historicalData/parquet/live-5/1771412400000-1771412490000.parquet +0 -0
  74. package/plugin-config-data/kip/historicalData/parquet/live-5/1771419600000-1771419650000.parquet +0 -0
  75. package/plugin-config-data/kip/historicalData/parquet/live-6/1771419600000-1771419650000.parquet +0 -0
  76. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771408800000-1771408890000.parquet +0 -0
  77. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771412400000-1771412490000.parquet +0 -0
  78. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771419600000-1771419650000.parquet +0 -0
  79. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584191-1772344584191.parquet +0 -0
  80. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584268-1772344584268.parquet +0 -0
  81. package/public/chunk-A6DQJFP4.js +0 -16
  82. package/public/chunk-DEGYRCMI.js +0 -1
  83. package/public/chunk-DYTBBUMI.js +0 -4
  84. package/public/chunk-FNF7M3AE.js +0 -1
  85. package/public/chunk-J3LDKVIS.js +0 -50
  86. package/public/chunk-JB4YVVNW.js +0 -1
  87. package/public/chunk-YKJKIWXO.js +0 -6
  88. package/public/main-EG2WF4EO.js +0 -1
  89. package/tools/schematics/collection.json +0 -9
  90. package/tools/schematics/create-host2-widget/files/readme/README.md.template +0 -109
  91. package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +0 -38
  92. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +0 -6
  93. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +0 -5
  94. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +0 -94
  95. package/tools/schematics/create-host2-widget/index.js +0 -138
  96. package/tools/schematics/create-host2-widget/schema.json +0 -89
  97. package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +0 -70
  98. package/tools/schematics/create-host2-widget/utils/formatting.js +0 -119
package/plugin/index.js CHANGED
@@ -34,10 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const server_api_1 = require("@signalk/server-api");
37
+ const module_1 = require("module");
37
38
  const openapi = __importStar(require("./openApi.json"));
38
39
  const history_series_service_1 = require("./history-series.service");
39
40
  const duckdb_parquet_storage_service_1 = require("./duckdb-parquet-storage.service");
40
41
  const start = (server) => {
42
+ const packageRequire = (0, module_1.createRequire)(__filename);
41
43
  const mutableOpenApi = JSON.parse(JSON.stringify(openapi.default ?? openapi));
42
44
  const API_PATHS = {
43
45
  DISPLAYS: `/displays`,
@@ -84,6 +86,23 @@ const start = (server) => {
84
86
  let historySeriesServiceEnabled = true;
85
87
  let registerAsHistoryApiProvider = true;
86
88
  let historyApiProviderRegistered = false;
89
+ function resolveDependencyIdentity(dependencyName) {
90
+ try {
91
+ const pkg = packageRequire(`${dependencyName}/package.json`);
92
+ const name = typeof pkg.name === 'string' && pkg.name.trim() ? pkg.name.trim() : dependencyName;
93
+ const version = typeof pkg.version === 'string' && pkg.version.trim() ? pkg.version.trim() : 'unknown';
94
+ return `${name}@${version}`;
95
+ }
96
+ catch {
97
+ return `${dependencyName}@unavailable`;
98
+ }
99
+ }
100
+ function logRuntimeDependencyVersions() {
101
+ const nodeIdentity = `node@${process.version}`;
102
+ const duckDbNodeIdentity = resolveDependencyIdentity('@duckdb/node-api');
103
+ const parquetIdentity = resolveDependencyIdentity('@dsnp/parquetjs');
104
+ server.debug(`[KIP][RUNTIME] ${nodeIdentity} duckdb=${duckDbNodeIdentity} parquet=${parquetIdentity}`);
105
+ }
87
106
  function resolveHistoryModeConfig(settings) {
88
107
  const root = (settings && typeof settings === 'object' ? settings : {});
89
108
  const historySeriesServiceEnabledSetting = typeof root.historySeriesServiceEnabled === 'boolean'
@@ -102,12 +121,12 @@ const start = (server) => {
102
121
  const tail = suffix ? `.${suffix}` : '';
103
122
  const want = `displays.${displayId}${tail}`;
104
123
  const full = server.getSelfPath(want);
105
- server.debug(`getDisplaySelfPath: displayId: ${displayId}, suffix: ${suffix}, want=${want}, fullPath=${JSON.stringify(full)}`);
124
+ server.debug(`[KIP][SELF_PATH] displayId=${displayId} suffix=${String(suffix ?? '')} requested=${want} resolved=${JSON.stringify(full)}`);
106
125
  return typeof full === 'object' && full !== null ? full : undefined;
107
126
  }
108
127
  function getAvailableDisplays() {
109
128
  const fullPath = server.getSelfPath('displays');
110
- server.debug(`getAvailableDisplays: fullPath=${JSON.stringify(fullPath)}`);
129
+ server.debug(`[KIP][DISPLAYS] resolved=${JSON.stringify(fullPath)}`);
111
130
  return typeof fullPath === 'object' && fullPath !== null ? fullPath : undefined;
112
131
  }
113
132
  function sendOk(res, body) {
@@ -212,7 +231,7 @@ const start = (server) => {
212
231
  }
213
232
  function applyDisplayWrite(displayId, suffix, value) {
214
233
  const path = suffix ? `displays.${displayId}.${suffix}` : `displays.${displayId}`;
215
- server.debug(`[WRITE TRACE] applyDisplayWrite path=${path} value=${JSON.stringify(value)}`);
234
+ server.debug(`[KIP][WRITE] applyDisplayWrite path=${path} value=${JSON.stringify(value)}`);
216
235
  try {
217
236
  server.handleMessage(plugin.id, {
218
237
  updates: [
@@ -226,7 +245,7 @@ const start = (server) => {
226
245
  }
227
246
  ]
228
247
  }, server_api_1.SKVersion.v1);
229
- server.debug(`[WRITE TRACE] handleMessage success path=${path}`);
248
+ server.debug(`[KIP][WRITE] handleMessage success path=${path}`);
230
249
  return completed(200);
231
250
  }
232
251
  catch (error) {
@@ -236,7 +255,7 @@ const start = (server) => {
236
255
  }
237
256
  }
238
257
  function handleSetDisplay(value) {
239
- server.debug(`[COMMAND TRACE] handleSetDisplay payload=${JSON.stringify(value)}`);
258
+ server.debug(`[KIP][COMMAND] handleSetDisplay payload=${JSON.stringify(value)}`);
240
259
  const command = value;
241
260
  if (!command || typeof command !== 'object') {
242
261
  return completed(400, 'Command payload is required');
@@ -251,7 +270,7 @@ const start = (server) => {
251
270
  return applyDisplayWrite(command.displayId, null, displayValue);
252
271
  }
253
272
  function handleScreenWrite(value, suffix) {
254
- server.debug(`[COMMAND TRACE] handleScreenWrite suffix=${suffix} payload=${JSON.stringify(value)}`);
273
+ server.debug(`[KIP][COMMAND] handleScreenWrite suffix=${suffix} payload=${JSON.stringify(value)}`);
255
274
  const command = value;
256
275
  if (!command || typeof command !== 'object') {
257
276
  return completed(400, 'Command payload is required');
@@ -266,7 +285,7 @@ const start = (server) => {
266
285
  return applyDisplayWrite(command.displayId, suffix, screenIdxValue);
267
286
  }
268
287
  function sendActionAsRest(res, result) {
269
- server.debug(`[REST TRACE] sendActionAsRest statusCode=${result.statusCode} message=${result.message ?? ''}`);
288
+ server.debug(`[KIP][REST] sendActionAsRest statusCode=${result.statusCode} message=${result.message ?? ''}`);
270
289
  if (result.statusCode === 200) {
271
290
  return res.status(200).json({ state: 'SUCCESS', statusCode: 200 });
272
291
  }
@@ -425,7 +444,7 @@ const start = (server) => {
425
444
  function registerHistoryProvider() {
426
445
  historyApiProviderRegistered = false;
427
446
  if (!isHistoryApiProviderEnabled()) {
428
- server.debug('[HISTORY PROVIDER] Registration disabled by plugin configuration');
447
+ server.debug('[KIP][HISTORY_PROVIDER] registration skipped reason=config-disabled');
429
448
  return;
430
449
  }
431
450
  const host = server;
@@ -459,10 +478,10 @@ const start = (server) => {
459
478
  if (typeof registry.unregisterHistoryApiProvider === 'function') {
460
479
  historyApiRegistry = { unregisterHistoryApiProvider: registry.unregisterHistoryApiProvider.bind(registry) };
461
480
  }
462
- server.debug('[HISTORY PROVIDER] Registered KIP as History API provider');
481
+ server.debug('[KIP][HISTORY_PROVIDER] registration success provider=kip');
463
482
  return;
464
483
  }
465
- server.debug('[HISTORY PROVIDER] Registration requested but no compatible registration API was found on server host');
484
+ server.debug('[KIP][HISTORY_PROVIDER] registration skipped reason=api-unavailable');
466
485
  }
467
486
  function rebuildSeriesCaptureSubscriptions() {
468
487
  stopSeriesCapture();
@@ -544,7 +563,7 @@ const start = (server) => {
544
563
  void storageService.flush()
545
564
  .then(result => {
546
565
  if (result.inserted > 0 || result.exported > 0) {
547
- server.debug(`[SERIES STORAGE] flushed inserted=${result.inserted} exported=${result.exported}`);
566
+ server.debug(`[KIP][STORAGE] flush inserted=${result.inserted} exported=${result.exported}`);
548
567
  }
549
568
  })
550
569
  .catch(error => {
@@ -558,108 +577,117 @@ const start = (server) => {
558
577
  name: 'KIP',
559
578
  description: 'KIP server plugin',
560
579
  start: (settings) => {
561
- server.debug(`Starting plugin with settings: ${JSON.stringify(settings)}`);
580
+ server.debug('[KIP][LIFECYCLE] start');
581
+ logRuntimeDependencyVersions();
562
582
  const modeConfig = resolveHistoryModeConfig(settings);
563
583
  historySeriesServiceEnabled = modeConfig.historySeriesServiceEnabled;
564
584
  registerAsHistoryApiProvider = modeConfig.registerAsHistoryApiProvider;
565
585
  logOperationalMode('start-configured');
566
- storageService.setLogger({
567
- debug: (msg) => server.debug(msg),
568
- error: (msg) => server.error(msg)
569
- });
570
- const storageConfig = storageService.configure(settings);
571
- server.debug(`[SERIES STORAGE] engine=${storageConfig.engine} db=${storageConfig.databaseFile} parquetDir=${storageConfig.parquetDirectory} flushMs=${storageConfig.flushIntervalMs}`);
572
- historySeries.setSampleSink(sample => {
573
- storageService.enqueueSample(sample);
574
- });
575
- duckDbInitializationPromise = storageService.initialize();
576
- void duckDbInitializationPromise.then((ready) => {
577
- server.debug(`[SERIES STORAGE] duckdbReady=${ready}`);
578
- if (ready && storageService.isDuckDbParquetEnabled()) {
579
- if (isHistorySeriesServiceEnabled()) {
580
- void storageService.getSeriesDefinitions()
581
- .then((storedSeries) => {
582
- if (storedSeries.length > 0) {
583
- historySeries.reconcileSeries(storedSeries);
584
- rebuildSeriesCaptureSubscriptions();
585
- }
586
- startStorageFlushTimer(storageConfig.flushIntervalMs);
587
- logOperationalMode('duckdb-ready');
588
- server.setPluginStatus(`KIP plugin started with DuckDB/Parquet history storage. Loaded ${storedSeries.length} persisted series. historySeriesServiceEnabled=${isHistorySeriesServiceEnabled()} historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
589
- })
590
- .catch((loadError) => {
591
- server.error(`[SERIES STORAGE] failed to load persisted series: ${String(loadError.message || loadError)}`);
586
+ const needsDuckDb = historySeriesServiceEnabled || registerAsHistoryApiProvider;
587
+ if (needsDuckDb) {
588
+ storageService.setLogger({
589
+ debug: (msg) => server.debug(msg),
590
+ error: (msg) => server.error(msg)
591
+ });
592
+ const storageConfig = storageService.configure();
593
+ server.debug(`[KIP][STORAGE] config engine=${storageConfig.engine} db=${storageConfig.databaseFile} parquetDir=${storageConfig.parquetDirectory} flushMs=${storageConfig.flushIntervalMs} parquetWindowMs=${storageConfig.parquetWindowMs} parquetCompression=${storageConfig.parquetCompression}`);
594
+ historySeries.setSampleSink(sample => {
595
+ storageService.enqueueSample(sample);
596
+ });
597
+ duckDbInitializationPromise = storageService.initialize();
598
+ void duckDbInitializationPromise.then((ready) => {
599
+ server.debug(`[KIP][STORAGE] duckdbReady=${ready}`);
600
+ if (ready && storageService.isDuckDbParquetEnabled()) {
601
+ if (isHistorySeriesServiceEnabled()) {
602
+ void storageService.getSeriesDefinitions()
603
+ .then((storedSeries) => {
604
+ if (storedSeries.length > 0) {
605
+ historySeries.reconcileSeries(storedSeries);
606
+ rebuildSeriesCaptureSubscriptions();
607
+ }
608
+ startStorageFlushTimer(storageConfig.flushIntervalMs);
609
+ logOperationalMode('duckdb-ready');
610
+ server.setPluginStatus(`KIP plugin started with DuckDB/Parquet history storage. Loaded ${storedSeries.length} persisted series. historySeriesServiceEnabled=${isHistorySeriesServiceEnabled()} historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
611
+ })
612
+ .catch((loadError) => {
613
+ server.error(`[SERIES STORAGE] failed to load persisted series: ${String(loadError.message || loadError)}`);
614
+ startStorageFlushTimer(storageConfig.flushIntervalMs);
615
+ logOperationalMode('duckdb-ready-series-load-failed');
616
+ server.setPluginStatus(`KIP plugin started with DuckDB/Parquet history storage. historySeriesServiceEnabled=${isHistorySeriesServiceEnabled()} historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
617
+ });
618
+ }
619
+ else {
620
+ historySeries.reconcileSeries([]);
621
+ stopSeriesCapture();
592
622
  startStorageFlushTimer(storageConfig.flushIntervalMs);
593
- logOperationalMode('duckdb-ready-series-load-failed');
594
- server.setPluginStatus(`KIP plugin started with DuckDB/Parquet history storage. historySeriesServiceEnabled=${isHistorySeriesServiceEnabled()} historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
595
- });
623
+ logOperationalMode('duckdb-ready-series-disabled');
624
+ server.setPluginStatus(`KIP plugin started with history-series service disabled. historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
625
+ }
626
+ return;
596
627
  }
597
- else {
598
- historySeries.reconcileSeries([]);
599
- stopSeriesCapture();
600
- startStorageFlushTimer(storageConfig.flushIntervalMs);
601
- logOperationalMode('duckdb-ready-series-disabled');
602
- server.setPluginStatus(`KIP plugin started with history-series service disabled. historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
628
+ if (storageFlushTimer) {
629
+ clearInterval(storageFlushTimer);
630
+ storageFlushTimer = null;
603
631
  }
604
- return;
605
- }
606
- if (storageFlushTimer) {
607
- clearInterval(storageFlushTimer);
608
- storageFlushTimer = null;
609
- }
610
- const initError = storageService.getLastInitError();
611
- if (initError) {
612
- server.setPluginError(`DuckDB unavailable. ${initError}`);
613
- logOperationalMode('duckdb-unavailable');
614
- server.setPluginStatus(`KIP plugin started with DuckDB unavailable. historySeriesServiceEnabled=${isHistorySeriesServiceEnabled()} historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
632
+ const initError = storageService.getLastInitError();
633
+ if (initError) {
634
+ server.setPluginError(`DuckDB unavailable. ${initError}`);
635
+ logOperationalMode('duckdb-unavailable');
636
+ server.setPluginStatus(`KIP plugin started with DuckDB unavailable. historySeriesServiceEnabled=${isHistorySeriesServiceEnabled()} historyApiProviderEnabled=${isHistoryApiProviderEnabled()} historyApiProviderRegistered=${historyApiProviderRegistered}`);
637
+ }
638
+ });
639
+ if (retentionSweepTimer) {
640
+ clearInterval(retentionSweepTimer);
615
641
  }
616
- });
617
- if (retentionSweepTimer) {
618
- clearInterval(retentionSweepTimer);
619
- }
620
- retentionSweepTimer = setInterval(() => {
621
- try {
622
- if (storageService.isDuckDbParquetReady()) {
623
- const lifecycleToken = storageService.getLifecycleToken();
624
- void storageService.pruneExpiredSamples(Date.now(), lifecycleToken)
625
- .then(removedPersistedRows => {
626
- if (removedPersistedRows > 0) {
627
- server.debug(`[SERIES RETENTION] duckdbPrune removedRows=${removedPersistedRows}`);
628
- }
629
- return storageService.pruneOrphanedSamples(lifecycleToken)
630
- .then(removedOrphanRows => {
631
- if (removedOrphanRows > 0) {
632
- server.debug(`[SERIES RETENTION] duckdbOrphanPrune removedRows=${removedOrphanRows}`);
642
+ retentionSweepTimer = setInterval(() => {
643
+ try {
644
+ if (storageService.isDuckDbParquetReady()) {
645
+ const lifecycleToken = storageService.getLifecycleToken();
646
+ void storageService.pruneExpiredSamples(Date.now(), lifecycleToken)
647
+ .then(removedPersistedRows => {
648
+ if (removedPersistedRows > 0) {
649
+ server.debug(`[KIP][RETENTION] pruneExpired removedRows=${removedPersistedRows}`);
633
650
  }
651
+ return storageService.pruneOrphanedSamples(lifecycleToken)
652
+ .then(removedOrphanRows => {
653
+ if (removedOrphanRows > 0) {
654
+ server.debug(`[KIP][RETENTION] pruneOrphaned removedRows=${removedOrphanRows}`);
655
+ }
656
+ });
657
+ })
658
+ .catch(error => {
659
+ server.error(`[SERIES RETENTION] duckdbPrune failed: ${String(error.message || error)}`);
634
660
  });
635
- })
636
- .catch(error => {
637
- server.error(`[SERIES RETENTION] duckdbPrune failed: ${String(error.message || error)}`);
638
- });
661
+ }
639
662
  }
640
- }
641
- catch (error) {
642
- server.error(`[SERIES RETENTION] sweep failed: ${String(error.message || error)}`);
643
- }
644
- }, 60 * 60_000);
645
- retentionSweepTimer.unref?.();
646
- rebuildSeriesCaptureSubscriptions();
663
+ catch (error) {
664
+ server.error(`[SERIES RETENTION] sweep failed: ${String(error.message || error)}`);
665
+ }
666
+ }, 60 * 60_000);
667
+ retentionSweepTimer.unref?.();
668
+ rebuildSeriesCaptureSubscriptions();
669
+ }
670
+ else {
671
+ server.debug('[KIP][STORAGE] duckdb init skipped reason=config-disabled');
672
+ duckDbInitializationPromise = null;
673
+ stopSeriesCapture();
674
+ }
647
675
  if (server.registerPutHandler) {
648
- server.debug(`[COMMAND TRACE] Registering PUT handlers under context=${PUT_CONTEXT}`);
676
+ server.debug(`[KIP][COMMAND] registerPutHandlers context=${PUT_CONTEXT}`);
649
677
  server.registerPutHandler(PUT_CONTEXT, COMMAND_PATHS.SET_DISPLAY, (context, path, value) => {
650
- server.debug(`[COMMAND TRACE] PUT handler hit path=${String(path)} context=${String(context)} command=${COMMAND_PATHS.SET_DISPLAY}`);
678
+ server.debug(`[KIP][COMMAND] putHandlerHit command=${COMMAND_PATHS.SET_DISPLAY} path=${String(path)} context=${String(context)}`);
651
679
  void context;
652
680
  void path;
653
681
  return handleSetDisplay(value);
654
682
  }, plugin.id);
655
683
  server.registerPutHandler(PUT_CONTEXT, COMMAND_PATHS.SET_SCREEN_INDEX, (context, path, value) => {
656
- server.debug(`[COMMAND TRACE] PUT handler hit path=${String(path)} context=${String(context)} command=${COMMAND_PATHS.SET_SCREEN_INDEX}`);
684
+ server.debug(`[KIP][COMMAND] putHandlerHit command=${COMMAND_PATHS.SET_SCREEN_INDEX} path=${String(path)} context=${String(context)}`);
657
685
  void context;
658
686
  void path;
659
687
  return handleScreenWrite(value, 'screenIndex');
660
688
  }, plugin.id);
661
689
  server.registerPutHandler(PUT_CONTEXT, COMMAND_PATHS.REQUEST_ACTIVE_SCREEN, (context, path, value) => {
662
- server.debug(`[COMMAND TRACE] PUT handler hit path=${String(path)} context=${String(context)} command=${COMMAND_PATHS.REQUEST_ACTIVE_SCREEN}`);
690
+ server.debug(`[KIP][COMMAND] putHandlerHit command=${COMMAND_PATHS.REQUEST_ACTIVE_SCREEN} path=${String(path)} context=${String(context)}`);
663
691
  void context;
664
692
  void path;
665
693
  return handleScreenWrite(value, 'activeScreen');
@@ -670,7 +698,7 @@ const start = (server) => {
670
698
  server.setPluginStatus(`Starting...`);
671
699
  },
672
700
  stop: () => {
673
- server.debug(`Stopping plugin`);
701
+ server.debug('[KIP][LIFECYCLE] stop');
674
702
  stopSeriesCapture();
675
703
  if (retentionSweepTimer) {
676
704
  clearInterval(retentionSweepTimer);
@@ -688,7 +716,7 @@ const start = (server) => {
688
716
  if (historyApiRegistry) {
689
717
  try {
690
718
  historyApiRegistry.unregisterHistoryApiProvider();
691
- server.debug('[HISTORY PROVIDER] Unregistered KIP History API provider');
719
+ server.debug('[KIP][HISTORY_PROVIDER] unregister success provider=kip');
692
720
  }
693
721
  catch (error) {
694
722
  server.error(`[HISTORY PROVIDER] unregister failed: ${String(error.message || error)}`);
@@ -701,7 +729,7 @@ const start = (server) => {
701
729
  },
702
730
  schema: () => CONFIG_SCHEMA,
703
731
  registerWithRouter(router) {
704
- server.debug(`Registering plugin routes: ${API_PATHS.DISPLAYS}, ${API_PATHS.INSTANCE}, ${API_PATHS.SCREEN_INDEX}, ${API_PATHS.ACTIVATE_SCREEN}`);
732
+ server.debug(`[KIP][ROUTES] register displays=${API_PATHS.DISPLAYS} instance=${API_PATHS.INSTANCE} screenIndex=${API_PATHS.SCREEN_INDEX} activeScreen=${API_PATHS.ACTIVATE_SCREEN}`);
705
733
  // Validate/normalize :displayId where present
706
734
  router.param('displayId', (req, res, next, displayId) => {
707
735
  logAuthTrace(req, 'router.param:displayId:entry');
@@ -736,7 +764,7 @@ const start = (server) => {
736
764
  return sendFail(res, 400, 'Invalid displayId format');
737
765
  }
738
766
  req.displayId = id;
739
- server.debug(`[AUTH TRACE] router.param:displayId:normalized displayId=${id}`);
767
+ server.debug(`[KIP][AUTH] displayIdNormalized value=${id}`);
740
768
  next();
741
769
  }
742
770
  catch {
@@ -746,7 +774,7 @@ const start = (server) => {
746
774
  });
747
775
  router.put(`${API_PATHS.INSTANCE}`, async (req, res) => {
748
776
  logAuthTrace(req, 'route:PUT:INSTANCE:entry');
749
- server.debug(`** PUT ${API_PATHS.INSTANCE}. Params: ${JSON.stringify(req.params)} Body: ${JSON.stringify(req.body)}`);
777
+ server.debug(`[KIP][ROUTE] method=PUT path=${API_PATHS.INSTANCE} params=${JSON.stringify(req.params)} body=${JSON.stringify(req.body)}`);
750
778
  try {
751
779
  const displayId = req.displayId;
752
780
  if (!displayId) {
@@ -764,7 +792,7 @@ const start = (server) => {
764
792
  });
765
793
  router.put(`${API_PATHS.SCREEN_INDEX}`, async (req, res) => {
766
794
  logAuthTrace(req, 'route:PUT:SCREEN_INDEX:entry');
767
- server.debug(`** PUT ${API_PATHS.SCREEN_INDEX}. Params: ${JSON.stringify(req.params)} Body: ${JSON.stringify(req.body)}`);
795
+ server.debug(`[KIP][ROUTE] method=PUT path=${API_PATHS.SCREEN_INDEX} params=${JSON.stringify(req.params)} body=${JSON.stringify(req.body)}`);
768
796
  try {
769
797
  const displayId = req.displayId;
770
798
  if (!displayId) {
@@ -785,7 +813,7 @@ const start = (server) => {
785
813
  });
786
814
  router.put(`${API_PATHS.ACTIVATE_SCREEN}`, async (req, res) => {
787
815
  logAuthTrace(req, 'route:PUT:ACTIVATE_SCREEN:entry');
788
- server.debug(`** PUT ${API_PATHS.ACTIVATE_SCREEN}. Params: ${JSON.stringify(req.params)} Body: ${JSON.stringify(req.body)}`);
816
+ server.debug(`[KIP][ROUTE] method=PUT path=${API_PATHS.ACTIVATE_SCREEN} params=${JSON.stringify(req.params)} body=${JSON.stringify(req.body)}`);
789
817
  try {
790
818
  const displayId = req.displayId;
791
819
  if (!displayId) {
@@ -805,7 +833,7 @@ const start = (server) => {
805
833
  }
806
834
  });
807
835
  router.get(API_PATHS.DISPLAYS, (req, res) => {
808
- server.debug(`*** GET DISPLAY ${API_PATHS.DISPLAYS}. Params: ${JSON.stringify(req.params)}`);
836
+ server.debug(`[KIP][ROUTE] method=GET path=${API_PATHS.DISPLAYS} params=${JSON.stringify(req.params)}`);
809
837
  try {
810
838
  const displays = getAvailableDisplays();
811
839
  const items = displays && typeof displays === 'object'
@@ -817,8 +845,8 @@ const start = (server) => {
817
845
  displayName: v?.value?.displayName ?? null
818
846
  }))
819
847
  : [];
820
- server.debug(`getAvailableDisplays returned: ${JSON.stringify(displays)}`);
821
- server.debug(`Found ${items.length} displays: ${JSON.stringify(items)}`);
848
+ server.debug(`[KIP][DISPLAYS] raw=${JSON.stringify(displays)}`);
849
+ server.debug(`[KIP][DISPLAYS] count=${items.length} items=${JSON.stringify(items)}`);
822
850
  return res.status(200).json(items);
823
851
  }
824
852
  catch (error) {
@@ -827,7 +855,7 @@ const start = (server) => {
827
855
  }
828
856
  });
829
857
  router.get(`${API_PATHS.INSTANCE}`, (req, res) => {
830
- server.debug(`*** GET INSTANCE ${API_PATHS.INSTANCE}. Params: ${JSON.stringify(req.params)}`);
858
+ server.debug(`[KIP][ROUTE] method=GET path=${API_PATHS.INSTANCE} params=${JSON.stringify(req.params)}`);
831
859
  try {
832
860
  const displayId = req.displayId;
833
861
  if (!displayId) {
@@ -847,7 +875,7 @@ const start = (server) => {
847
875
  }
848
876
  });
849
877
  router.get(`${API_PATHS.SCREEN_INDEX}`, (req, res) => {
850
- server.debug(`*** GET SCREEN_INDEX ${API_PATHS.SCREEN_INDEX}. Params: ${JSON.stringify(req.params)}`);
878
+ server.debug(`[KIP][ROUTE] method=GET path=${API_PATHS.SCREEN_INDEX} params=${JSON.stringify(req.params)}`);
851
879
  try {
852
880
  const displayId = req.displayId;
853
881
  if (!displayId) {
@@ -867,7 +895,7 @@ const start = (server) => {
867
895
  }
868
896
  });
869
897
  router.get(`${API_PATHS.ACTIVATE_SCREEN}`, (req, res) => {
870
- server.debug(`*** GET ACTIVATE_SCREEN ${API_PATHS.ACTIVATE_SCREEN}. Params: ${JSON.stringify(req.params)}`);
898
+ server.debug(`[KIP][ROUTE] method=GET path=${API_PATHS.ACTIVATE_SCREEN} params=${JSON.stringify(req.params)}`);
871
899
  try {
872
900
  const displayId = req.displayId;
873
901
  if (!displayId) {
@@ -887,7 +915,7 @@ const start = (server) => {
887
915
  }
888
916
  });
889
917
  router.get(API_PATHS.SERIES, async (req, res) => {
890
- server.debug(`*** GET SERIES ${API_PATHS.SERIES}. Params: ${JSON.stringify(req.params)}`);
918
+ server.debug(`[KIP][ROUTE] method=GET path=${API_PATHS.SERIES} params=${JSON.stringify(req.params)}`);
891
919
  try {
892
920
  if (!ensureHistorySeriesServiceEnabledForRequest(res)) {
893
921
  return;
@@ -904,7 +932,7 @@ const start = (server) => {
904
932
  }
905
933
  });
906
934
  router.put(API_PATHS.SERIES_INSTANCE, async (req, res) => {
907
- server.debug(`** PUT ${API_PATHS.SERIES_INSTANCE}. Params: ${JSON.stringify(req.params)} Body: ${JSON.stringify(req.body)}`);
935
+ server.debug(`[KIP][ROUTE] method=PUT path=${API_PATHS.SERIES_INSTANCE} params=${JSON.stringify(req.params)} body=${JSON.stringify(req.body)}`);
908
936
  try {
909
937
  if (!ensureHistorySeriesServiceEnabledForRequest(res)) {
910
938
  return;
@@ -945,7 +973,7 @@ const start = (server) => {
945
973
  }
946
974
  });
947
975
  router.delete(API_PATHS.SERIES_INSTANCE, async (req, res) => {
948
- server.debug(`** DELETE ${API_PATHS.SERIES_INSTANCE}. Params: ${JSON.stringify(req.params)}`);
976
+ server.debug(`[KIP][ROUTE] method=DELETE path=${API_PATHS.SERIES_INSTANCE} params=${JSON.stringify(req.params)}`);
949
977
  try {
950
978
  if (!ensureHistorySeriesServiceEnabledForRequest(res)) {
951
979
  return;
@@ -973,7 +1001,7 @@ const start = (server) => {
973
1001
  }
974
1002
  });
975
1003
  router.post(API_PATHS.SERIES_RECONCILE, async (req, res) => {
976
- server.debug(`** POST ${API_PATHS.SERIES_RECONCILE}. Body: ${JSON.stringify(req.body)}`);
1004
+ server.debug(`[KIP][ROUTE] method=POST path=${API_PATHS.SERIES_RECONCILE} body=${JSON.stringify(req.body)}`);
977
1005
  try {
978
1006
  if (!ensureHistorySeriesServiceEnabledForRequest(res)) {
979
1007
  return;
@@ -997,7 +1025,7 @@ const start = (server) => {
997
1025
  await storageService.replaceSeriesDefinitions(nextSeries);
998
1026
  const seriesOutsideScope = historySeries.listSeries();
999
1027
  historySeries.reconcileSeries([...seriesOutsideScope, ...nextSeries]);
1000
- server.debug(`[SERIES RECONCILE] created=${result.created} updated=${result.updated} deleted=${result.deleted} total=${result.total}`);
1028
+ server.debug(`[KIP][SERIES_RECONCILE] created=${result.created} updated=${result.updated} deleted=${result.deleted} total=${result.total}`);
1001
1029
  rebuildSeriesCaptureSubscriptions();
1002
1030
  return sendOk(res, result);
1003
1031
  }
@@ -1011,7 +1039,7 @@ const start = (server) => {
1011
1039
  if (router.stack) {
1012
1040
  router.stack.forEach((layer) => {
1013
1041
  if (layer.route && layer.route.path) {
1014
- server.debug(`Registered route: ${layer.route.stack[0].method.toUpperCase()} ${layer.route.path}`);
1042
+ server.debug(`[KIP][ROUTES] registered method=${layer.route.stack[0].method.toUpperCase()} path=${layer.route.path}`);
1015
1043
  }
1016
1044
  });
1017
1045
  }