@trillboards/edge-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/DeviceIdentity.d.ts +32 -0
  2. package/dist/DeviceIdentity.d.ts.map +1 -0
  3. package/dist/DeviceIdentity.js +131 -0
  4. package/dist/DeviceIdentity.js.map +1 -0
  5. package/dist/DeviceProfile.d.ts +39 -0
  6. package/dist/DeviceProfile.d.ts.map +1 -0
  7. package/dist/DeviceProfile.js +199 -0
  8. package/dist/DeviceProfile.js.map +1 -0
  9. package/dist/ObservationSignalClassifier.d.ts +33 -0
  10. package/dist/ObservationSignalClassifier.d.ts.map +1 -0
  11. package/dist/ObservationSignalClassifier.js +116 -0
  12. package/dist/ObservationSignalClassifier.js.map +1 -0
  13. package/dist/RecoveryLadder.d.ts +58 -0
  14. package/dist/RecoveryLadder.d.ts.map +1 -0
  15. package/dist/RecoveryLadder.js +199 -0
  16. package/dist/RecoveryLadder.js.map +1 -0
  17. package/dist/SensingConfig.d.ts +33 -0
  18. package/dist/SensingConfig.d.ts.map +1 -0
  19. package/dist/SensingConfig.js +179 -0
  20. package/dist/SensingConfig.js.map +1 -0
  21. package/dist/SignalBuffer.d.ts +56 -0
  22. package/dist/SignalBuffer.d.ts.map +1 -0
  23. package/dist/SignalBuffer.js +143 -0
  24. package/dist/SignalBuffer.js.map +1 -0
  25. package/dist/SocketManager.d.ts +73 -0
  26. package/dist/SocketManager.d.ts.map +1 -0
  27. package/dist/SocketManager.js +160 -0
  28. package/dist/SocketManager.js.map +1 -0
  29. package/dist/SubsystemHealthRegistry.d.ts +61 -0
  30. package/dist/SubsystemHealthRegistry.d.ts.map +1 -0
  31. package/dist/SubsystemHealthRegistry.js +230 -0
  32. package/dist/SubsystemHealthRegistry.js.map +1 -0
  33. package/dist/TelemetryScheduler.d.ts +56 -0
  34. package/dist/TelemetryScheduler.d.ts.map +1 -0
  35. package/dist/TelemetryScheduler.js +99 -0
  36. package/dist/TelemetryScheduler.js.map +1 -0
  37. package/dist/VASWeightConfig.d.ts +26 -0
  38. package/dist/VASWeightConfig.d.ts.map +1 -0
  39. package/dist/VASWeightConfig.js +83 -0
  40. package/dist/VASWeightConfig.js.map +1 -0
  41. package/dist/index.d.ts +15 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +44 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/types.d.ts +530 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +96 -0
  48. package/dist/types.js.map +1 -0
  49. package/package.json +40 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * SocketManager — Socket.io client for edge-to-backend communication.
