@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.
- package/CHANGELOG.md +9 -0
- package/package.json +28 -18
- package/plugin/duckdb-parquet-storage.service.js +199 -104
- package/plugin/index.js +137 -109
- package/public/{chunk-D7VDX7ZF.js → chunk-67V4XHCY.js} +1 -1
- package/public/chunk-BTFZS2TW.js +16 -0
- package/public/{chunk-UYIJND2R.js → chunk-CD5TQSCS.js} +1 -1
- package/public/chunk-FZFDGAQO.js +1 -0
- package/public/{chunk-EDNYYQIZ.js → chunk-I4SJ5UNN.js} +1 -1
- package/public/{chunk-2ICAVOT2.js → chunk-IH4CEW4C.js} +7 -7
- package/public/chunk-ISF5E3CX.js +50 -0
- package/public/{chunk-6XFWUUDD.js → chunk-KQEEYPK3.js} +2 -2
- package/public/chunk-NFJ4RQSE.js +4 -0
- package/public/{chunk-DEM56G4S.js → chunk-OPTBDYBL.js} +1 -1
- package/public/{chunk-YCEXTKGG.js → chunk-P4CRTB7N.js} +1 -1
- package/public/{chunk-IHURI4IH.js → chunk-P7JKENHI.js} +3 -3
- package/public/chunk-Q2ANAJAD.js +1 -0
- package/public/{chunk-B75MT7ND.js → chunk-R36UY4Q4.js} +1 -1
- package/public/{chunk-CHGXAEKT.js → chunk-RCYOZLZB.js} +1 -1
- package/public/{chunk-KPHICV76.js → chunk-SJFJEOSG.js} +1 -1
- package/public/{chunk-MGPPVLZ7.js → chunk-TBNKOU7M.js} +1 -1
- package/public/chunk-TVNXBPFF.js +6 -0
- package/public/{chunk-S72JTJPN.js → chunk-VPF5756E.js} +1 -1
- package/public/chunk-VXCYPAWR.js +1 -0
- package/public/{chunk-DD4F6F4S.js → chunk-VXTTEFRP.js} +8 -8
- package/public/{chunk-R7RQHWKJ.js → chunk-WH5CIUSB.js} +1 -1
- package/public/{chunk-LQDSU4WS.js → chunk-WQSJFJLW.js} +1 -1
- package/public/{chunk-KZ5DUKAX.js → chunk-XBSU7OGT.js} +1 -1
- package/public/{chunk-CEB42O2C.js → chunk-YI3MZWRZ.js} +1 -1
- package/public/index.html +1 -1
- package/public/main-B6TXB3EB.js +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -84
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -35
- package/.github/copilot-instructions.md +0 -218
- package/.github/instructions/angular.instructions.md +0 -123
- package/.github/instructions/best-practices.instructions.md +0 -59
- package/.github/instructions/project.instructions.md +0 -468
- package/.github/workflows/ci.yml +0 -37
- package/docs/widget-schematic.md +0 -102
- package/images/ActionSidenav.png +0 -0
- package/images/ChartplotterMode.png +0 -0
- package/images/KIPDemo.png +0 -0
- package/images/KipBrightness-1024.png +0 -0
- package/images/KipConfig-Units-1024.png +0 -0
- package/images/KipConfig-display-1024x488.png +0 -0
- package/images/KipFreeboard-SK-1024.png +0 -0
- package/images/KipGaugeSample1-1024x545.png +0 -0
- package/images/KipGaugeSample2-1024x488.png +0 -0
- package/images/KipGaugeSample3-1024x508.png +0 -0
- package/images/KipNightMode-1024.png +0 -0
- package/images/KipWidgetConfig-layout-1024.png +0 -0
- package/images/KipWidgetConfig-paths-1024x488.png +0 -0
- package/images/Options.png +0 -0
- package/images/exterior_user_installs.png +0 -0
- package/images/formfactor.png +0 -0
- package/plugin-config-data/kip/historicalData/kip-history.duckdb +0 -0
- package/plugin-config-data/kip/historicalData/parquet/chart-1/1772344583976-1772344583976.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584154-1772344584154.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584191-1772344584191.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584268-1772344584268.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-2/1771502400000-1771502400000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1772344584268-1772344584268.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-4/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-4/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-4/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-5/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-5/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-6/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584191-1772344584191.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584268-1772344584268.parquet +0 -0
- package/public/chunk-A6DQJFP4.js +0 -16
- package/public/chunk-DEGYRCMI.js +0 -1
- package/public/chunk-DYTBBUMI.js +0 -4
- package/public/chunk-FNF7M3AE.js +0 -1
- package/public/chunk-J3LDKVIS.js +0 -50
- package/public/chunk-JB4YVVNW.js +0 -1
- package/public/chunk-YKJKIWXO.js +0 -6
- package/public/main-EG2WF4EO.js +0 -1
- package/tools/schematics/collection.json +0 -9
- package/tools/schematics/create-host2-widget/files/readme/README.md.template +0 -109
- package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +0 -38
- package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +0 -6
- package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +0 -5
- package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +0 -94
- package/tools/schematics/create-host2-widget/index.js +0 -138
- package/tools/schematics/create-host2-widget/schema.json +0 -89
- package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +0 -70
- 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(`
|
|
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(`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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('[
|
|
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('[
|
|
481
|
+
server.debug('[KIP][HISTORY_PROVIDER] registration success provider=kip');
|
|
463
482
|
return;
|
|
464
483
|
}
|
|
465
|
-
server.debug('[
|
|
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(`[
|
|
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(
|
|
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
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
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-
|
|
594
|
-
server.setPluginStatus(`KIP plugin started with
|
|
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
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (
|
|
612
|
-
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
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
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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('[
|
|
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(`
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(`
|
|
821
|
-
server.debug(`
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(`[
|
|
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(`
|
|
1042
|
+
server.debug(`[KIP][ROUTES] registered method=${layer.route.stack[0].method.toUpperCase()} path=${layer.route.path}`);
|
|
1015
1043
|
}
|
|
1016
1044
|
});
|
|
1017
1045
|
}
|