3
+ * Port of AgentSocketManager.kt with same event protocol contract.
4
+ *
5
+ * Events (incoming): privateMessage, deviceCommand, config.push
6
+ * Events (outgoing): audienceSignals, deviceCommandAck, deviceCommandStatus
7
+ * Auth: fingerprint + device_token as query params
8
+ * Reconnection: infinite attempts, 3s initial delay, max 60s
9
+ */
10
+ /// <reference types="node" />
11
+ import { EventEmitter } from 'events';
12
+ import { SensingConfig } from './SensingConfig';
13
+ import { VASWeightConfig } from './VASWeightConfig';
14
+ export interface SocketManagerOptions {
15
+ url: string;
16
+ fingerprint: string;
17
+ deviceToken?: string;
18
+ sensingConfig: SensingConfig;
19
+ vasWeightConfig: VASWeightConfig;
20
+ }
21
+ export interface SocketManagerEvents {
22
+ connect: () => void;
23
+ disconnect: (reason: string) => void;
24
+ error: (error: Error) => void;
25
+ privateMessage: (data: unknown) => void;
26
+ deviceCommand: (data: {
27
+ command: string;
28
+ payload?: unknown;
29
+ commandId?: string;
30
+ }) => void;
31
+ configUpdate: (type: string, payload: unknown) => void;
32
+ }
33
+ export declare class SocketManager extends EventEmitter {
34
+ private socket;
35
+ private readonly url;
36
+ private readonly fingerprint;
37
+ private readonly deviceToken;
38
+ private readonly sensingConfig;
39
+ private readonly vasWeightConfig;
40
+ private connected_;
41
+ constructor(options: SocketManagerOptions);
42
+ /**
43
+ * Connect to the backend Socket.io server.
44
+ * Same auth flow as Kotlin: fingerprint + device_token as query params.
45
+ */
46
+ connect(): void;
47
+ private setupListeners;
48
+ /**
49
+ * Emit an audience signal to the backend.
50
+ * Same event name as Kotlin: "audienceSignals"
51
+ */
52
+ emitAudienceSignal(payload: Record<string, unknown>): boolean;
53
+ /**
54
+ * Emit a heartbeat payload.
55
+ */
56
+ emitHeartbeat(payload: Record<string, unknown>): boolean;
57
+ /**
58
+ * Acknowledge a device command.
59
+ */
60
+ emitCommandAck(commandId: string, status: string): void;
61
+ /**
62
+ * Report device command execution status.
63
+ */
64
+ emitCommandStatus(commandId: string, status: string, result?: unknown): void;
65
+ /**
66
+ * Emit arbitrary event with data.
67
+ */
68
+ emitEvent(event: string, data: unknown): boolean;
69
+ get isConnected(): boolean;
70
+ get socketId(): string | null;
71
+ disconnect(): void;
72
+ }
73
+ //# sourceMappingURL=SocketManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocketManager.d.ts","sourceRoot":"","sources":["../src/SocketManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC9B,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1F,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,oBAAoB;IASzC;;;OAGG;IACH,OAAO,IAAI,IAAI;IAqBf,OAAO,CAAC,cAAc;IA8DtB;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAM7D;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAMxD;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAKvD;;OAEG;IACH,iBAAiB,CACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,GACf,IAAI;IAKP;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO;IAMhD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED,UAAU,IAAI,IAAI;CAOnB"}
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ /**
3
+ * SocketManager — Socket.io client for edge-to-backend communication.
4
+ * Port of AgentSocketManager.kt with same event protocol contract.
5
+ *
6
+ * Events (incoming): privateMessage, deviceCommand, config.push
7
+ * Events (outgoing): audienceSignals, deviceCommandAck, deviceCommandStatus
8
+ * Auth: fingerprint + device_token as query params
9
+ * Reconnection: infinite attempts, 3s initial delay, max 60s
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SocketManager = void 0;
13
+ const socket_io_client_1 = require("socket.io-client");
14
+ const events_1 = require("events");
15
+ class SocketManager extends events_1.EventEmitter {
16
+ constructor(options) {
17
+ super();
18
+ this.socket = null;
19
+ this.connected_ = false;
20
+ this.url = options.url;
21
+ this.fingerprint = options.fingerprint;
22
+ this.deviceToken = options.deviceToken || '';
23
+ this.sensingConfig = options.sensingConfig;
24
+ this.vasWeightConfig = options.vasWeightConfig;
25
+ }
26
+ /**
27
+ * Connect to the backend Socket.io server.
28
+ * Same auth flow as Kotlin: fingerprint + device_token as query params.
29
+ */
30
+ connect() {
31
+ if (this.socket) {
32
+ this.socket.disconnect();
33
+ }
34
+ this.socket = (0, socket_io_client_1.io)(this.url, {
35
+ query: {
36
+ fingerprint: this.fingerprint,
37
+ device_token: this.deviceToken,
38
+ },
39
+ reconnection: true,
40
+ reconnectionAttempts: Infinity,
41
+ reconnectionDelay: 3000,
42
+ reconnectionDelayMax: 60000,
43
+ timeout: 20000,
44
+ transports: ['websocket', 'polling'],
45
+ });
46
+ this.setupListeners();
47
+ }
48
+ setupListeners() {
49
+ if (!this.socket)
50
+ return;
51
+ this.socket.on('connect', () => {
52
+ this.connected_ = true;
53
+ this.emit('connect');
54
+ });
55
+ this.socket.on('disconnect', (reason) => {
56
+ this.connected_ = false;
57
+ this.emit('disconnect', reason);
58
+ });
59
+ this.socket.on('connect_error', (error) => {
60
+ this.emit('error', error);
61
+ });
62
+ // Incoming events — same as Kotlin agent-core
63
+ this.socket.on('privateMessage', (data) => {
64
+ this.emit('privateMessage', data);
65
+ });
66
+ this.socket.on('deviceCommand', (data) => {
67
+ let parsed;
68
+ try {
69
+ parsed = typeof data === 'string' ? JSON.parse(data) : data;
70
+ }
71
+ catch {
72
+ this.emit('error', new Error(`Invalid JSON in deviceCommand: ${String(data).slice(0, 200)}`));
73
+ return;
74
+ }
75
+ this.emit('deviceCommand', parsed);
76
+ });
77
+ // Config push — hot-reload sensing config and VAS weights
78
+ this.socket.on('config.push', (data) => {
79
+ let parsed;
80
+ try {
81
+ parsed = typeof data === 'string' ? JSON.parse(data) : data;
82
+ }
83
+ catch {
84
+ this.emit('error', new Error(`Invalid JSON in config.push: ${String(data).slice(0, 200)}`));
85
+ return;
86
+ }
87
+ if (typeof parsed === 'object' && parsed !== null) {
88
+ const configData = parsed;
89
+ const type = configData.type || '';
90
+ const payload = configData.payload || parsed;
91
+ if (type === 'sensing_config_update' && typeof payload === 'object') {
92
+ this.sensingConfig.mergeWithServerUpdate(payload);
93
+ }
94
+ else if (type === 'vas_weights_update' && typeof payload === 'object') {
95
+ this.vasWeightConfig.updateFromJSON(payload);
96
+ }
97
+ this.emit('configUpdate', type, payload);
98
+ }
99
+ });
100
+ }
101
+ /**
102
+ * Emit an audience signal to the backend.
103
+ * Same event name as Kotlin: "audienceSignals"
104
+ */
105
+ emitAudienceSignal(payload) {
106
+ if (!this.socket || !this.connected_)
107
+ return false;
108
+ this.socket.emit('audienceSignals', payload);
109
+ return true;
110
+ }
111
+ /**
112
+ * Emit a heartbeat payload.
113
+ */
114
+ emitHeartbeat(payload) {
115
+ if (!this.socket || !this.connected_)
116
+ return false;
117
+ this.socket.emit('heartbeat', payload);
118
+ return true;
119
+ }
120
+ /**
121
+ * Acknowledge a device command.
122
+ */
123
+ emitCommandAck(commandId, status) {
124
+ if (!this.socket || !this.connected_)
125
+ return;
126
+ this.socket.emit('deviceCommandAck', { commandId, status });
127
+ }
128
+ /**
129
+ * Report device command execution status.
130
+ */
131
+ emitCommandStatus(commandId, status, result) {
132
+ if (!this.socket || !this.connected_)
133
+ return;
134
+ this.socket.emit('deviceCommandStatus', { commandId, status, result });
135
+ }
136
+ /**
137
+ * Emit arbitrary event with data.
138
+ */
139
+ emitEvent(event, data) {
140
+ if (!this.socket || !this.connected_)
141
+ return false;
142
+ this.socket.emit(event, data);
143
+ return true;
144
+ }
145
+ get isConnected() {
146
+ return this.connected_;
147
+ }
148
+ get socketId() {
149
+ return this.socket?.id || null;
150
+ }
151
+ disconnect() {
152
+ if (this.socket) {
153
+ this.socket.disconnect();
154
+ this.socket = null;
155
+ this.connected_ = false;
156
+ }
157
+ }
158
+ }
159
+ exports.SocketManager = SocketManager;
160
+ //# sourceMappingURL=SocketManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocketManager.js","sourceRoot":"","sources":["../src/SocketManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * SubsystemHealthRegistry — Fleet-visible health snapshot system.
3
+ * Port of SubsystemHealthRegistry.kt.
4
+ *
5
+ * 6 subsystems: SOCKET, PLAYER, CAMERA, MICROPHONE, ML_PIPELINE, MEMORY
6
+ * Each has specific stale thresholds:
7
+ * SOCKET: 60s (heartbeat every 30s)
8
+ * PLAYER: 180s (ping every 60s)
9
+ * CAMERA/MIC/ML/MEMORY: 30s (check every 10-15s)
10
+ *
11
+ * Persisted to JSON file for crash recovery.
12
+ */
13
+ import { Subsystem, SubsystemStatus, type SubsystemHealth } from './types';
14
+ export declare class SubsystemHealthRegistry {
15
+ private health;
16
+ private persistPath;
17
+ private persistTimer;
18
+ private persistDirty;
19
+ constructor(persistDir?: string);
20
+ /**
21
+ * Update the health status of a subsystem.
22
+ */
23
+ updateHealth(subsystem: Subsystem, status: SubsystemStatus, errorMessage?: string | null, metadata?: Record<string, unknown> | null): void;
24
+ /**
25
+ * Get the current health of a subsystem.
26
+ */
27
+ getHealth(subsystem: Subsystem): SubsystemHealth | null;
28
+ /**
29
+ * Check if a subsystem has failed (stale heartbeat or error status).
30
+ */
31
+ isSubsystemFailed(subsystem: Subsystem): boolean;
32
+ /**
33
+ * Check if overall system is healthy (all subsystems OK).
34
+ */
35
+ isOverallHealthy(): boolean;
36
+ /**
37
+ * Get list of failed subsystems.
38
+ */
39
+ getFailedSubsystems(): Subsystem[];
40
+ /**
41
+ * Generate heartbeat payload with all subsystem health.
42
+ */
43
+ toHeartbeatPayload(): Record<string, unknown>;
44
+ /**
45
+ * Clear all health records.
46
+ */
47
+ clear(): void;
48
+ /**
49
+ * Clean up the debounce timer. Call this when shutting down to prevent
50
+ * the timer from keeping the process alive or firing after disposal.
51
+ */
52
+ dispose(): void;
53
+ /**
54
+ * Debounce persistence writes — coalesce rapid updateHealth() calls (4-12/sec)
55
+ * into a single write every 2 seconds to protect flash storage.
56
+ */
57
+ private debouncedPersist;
58
+ private persist;
59
+ private restore;
60
+ }
61
+ //# sourceMappingURL=SubsystemHealthRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubsystemHealthRegistry.d.ts","sourceRoot":"","sources":["../src/SubsystemHealthRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EACL,SAAS,EACT,eAAe,EACf,KAAK,eAAe,EACrB,MAAM,SAAS,CAAC;AAsBjB,qBAAa,uBAAuB;IAClC,OAAO,CAAC,MAAM,CAA8C;IAC5D,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,YAAY,CAAS;gBAEjB,UAAU,CAAC,EAAE,MAAM;IAS/B;;OAEG;IACH,YAAY,CACV,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,eAAe,EACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,EAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACxC,IAAI;IAWP;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,eAAe,GAAG,IAAI;IAIvD;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IAWhD;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAS3B;;OAEG;IACH,mBAAmB,IAAI,SAAS,EAAE;IAUlC;;OAEG;IACH,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAe7C;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,OAAO,IAAI,IAAI;IAYf;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,OAAO;CAsBhB"}
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ /**
3
+ * SubsystemHealthRegistry — Fleet-visible health snapshot system.
4
+ * Port of SubsystemHealthRegistry.kt.
5
+ *
6
+ * 6 subsystems: SOCKET, PLAYER, CAMERA, MICROPHONE, ML_PIPELINE, MEMORY
7
+ * Each has specific stale thresholds:
8
+ * SOCKET: 60s (heartbeat every 30s)
9
+ * PLAYER: 180s (ping every 60s)
10
+ * CAMERA/MIC/ML/MEMORY: 30s (check every 10-15s)
11
+ *
12
+ * Persisted to JSON file for crash recovery.
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.SubsystemHealthRegistry = void 0;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const types_1 = require("./types");
42
+ const STALE_THRESHOLDS = {
43
+ [types_1.Subsystem.SOCKET]: 60000,
44
+ [types_1.Subsystem.PLAYER]: 180000,
45
+ [types_1.Subsystem.CAMERA]: 30000,
46
+ [types_1.Subsystem.MICROPHONE]: 30000,
47
+ [types_1.Subsystem.ML_PIPELINE]: 30000,
48
+ [types_1.Subsystem.MEMORY]: 30000,
49
+ };
50
+ const ERROR_STATUSES = new Set([
51
+ types_1.SubsystemStatus.DISCONNECTED,
52
+ types_1.SubsystemStatus.STUCK,
53
+ types_1.SubsystemStatus.CRASHED,
54
+ types_1.SubsystemStatus.PERMISSION_DENIED,
55
+ types_1.SubsystemStatus.ERROR,
56
+ types_1.SubsystemStatus.CRITICAL,
57
+ types_1.SubsystemStatus.OFFLINE,
58
+ types_1.SubsystemStatus.HIGH,
59
+ ]);
60
+ class SubsystemHealthRegistry {
61
+ constructor(persistDir) {
62
+ this.health = new Map();
63
+ this.persistTimer = null;
64
+ this.persistDirty = false;
65
+ if (persistDir) {
66
+ this.persistPath = path.join(persistDir, 'subsystem_health.json');
67
+ this.restore();
68
+ }
69
+ else {
70
+ this.persistPath = null;
71
+ }
72
+ }
73
+ /**
74
+ * Update the health status of a subsystem.
75
+ */
76
+ updateHealth(subsystem, status, errorMessage, metadata) {
77
+ this.health.set(subsystem, {
78
+ subsystem,
79
+ status,
80
+ lastHeartbeatMs: Date.now(),
81
+ errorMessage: errorMessage ?? null,
82
+ metadata: metadata ?? null,
83
+ });
84
+ this.debouncedPersist();
85
+ }
86
+ /**
87
+ * Get the current health of a subsystem.
88
+ */
89
+ getHealth(subsystem) {
90
+ return this.health.get(subsystem) || null;
91
+ }
92
+ /**
93
+ * Check if a subsystem has failed (stale heartbeat or error status).
94
+ */
95
+ isSubsystemFailed(subsystem) {
96
+ const h = this.health.get(subsystem);
97
+ if (!h)
98
+ return true; // Never reported = failed
99
+ const staleThreshold = STALE_THRESHOLDS[subsystem];
100
+ const age = Date.now() - h.lastHeartbeatMs;
101
+ if (age > staleThreshold)
102
+ return true;
103
+ return ERROR_STATUSES.has(h.status);
104
+ }
105
+ /**
106
+ * Check if overall system is healthy (all subsystems OK).
107
+ */
108
+ isOverallHealthy() {
109
+ for (const subsystem of Object.values(types_1.Subsystem)) {
110
+ if (this.health.has(subsystem) && this.isSubsystemFailed(subsystem)) {
111
+ return false;
112
+ }
113
+ }
114
+ return true;
115
+ }
116
+ /**
117
+ * Get list of failed subsystems.
118
+ */
119
+ getFailedSubsystems() {
120
+ const failed = [];
121
+ for (const subsystem of Object.values(types_1.Subsystem)) {
122
+ if (this.health.has(subsystem) && this.isSubsystemFailed(subsystem)) {
123
+ failed.push(subsystem);
124
+ }
125
+ }
126
+ return failed;
127
+ }
128
+ /**
129
+ * Generate heartbeat payload with all subsystem health.
130
+ */
131
+ toHeartbeatPayload() {
132
+ const payload = {};
133
+ for (const [subsystem, health] of this.health) {
134
+ const age = Date.now() - health.lastHeartbeatMs;
135
+ payload[subsystem] = {
136
+ status: health.status,
137
+ ageMs: age,
138
+ stale: age > STALE_THRESHOLDS[subsystem],
139
+ ...(health.errorMessage ? { error: health.errorMessage } : {}),
140
+ ...(health.metadata ? { metadata: health.metadata } : {}),
141
+ };
142
+ }
143
+ return payload;
144
+ }
145
+ /**
146
+ * Clear all health records.
147
+ */
148
+ clear() {
149
+ this.health.clear();
150
+ this.persist();
151
+ }
152
+ /**
153
+ * Clean up the debounce timer. Call this when shutting down to prevent
154
+ * the timer from keeping the process alive or firing after disposal.
155
+ */
156
+ dispose() {
157
+ if (this.persistTimer) {
158
+ clearTimeout(this.persistTimer);
159
+ this.persistTimer = null;
160
+ }
161
+ // Flush any pending dirty state synchronously before disposal
162
+ if (this.persistDirty) {
163
+ this.persistDirty = false;
164
+ this.persist();
165
+ }
166
+ }
167
+ /**
168
+ * Debounce persistence writes — coalesce rapid updateHealth() calls (4-12/sec)
169
+ * into a single write every 2 seconds to protect flash storage.
170
+ */
171
+ debouncedPersist() {
172
+ this.persistDirty = true;
173
+ if (this.persistTimer)
174
+ return; // already scheduled
175
+ this.persistTimer = setTimeout(() => {
176
+ this.persistTimer = null;
177
+ if (this.persistDirty) {
178
+ this.persistDirty = false;
179
+ this.persist();
180
+ }
181
+ }, 2000);
182
+ }
183
+ persist() {
184
+ if (!this.persistPath)
185
+ return;
186
+ try {
187
+ const data = {};
188
+ for (const [subsystem, health] of this.health) {
189
+ data[subsystem] = {
190
+ status: health.status,
191
+ lastHeartbeatMs: health.lastHeartbeatMs,
192
+ };
193
+ }
194
+ const dir = path.dirname(this.persistPath);
195
+ if (!fs.existsSync(dir)) {
196
+ fs.mkdirSync(dir, { recursive: true });
197
+ }
198
+ fs.writeFileSync(this.persistPath, JSON.stringify(data));
199
+ }
200
+ catch {
201
+ // Non-fatal
202
+ }
203
+ }
204
+ restore() {
205
+ if (!this.persistPath)
206
+ return;
207
+ try {
208
+ if (fs.existsSync(this.persistPath)) {
209
+ const data = JSON.parse(fs.readFileSync(this.persistPath, 'utf-8'));
210
+ for (const [subsystem, info] of Object.entries(data)) {
211
+ const parsed = info;
212
+ if (Object.values(types_1.Subsystem).includes(subsystem)) {
213
+ this.health.set(subsystem, {
214
+ subsystem: subsystem,
215
+ status: parsed.status,
216
+ lastHeartbeatMs: parsed.lastHeartbeatMs,
217
+ errorMessage: null,
218
+ metadata: null,
219
+ });
220
+ }
221
+ }
222
+ }
223
+ }
224
+ catch {
225
+ // Corrupted — start fresh
226
+ }
227
+ }
228
+ }
229
+ exports.SubsystemHealthRegistry = SubsystemHealthRegistry;
230
+ //# sourceMappingURL=SubsystemHealthRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubsystemHealthRegistry.js","sourceRoot":"","sources":["../src/SubsystemHealthRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * TelemetryScheduler — Heartbeat emission loop.
3
+ * Port of TelemetryScheduler.kt.
4
+ *
5
+ * Emits heartbeat every 30s (configurable via heartbeatIntervalMs).
6
+ * Skips if powerState == "off" or "standby" — lets server TTL handle offline marking.
7
+ * Skips if screenId not yet resolved.
8
+ */
9
+ import { SocketManager } from './SocketManager';
10
+ import { SubsystemHealthRegistry } from './SubsystemHealthRegistry';
11
+ import type { PlatformAdapter } from './types';
12
+ export interface TelemetrySchedulerOptions {
13
+ socketManager: SocketManager;
14
+ healthRegistry: SubsystemHealthRegistry;
15
+ platform: PlatformAdapter;
16
+ fingerprint: string;
17
+ heartbeatIntervalMs?: number;
18
+ screenId?: string;
19
+ metadata?: Record<string, unknown>;
20
+ }
21
+ export declare class TelemetryScheduler {
22
+ private socketManager;
23
+ private healthRegistry;
24
+ private platform;
25
+ private fingerprint;
26
+ private heartbeatIntervalMs;
27
+ private screenId;
28
+ private metadata;
29
+ private interval;
30
+ private startTime;
31
+ private powerState;
32
+ constructor(options: TelemetrySchedulerOptions);
33
+ /**
34
+ * Start the heartbeat emission loop.
35
+ */
36
+ start(): void;
37
+ /**
38
+ * Stop the heartbeat loop.
39
+ */
40
+ stop(): void;
41
+ /**
42
+ * Update the screen ID after registration.
43
+ */
44
+ setScreenId(screenId: string): void;
45
+ /**
46
+ * Update the power state.
47
+ * "off" or "standby" → skip heartbeats, let server TTL mark offline.
48
+ */
49
+ setPowerState(state: 'on' | 'off' | 'standby'): void;
50
+ /**
51
+ * Update metadata to include in heartbeats.
52
+ */
53
+ updateMetadata(metadata: Record<string, unknown>): void;
54
+ private emitHeartbeat;
55
+ }
56
+ //# sourceMappingURL=TelemetryScheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelemetryScheduler.d.ts","sourceRoot":"","sources":["../src/TelemetryScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,SAAS,CAAC;AAEjE,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,uBAAuB,CAAC;IACxC,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAkC;gBAExC,OAAO,EAAE,yBAAyB;IAW9C;;OAEG;IACH,KAAK,IAAI,IAAI;IAWb;;OAEG;IACH,IAAI,IAAI,IAAI;IAOZ;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAInC;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG,SAAS,GAAG,IAAI;IAIpD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIvD,OAAO,CAAC,aAAa;CAkCtB"}