@trillboards/edge-core 0.2.1 → 0.2.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/dist/JsonFileStore.d.ts +33 -0
- package/dist/JsonFileStore.d.ts.map +1 -0
- package/dist/JsonFileStore.js +210 -0
- package/dist/JsonFileStore.js.map +1 -0
- package/dist/SignalBuffer.d.ts +20 -12
- package/dist/SignalBuffer.d.ts.map +1 -1
- package/dist/SignalBuffer.js +56 -71
- package/dist/SignalBuffer.js.map +1 -1
- package/dist/SignalStore.d.ts +35 -0
- package/dist/SignalStore.d.ts.map +1 -0
- package/dist/SignalStore.js +13 -0
- package/dist/SignalStore.js.map +1 -0
- package/dist/SqliteStore.d.ts +41 -0
- package/dist/SqliteStore.d.ts.map +1 -0
- package/dist/SqliteStore.js +162 -0
- package/dist/SqliteStore.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JsonFileStore — Zero-dependency signal store using Node.js fs.
|
|
3
|
+
*
|
|
4
|
+
* Storage: configurable path (default: ~/.trillboards/signal_buffer.json)
|
|
5
|
+
* Persistence: debounced writes (every 5s max) + sync write on close()
|
|
6
|
+
* Crash safety: write to .tmp then fs.renameSync (atomic on all platforms)
|
|
7
|
+
* Priority: FACE_BACKED > PERSON_BACKED > SPEECH_ONLY > PROXY_ONLY > EMPTY
|
|
8
|
+
*/
|
|
9
|
+
import type { SignalStore, StoredSignal, SignalStoreStats } from './SignalStore';
|
|
10
|
+
export declare class JsonFileStore implements SignalStore {
|
|
11
|
+
private signals;
|
|
12
|
+
private nextId;
|
|
13
|
+
private readonly filePath;
|
|
14
|
+
private dirty;
|
|
15
|
+
private flushTimer;
|
|
16
|
+
private static readonly FLUSH_INTERVAL_MS;
|
|
17
|
+
constructor(filePath?: string);
|
|
18
|
+
private loadFromDisk;
|
|
19
|
+
private schedulePersist;
|
|
20
|
+
private persistSync;
|
|
21
|
+
private extractEvidenceGrade;
|
|
22
|
+
insert(payload: string, timestamp: number): void;
|
|
23
|
+
getOldest(limit: number): StoredSignal[];
|
|
24
|
+
deleteById(id: number): void;
|
|
25
|
+
deleteOlderThan(cutoffMs: number): number;
|
|
26
|
+
deleteOldestN(n: number): void;
|
|
27
|
+
deleteExceedingRetries(maxRetries: number): void;
|
|
28
|
+
incrementRetry(id: number): void;
|
|
29
|
+
count(): number;
|
|
30
|
+
stats(): SignalStoreStats;
|
|
31
|
+
close(): void;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=JsonFileStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonFileStore.d.ts","sourceRoot":"","sources":["../src/JsonFileStore.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAejF,qBAAa,aAAc,YAAW,WAAW;IAC/C,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;gBAErC,QAAQ,CAAC,EAAE,MAAM;IAiB7B,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,oBAAoB;IAW5B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAYhD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;IAWxC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQ5B,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAQzC,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ9B,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAMhD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQhC,KAAK,IAAI,MAAM;IAIf,KAAK,IAAI,gBAAgB;IAmBzB,KAAK,IAAI,IAAI;CASd"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JsonFileStore — Zero-dependency signal store using Node.js fs.
|
|
4
|
+
*
|
|
5
|
+
* Storage: configurable path (default: ~/.trillboards/signal_buffer.json)
|
|
6
|
+
* Persistence: debounced writes (every 5s max) + sync write on close()
|
|
7
|
+
* Crash safety: write to .tmp then fs.renameSync (atomic on all platforms)
|
|
8
|
+
* Priority: FACE_BACKED > PERSON_BACKED > SPEECH_ONLY > PROXY_ONLY > EMPTY
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
27
|
+
if (mod && mod.__esModule) return mod;
|
|
28
|
+
var result = {};
|
|
29
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
30
|
+
__setModuleDefault(result, mod);
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.JsonFileStore = void 0;
|
|
35
|
+
const fs = __importStar(require("fs"));
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const EVIDENCE_GRADE_PRIORITY = {
|
|
38
|
+
FACE_BACKED: 1,
|
|
39
|
+
PERSON_BACKED: 2,
|
|
40
|
+
SPEECH_ONLY: 3,
|
|
41
|
+
PROXY_ONLY: 4,
|
|
42
|
+
EMPTY: 5,
|
|
43
|
+
};
|
|
44
|
+
class JsonFileStore {
|
|
45
|
+
constructor(filePath) {
|
|
46
|
+
this.signals = [];
|
|
47
|
+
this.nextId = 1;
|
|
48
|
+
this.dirty = false;
|
|
49
|
+
this.flushTimer = null;
|
|
50
|
+
this.filePath =
|
|
51
|
+
filePath ||
|
|
52
|
+
path.join(process.env.HOME || process.env.USERPROFILE || '/tmp', '.trillboards', 'signal_buffer.json');
|
|
53
|
+
const dir = path.dirname(this.filePath);
|
|
54
|
+
if (!fs.existsSync(dir)) {
|
|
55
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
this.loadFromDisk();
|
|
58
|
+
}
|
|
59
|
+
loadFromDisk() {
|
|
60
|
+
try {
|
|
61
|
+
if (fs.existsSync(this.filePath)) {
|
|
62
|
+
const raw = fs.readFileSync(this.filePath, 'utf-8');
|
|
63
|
+
const data = JSON.parse(raw);
|
|
64
|
+
if (Array.isArray(data.signals)) {
|
|
65
|
+
this.signals = data.signals;
|
|
66
|
+
this.nextId = typeof data.nextId === 'number' ? data.nextId : 1;
|
|
67
|
+
// Ensure nextId is higher than any existing signal id
|
|
68
|
+
for (const s of this.signals) {
|
|
69
|
+
if (s.id >= this.nextId) {
|
|
70
|
+
this.nextId = s.id + 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Corrupt file — start fresh, log warning
|
|
78
|
+
console.warn(`[JsonFileStore] Corrupt signal buffer at ${this.filePath}, starting fresh`);
|
|
79
|
+
this.signals = [];
|
|
80
|
+
this.nextId = 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
schedulePersist() {
|
|
84
|
+
this.dirty = true;
|
|
85
|
+
if (this.flushTimer)
|
|
86
|
+
return;
|
|
87
|
+
this.flushTimer = setTimeout(() => {
|
|
88
|
+
this.flushTimer = null;
|
|
89
|
+
if (this.dirty) {
|
|
90
|
+
this.persistSync();
|
|
91
|
+
}
|
|
92
|
+
}, JsonFileStore.FLUSH_INTERVAL_MS);
|
|
93
|
+
}
|
|
94
|
+
persistSync() {
|
|
95
|
+
this.dirty = false;
|
|
96
|
+
const data = {
|
|
97
|
+
nextId: this.nextId,
|
|
98
|
+
signals: this.signals,
|
|
99
|
+
};
|
|
100
|
+
const json = JSON.stringify(data);
|
|
101
|
+
const tmpPath = this.filePath + '.tmp';
|
|
102
|
+
try {
|
|
103
|
+
fs.writeFileSync(tmpPath, json, 'utf-8');
|
|
104
|
+
fs.renameSync(tmpPath, this.filePath);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.error(`[JsonFileStore] Failed to persist signal buffer:`, err);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
extractEvidenceGrade(payload) {
|
|
111
|
+
try {
|
|
112
|
+
const parsed = JSON.parse(payload);
|
|
113
|
+
return typeof parsed.evidenceGrade === 'string'
|
|
114
|
+
? parsed.evidenceGrade
|
|
115
|
+
: 'EMPTY';
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return 'EMPTY';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
insert(payload, timestamp) {
|
|
122
|
+
const signal = {
|
|
123
|
+
id: this.nextId++,
|
|
124
|
+
payload,
|
|
125
|
+
timestamp,
|
|
126
|
+
retryCount: 0,
|
|
127
|
+
evidenceGrade: this.extractEvidenceGrade(payload),
|
|
128
|
+
};
|
|
129
|
+
this.signals.push(signal);
|
|
130
|
+
this.schedulePersist();
|
|
131
|
+
}
|
|
132
|
+
getOldest(limit) {
|
|
133
|
+
// Sort by priority (evidence grade), then by timestamp (oldest first)
|
|
134
|
+
const sorted = [...this.signals].sort((a, b) => {
|
|
135
|
+
const prioA = EVIDENCE_GRADE_PRIORITY[a.evidenceGrade || 'EMPTY'] || 5;
|
|
136
|
+
const prioB = EVIDENCE_GRADE_PRIORITY[b.evidenceGrade || 'EMPTY'] || 5;
|
|
137
|
+
if (prioA !== prioB)
|
|
138
|
+
return prioA - prioB;
|
|
139
|
+
return a.timestamp - b.timestamp;
|
|
140
|
+
});
|
|
141
|
+
return sorted.slice(0, limit);
|
|
142
|
+
}
|
|
143
|
+
deleteById(id) {
|
|
144
|
+
const idx = this.signals.findIndex((s) => s.id === id);
|
|
145
|
+
if (idx !== -1) {
|
|
146
|
+
this.signals.splice(idx, 1);
|
|
147
|
+
this.schedulePersist();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
deleteOlderThan(cutoffMs) {
|
|
151
|
+
const before = this.signals.length;
|
|
152
|
+
this.signals = this.signals.filter((s) => s.timestamp >= cutoffMs);
|
|
153
|
+
const deleted = before - this.signals.length;
|
|
154
|
+
if (deleted > 0)
|
|
155
|
+
this.schedulePersist();
|
|
156
|
+
return deleted;
|
|
157
|
+
}
|
|
158
|
+
deleteOldestN(n) {
|
|
159
|
+
if (n <= 0 || this.signals.length === 0)
|
|
160
|
+
return;
|
|
161
|
+
// Sort by timestamp ascending, remove the oldest N
|
|
162
|
+
this.signals.sort((a, b) => a.timestamp - b.timestamp);
|
|
163
|
+
this.signals.splice(0, n);
|
|
164
|
+
this.schedulePersist();
|
|
165
|
+
}
|
|
166
|
+
deleteExceedingRetries(maxRetries) {
|
|
167
|
+
const before = this.signals.length;
|
|
168
|
+
this.signals = this.signals.filter((s) => s.retryCount < maxRetries);
|
|
169
|
+
if (this.signals.length < before)
|
|
170
|
+
this.schedulePersist();
|
|
171
|
+
}
|
|
172
|
+
incrementRetry(id) {
|
|
173
|
+
const signal = this.signals.find((s) => s.id === id);
|
|
174
|
+
if (signal) {
|
|
175
|
+
signal.retryCount++;
|
|
176
|
+
this.schedulePersist();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
count() {
|
|
180
|
+
return this.signals.length;
|
|
181
|
+
}
|
|
182
|
+
stats() {
|
|
183
|
+
const byGrade = {};
|
|
184
|
+
let oldest = null;
|
|
185
|
+
for (const s of this.signals) {
|
|
186
|
+
const grade = s.evidenceGrade || 'EMPTY';
|
|
187
|
+
byGrade[grade] = (byGrade[grade] || 0) + 1;
|
|
188
|
+
if (oldest === null || s.timestamp < oldest) {
|
|
189
|
+
oldest = s.timestamp;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
total: this.signals.length,
|
|
194
|
+
byEvidenceGrade: byGrade,
|
|
195
|
+
oldestTimestampMs: oldest,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
close() {
|
|
199
|
+
if (this.flushTimer) {
|
|
200
|
+
clearTimeout(this.flushTimer);
|
|
201
|
+
this.flushTimer = null;
|
|
202
|
+
}
|
|
203
|
+
if (this.dirty) {
|
|
204
|
+
this.persistSync();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.JsonFileStore = JsonFileStore;
|
|
209
|
+
JsonFileStore.FLUSH_INTERVAL_MS = 5000;
|
|
210
|
+
//# sourceMappingURL=JsonFileStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonFileStore.js","sourceRoot":"","sources":["../src/JsonFileStore.ts"],"names":[],"mappings":"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"}
|
package/dist/SignalBuffer.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SignalBuffer — Offline signal buffering
|
|
3
|
-
* Port of SignalBuffer.kt (Room database) to cross-platform
|
|
2
|
+
* SignalBuffer — Offline signal buffering with auto-detecting backend.
|
|
3
|
+
* Port of SignalBuffer.kt (Room database) to cross-platform storage.
|
|
4
|
+
*
|
|
5
|
+
* Backends:
|
|
6
|
+
* - SqliteStore (better-sqlite3 installed → WAL mode, prepared stmts)
|
|
7
|
+
* - JsonFileStore (fallback → zero deps, fs.renameSync atomic writes)
|
|
8
|
+
*
|
|
9
|
+
* Auto-detection: tries require('better-sqlite3') at construction time.
|
|
10
|
+
* If unavailable (native compilation failed, not installed), falls back
|
|
11
|
+
* to JsonFileStore — guaranteed to work on any Node.js >=18 platform.
|
|
4
12
|
*
|
|
5
13
|
* Capacity: 8,640 signals (24h at 6 signals/min)
|
|
6
14
|
* Eviction: oldest 10% when at capacity
|
|
7
15
|
* Flush: batch of 50, marks with _buffered and _bufferedAt
|
|
8
16
|
* Pruning: signals older than 24h auto-deleted
|
|
17
|
+
* Priority: FACE_BACKED > PERSON_BACKED > SPEECH_ONLY > PROXY_ONLY > EMPTY
|
|
9
18
|
*/
|
|
19
|
+
import type { SignalStoreStats } from './SignalStore';
|
|
10
20
|
import { SocketManager } from './SocketManager';
|
|
11
21
|
export interface BufferedSignal {
|
|
12
22
|
id: number;
|
|
@@ -20,15 +30,8 @@ export declare class SignalBuffer {
|
|
|
20
30
|
static readonly MAX_AGE_MS: number;
|
|
21
31
|
static readonly MAX_RETRIES = 5;
|
|
22
32
|
static readonly EVICT_RATIO = 0.1;
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
private getOldestStmt;
|
|
26
|
-
private deleteByIdStmt;
|
|
27
|
-
private countStmt;
|
|
28
|
-
private pruneStmt;
|
|
29
|
-
private deleteOldestNStmt;
|
|
30
|
-
private incrementRetryStmt;
|
|
31
|
-
private deleteMaxRetriesStmt;
|
|
33
|
+
private store;
|
|
34
|
+
readonly backend: 'sqlite' | 'json';
|
|
32
35
|
constructor(dbPath: string);
|
|
33
36
|
/**
|
|
34
37
|
* Buffer a signal for later sending.
|
|
@@ -38,6 +41,7 @@ export declare class SignalBuffer {
|
|
|
38
41
|
/**
|
|
39
42
|
* Flush buffered signals via socket.
|
|
40
43
|
* Returns number of successfully sent signals.
|
|
44
|
+
* Signals are flushed in priority order — highest evidence grade first.
|
|
41
45
|
*/
|
|
42
46
|
flushBuffer(socketManager: SocketManager, limit?: number): number;
|
|
43
47
|
/**
|
|
@@ -49,7 +53,11 @@ export declare class SignalBuffer {
|
|
|
49
53
|
*/
|
|
50
54
|
count(): number;
|
|
51
55
|
/**
|
|
52
|
-
*
|
|
56
|
+
* Signal buffer statistics — count by evidence grade, oldest timestamp.
|
|
57
|
+
*/
|
|
58
|
+
stats(): SignalStoreStats;
|
|
59
|
+
/**
|
|
60
|
+
* Close the store connection.
|
|
53
61
|
*/
|
|
54
62
|
shutdown(): void;
|
|
55
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SignalBuffer.d.ts","sourceRoot":"","sources":["../src/SignalBuffer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SignalBuffer.d.ts","sourceRoot":"","sources":["../src/SignalBuffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,YAAY;IACvB,MAAM,CAAC,QAAQ,CAAC,YAAY,QAAQ;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,MAAM;IACtC,MAAM,CAAC,QAAQ,CAAC,UAAU,SAAuB;IACjD,MAAM,CAAC,QAAQ,CAAC,WAAW,KAAK;IAChC,MAAM,CAAC,QAAQ,CAAC,WAAW,OAAO;IAElC,OAAO,CAAC,KAAK,CAAc;IAC3B,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;gBAExB,MAAM,EAAE,MAAM;IAiC1B;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYpD;;;;OAIG;IACH,WAAW,CACT,aAAa,EAAE,aAAa,EAC5B,KAAK,GAAE,MAAsC,GAC5C,MAAM;IA8BT;;OAEG;IACH,eAAe,IAAI,MAAM;IAKzB;;OAEG;IACH,KAAK,IAAI,MAAM;IAIf;;OAEG;IACH,KAAK,IAAI,gBAAgB;IAIzB;;OAEG;IACH,QAAQ,IAAI,IAAI;CAGjB"}
|
package/dist/SignalBuffer.js
CHANGED
|
@@ -1,92 +1,73 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* SignalBuffer — Offline signal buffering
|
|
4
|
-
* Port of SignalBuffer.kt (Room database) to cross-platform
|
|
3
|
+
* SignalBuffer — Offline signal buffering with auto-detecting backend.
|
|
4
|
+
* Port of SignalBuffer.kt (Room database) to cross-platform storage.
|
|
5
|
+
*
|
|
6
|
+
* Backends:
|
|
7
|
+
* - SqliteStore (better-sqlite3 installed → WAL mode, prepared stmts)
|
|
8
|
+
* - JsonFileStore (fallback → zero deps, fs.renameSync atomic writes)
|
|
9
|
+
*
|
|
10
|
+
* Auto-detection: tries require('better-sqlite3') at construction time.
|
|
11
|
+
* If unavailable (native compilation failed, not installed), falls back
|
|
12
|
+
* to JsonFileStore — guaranteed to work on any Node.js >=18 platform.
|
|
5
13
|
*
|
|
6
14
|
* Capacity: 8,640 signals (24h at 6 signals/min)
|
|
7
15
|
* Eviction: oldest 10% when at capacity
|
|
8
16
|
* Flush: batch of 50, marks with _buffered and _bufferedAt
|
|
9
17
|
* Pruning: signals older than 24h auto-deleted
|
|
18
|
+
* Priority: FACE_BACKED > PERSON_BACKED > SPEECH_ONLY > PROXY_ONLY > EMPTY
|
|
10
19
|
*/
|
|
11
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
-
if (k2 === undefined) k2 = k;
|
|
13
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
-
}
|
|
17
|
-
Object.defineProperty(o, k2, desc);
|
|
18
|
-
}) : (function(o, m, k, k2) {
|
|
19
|
-
if (k2 === undefined) k2 = k;
|
|
20
|
-
o[k2] = m[k];
|
|
21
|
-
}));
|
|
22
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
-
}) : function(o, v) {
|
|
25
|
-
o["default"] = v;
|
|
26
|
-
});
|
|
27
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
-
};
|
|
37
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
21
|
exports.SignalBuffer = void 0;
|
|
39
|
-
const
|
|
40
|
-
const path = __importStar(require("path"));
|
|
41
|
-
const fs = __importStar(require("fs"));
|
|
22
|
+
const JsonFileStore_1 = require("./JsonFileStore");
|
|
42
23
|
class SignalBuffer {
|
|
43
24
|
constructor(dbPath) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
25
|
+
let store = null;
|
|
26
|
+
let backend = 'json';
|
|
27
|
+
// Try SQLite first (high-performance, optional)
|
|
28
|
+
try {
|
|
29
|
+
// Dynamic require — only resolves if better-sqlite3 is installed + compiled
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
31
|
+
const Database = require('better-sqlite3');
|
|
32
|
+
const { SqliteStore } = require('./SqliteStore');
|
|
33
|
+
store = new SqliteStore(dbPath, Database);
|
|
34
|
+
backend = 'sqlite';
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// better-sqlite3 not available — fall back to JSON file store
|
|
47
38
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
CREATE INDEX IF NOT EXISTS idx_signals_timestamp ON buffered_signals(timestamp)
|
|
61
|
-
`);
|
|
62
|
-
// Prepared statements for performance
|
|
63
|
-
this.insertStmt = this.db.prepare('INSERT INTO buffered_signals (payload, timestamp, retry_count) VALUES (?, ?, 0)');
|
|
64
|
-
this.getOldestStmt = this.db.prepare('SELECT id, payload, timestamp, retry_count FROM buffered_signals ORDER BY timestamp ASC LIMIT ?');
|
|
65
|
-
this.deleteByIdStmt = this.db.prepare('DELETE FROM buffered_signals WHERE id = ?');
|
|
66
|
-
this.countStmt = this.db.prepare('SELECT COUNT(*) as count FROM buffered_signals');
|
|
67
|
-
this.pruneStmt = this.db.prepare('DELETE FROM buffered_signals WHERE timestamp < ?');
|
|
68
|
-
this.deleteOldestNStmt = this.db.prepare('DELETE FROM buffered_signals WHERE id IN (SELECT id FROM buffered_signals ORDER BY timestamp ASC LIMIT ?)');
|
|
69
|
-
this.incrementRetryStmt = this.db.prepare('UPDATE buffered_signals SET retry_count = retry_count + 1 WHERE id = ?');
|
|
70
|
-
this.deleteMaxRetriesStmt = this.db.prepare('DELETE FROM buffered_signals WHERE retry_count >= ?');
|
|
39
|
+
if (!store) {
|
|
40
|
+
// Use JSON file store — zero dependencies, universal
|
|
41
|
+
const jsonPath = dbPath.replace(/\.db$/, '.json');
|
|
42
|
+
store = new JsonFileStore_1.JsonFileStore(jsonPath);
|
|
43
|
+
backend = 'json';
|
|
44
|
+
}
|
|
45
|
+
this.store = store;
|
|
46
|
+
this.backend = backend;
|
|
47
|
+
const label = backend === 'sqlite'
|
|
48
|
+
? 'SQLite (disk-persistent, WAL mode)'
|
|
49
|
+
: 'JSON file (disk-persistent, atomic writes)';
|
|
50
|
+
console.log(`[SignalBuffer] Initialized: ${label}`);
|
|
71
51
|
}
|
|
72
52
|
/**
|
|
73
53
|
* Buffer a signal for later sending.
|
|
74
54
|
* If at capacity, evicts oldest 10% first.
|
|
75
55
|
*/
|
|
76
56
|
bufferSignal(payload) {
|
|
77
|
-
const count = this.count();
|
|
57
|
+
const count = this.store.count();
|
|
78
58
|
if (count >= SignalBuffer.MAX_CAPACITY) {
|
|
79
59
|
const evictCount = Math.ceil(SignalBuffer.MAX_CAPACITY * SignalBuffer.EVICT_RATIO);
|
|
80
|
-
this.
|
|
60
|
+
this.store.deleteOldestN(evictCount);
|
|
81
61
|
}
|
|
82
|
-
this.
|
|
62
|
+
this.store.insert(JSON.stringify(payload), Date.now());
|
|
83
63
|
}
|
|
84
64
|
/**
|
|
85
65
|
* Flush buffered signals via socket.
|
|
86
66
|
* Returns number of successfully sent signals.
|
|
67
|
+
* Signals are flushed in priority order — highest evidence grade first.
|
|
87
68
|
*/
|
|
88
69
|
flushBuffer(socketManager, limit = SignalBuffer.FLUSH_BATCH_SIZE) {
|
|
89
|
-
const signals = this.
|
|
70
|
+
const signals = this.store.getOldest(limit);
|
|
90
71
|
let sent = 0;
|
|
91
72
|
for (const signal of signals) {
|
|
92
73
|
try {
|
|
@@ -96,20 +77,20 @@ class SignalBuffer {
|
|
|
96
77
|
payload._bufferedAt = signal.timestamp;
|
|
97
78
|
const success = socketManager.emitAudienceSignal(payload);
|
|
98
79
|
if (success) {
|
|
99
|
-
this.
|
|
80
|
+
this.store.deleteById(signal.id);
|
|
100
81
|
sent++;
|
|
101
82
|
}
|
|
102
83
|
else {
|
|
103
|
-
this.
|
|
84
|
+
this.store.incrementRetry(signal.id);
|
|
104
85
|
}
|
|
105
86
|
}
|
|
106
87
|
catch {
|
|
107
88
|
// Corrupted payload — remove it
|
|
108
|
-
this.
|
|
89
|
+
this.store.deleteById(signal.id);
|
|
109
90
|
}
|
|
110
91
|
}
|
|
111
92
|
// Clean up signals that have exceeded max retries
|
|
112
|
-
this.
|
|
93
|
+
this.store.deleteExceedingRetries(SignalBuffer.MAX_RETRIES);
|
|
113
94
|
return sent;
|
|
114
95
|
}
|
|
115
96
|
/**
|
|
@@ -117,21 +98,25 @@ class SignalBuffer {
|
|
|
117
98
|
*/
|
|
118
99
|
pruneOldSignals() {
|
|
119
100
|
const cutoff = Date.now() - SignalBuffer.MAX_AGE_MS;
|
|
120
|
-
|
|
121
|
-
return result.changes;
|
|
101
|
+
return this.store.deleteOlderThan(cutoff);
|
|
122
102
|
}
|
|
123
103
|
/**
|
|
124
104
|
* Current number of buffered signals.
|
|
125
105
|
*/
|
|
126
106
|
count() {
|
|
127
|
-
|
|
128
|
-
|
|
107
|
+
return this.store.count();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Signal buffer statistics — count by evidence grade, oldest timestamp.
|
|
111
|
+
*/
|
|
112
|
+
stats() {
|
|
113
|
+
return this.store.stats();
|
|
129
114
|
}
|
|
130
115
|
/**
|
|
131
|
-
* Close the
|
|
116
|
+
* Close the store connection.
|
|
132
117
|
*/
|
|
133
118
|
shutdown() {
|
|
134
|
-
this.
|
|
119
|
+
this.store.close();
|
|
135
120
|
}
|
|
136
121
|
}
|
|
137
122
|
exports.SignalBuffer = SignalBuffer;
|
package/dist/SignalBuffer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SignalBuffer.js","sourceRoot":"","sources":["../src/SignalBuffer.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"SignalBuffer.js","sourceRoot":"","sources":["../src/SignalBuffer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignalStore — Internal interface for signal-aware persistence backends.
|
|
3
|
+
*
|
|
4
|
+
* The SignalBuffer delegates all storage operations to a SignalStore implementation.
|
|
5
|
+
* Two built-in implementations:
|
|
6
|
+
* - JsonFileStore (zero dependencies, universal default)
|
|
7
|
+
* - SqliteStore (optional, high-throughput upgrade via better-sqlite3)
|
|
8
|
+
*
|
|
9
|
+
* Advanced users can implement this interface for custom backends (Redis, IndexedDB, etc.)
|
|
10
|
+
*/
|
|
11
|
+
export interface StoredSignal {
|
|
12
|
+
id: number;
|
|
13
|
+
payload: string;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
retryCount: number;
|
|
16
|
+
evidenceGrade?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SignalStoreStats {
|
|
19
|
+
total: number;
|
|
20
|
+
byEvidenceGrade: Record<string, number>;
|
|
21
|
+
oldestTimestampMs: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface SignalStore {
|
|
24
|
+
insert(payload: string, timestamp: number): void;
|
|
25
|
+
getOldest(limit: number): StoredSignal[];
|
|
26
|
+
deleteById(id: number): void;
|
|
27
|
+
deleteOlderThan(cutoffMs: number): number;
|
|
28
|
+
deleteOldestN(n: number): void;
|
|
29
|
+
deleteExceedingRetries(maxRetries: number): void;
|
|
30
|
+
incrementRetry(id: number): void;
|
|
31
|
+
count(): number;
|
|
32
|
+
stats(): SignalStoreStats;
|
|
33
|
+
close(): void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=SignalStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignalStore.d.ts","sourceRoot":"","sources":["../src/SignalStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;IACzC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,KAAK,IAAI,MAAM,CAAC;IAChB,KAAK,IAAI,gBAAgB,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SignalStore — Internal interface for signal-aware persistence backends.
|
|
4
|
+
*
|
|
5
|
+
* The SignalBuffer delegates all storage operations to a SignalStore implementation.
|
|
6
|
+
* Two built-in implementations:
|
|
7
|
+
* - JsonFileStore (zero dependencies, universal default)
|
|
8
|
+
* - SqliteStore (optional, high-throughput upgrade via better-sqlite3)
|
|
9
|
+
*
|
|
10
|
+
* Advanced users can implement this interface for custom backends (Redis, IndexedDB, etc.)
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
//# sourceMappingURL=SignalStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignalStore.js","sourceRoot":"","sources":["../src/SignalStore.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqliteStore — High-performance signal store using better-sqlite3.
|
|
3
|
+
* Extracted from the original SignalBuffer implementation.
|
|
4
|
+
*
|
|
5
|
+
* WAL journal mode, prepared statements, evidence_grade column + index
|
|
6
|
+
* for priority-aware flushing (FACE_BACKED sent first).
|
|
7
|
+
*
|
|
8
|
+
* Only loaded when better-sqlite3 is available (optional dependency).
|
|
9
|
+
*/
|
|
10
|
+
import type { SignalStore, StoredSignal, SignalStoreStats } from './SignalStore';
|
|
11
|
+
import type { Database as DatabaseType } from 'better-sqlite3';
|
|
12
|
+
export declare class SqliteStore implements SignalStore {
|
|
13
|
+
private db;
|
|
14
|
+
private insertStmt;
|
|
15
|
+
private getOldestStmt;
|
|
16
|
+
private deleteByIdStmt;
|
|
17
|
+
private countStmt;
|
|
18
|
+
private pruneStmt;
|
|
19
|
+
private deleteOldestNStmt;
|
|
20
|
+
private incrementRetryStmt;
|
|
21
|
+
private deleteMaxRetriesStmt;
|
|
22
|
+
private statsStmt;
|
|
23
|
+
private oldestStmt;
|
|
24
|
+
/**
|
|
25
|
+
* @param dbPath - Path to the SQLite database file
|
|
26
|
+
* @param DatabaseConstructor - The better-sqlite3 Database constructor (injected to avoid top-level require)
|
|
27
|
+
*/
|
|
28
|
+
constructor(dbPath: string, DatabaseConstructor: new (filename: string) => DatabaseType);
|
|
29
|
+
private extractEvidenceGrade;
|
|
30
|
+
insert(payload: string, timestamp: number): void;
|
|
31
|
+
getOldest(limit: number): StoredSignal[];
|
|
32
|
+
deleteById(id: number): void;
|
|
33
|
+
deleteOlderThan(cutoffMs: number): number;
|
|
34
|
+
deleteOldestN(n: number): void;
|
|
35
|
+
deleteExceedingRetries(maxRetries: number): void;
|
|
36
|
+
incrementRetry(id: number): void;
|
|
37
|
+
count(): number;
|
|
38
|
+
stats(): SignalStoreStats;
|
|
39
|
+
close(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=SqliteStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqliteStore.d.ts","sourceRoot":"","sources":["../src/SqliteStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjF,OAAO,KAAK,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE/D,qBAAa,WAAY,YAAW,WAAW;IAC7C,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,UAAU,CAAsC;IACxD,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,kBAAkB,CAAsC;IAChE,OAAO,CAAC,oBAAoB,CAAsC;IAClE,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,UAAU,CAAsC;IAExD;;;OAGG;gBAED,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,YAAY;IA4F7D,OAAO,CAAC,oBAAoB;IAW5B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKhD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;IAIxC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAKzC,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAI9B,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIhD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIhC,KAAK,IAAI,MAAM;IAKf,KAAK,IAAI,gBAAgB;IAoBzB,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SqliteStore — High-performance signal store using better-sqlite3.
|
|
4
|
+
* Extracted from the original SignalBuffer implementation.
|
|
5
|
+
*
|
|
6
|
+
* WAL journal mode, prepared statements, evidence_grade column + index
|
|
7
|
+
* for priority-aware flushing (FACE_BACKED sent first).
|
|
8
|
+
*
|
|
9
|
+
* Only loaded when better-sqlite3 is available (optional dependency).
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.SqliteStore = void 0;
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
class SqliteStore {
|
|
39
|
+
/**
|
|
40
|
+
* @param dbPath - Path to the SQLite database file
|
|
41
|
+
* @param DatabaseConstructor - The better-sqlite3 Database constructor (injected to avoid top-level require)
|
|
42
|
+
*/
|
|
43
|
+
constructor(dbPath, DatabaseConstructor) {
|
|
44
|
+
const dir = path.dirname(dbPath);
|
|
45
|
+
if (!fs.existsSync(dir)) {
|
|
46
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
this.db = new DatabaseConstructor(dbPath);
|
|
49
|
+
this.db.pragma('journal_mode = WAL');
|
|
50
|
+
this.db.pragma('synchronous = NORMAL');
|
|
51
|
+
this.db.exec(`
|
|
52
|
+
CREATE TABLE IF NOT EXISTS buffered_signals (
|
|
53
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
54
|
+
payload TEXT NOT NULL,
|
|
55
|
+
timestamp INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000),
|
|
56
|
+
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
57
|
+
evidence_grade TEXT NOT NULL DEFAULT 'EMPTY'
|
|
58
|
+
)
|
|
59
|
+
`);
|
|
60
|
+
this.db.exec(`
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_signals_timestamp ON buffered_signals(timestamp)
|
|
62
|
+
`);
|
|
63
|
+
this.db.exec(`
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_signals_evidence_grade ON buffered_signals(evidence_grade)
|
|
65
|
+
`);
|
|
66
|
+
// Migrate existing rows that lack evidence_grade (from pre-0.2.2 databases)
|
|
67
|
+
try {
|
|
68
|
+
// Check if evidence_grade column exists by querying pragma
|
|
69
|
+
const columns = this.db
|
|
70
|
+
.prepare("PRAGMA table_info('buffered_signals')")
|
|
71
|
+
.all();
|
|
72
|
+
const hasGradeCol = columns.some((c) => c.name === 'evidence_grade');
|
|
73
|
+
if (!hasGradeCol) {
|
|
74
|
+
this.db.exec("ALTER TABLE buffered_signals ADD COLUMN evidence_grade TEXT NOT NULL DEFAULT 'EMPTY'");
|
|
75
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_signals_evidence_grade ON buffered_signals(evidence_grade)");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Column already exists or migration not needed
|
|
80
|
+
}
|
|
81
|
+
// Prepared statements
|
|
82
|
+
this.insertStmt = this.db.prepare('INSERT INTO buffered_signals (payload, timestamp, retry_count, evidence_grade) VALUES (?, ?, 0, ?)');
|
|
83
|
+
this.getOldestStmt = this.db.prepare(`
|
|
84
|
+
SELECT id, payload, timestamp, retry_count as retryCount, evidence_grade as evidenceGrade
|
|
85
|
+
FROM buffered_signals
|
|
86
|
+
ORDER BY
|
|
87
|
+
CASE evidence_grade
|
|
88
|
+
WHEN 'FACE_BACKED' THEN 1
|
|
89
|
+
WHEN 'PERSON_BACKED' THEN 2
|
|
90
|
+
WHEN 'SPEECH_ONLY' THEN 3
|
|
91
|
+
WHEN 'PROXY_ONLY' THEN 4
|
|
92
|
+
ELSE 5
|
|
93
|
+
END,
|
|
94
|
+
timestamp ASC
|
|
95
|
+
LIMIT ?
|
|
96
|
+
`);
|
|
97
|
+
this.deleteByIdStmt = this.db.prepare('DELETE FROM buffered_signals WHERE id = ?');
|
|
98
|
+
this.countStmt = this.db.prepare('SELECT COUNT(*) as count FROM buffered_signals');
|
|
99
|
+
this.pruneStmt = this.db.prepare('DELETE FROM buffered_signals WHERE timestamp < ?');
|
|
100
|
+
this.deleteOldestNStmt = this.db.prepare('DELETE FROM buffered_signals WHERE id IN (SELECT id FROM buffered_signals ORDER BY timestamp ASC LIMIT ?)');
|
|
101
|
+
this.incrementRetryStmt = this.db.prepare('UPDATE buffered_signals SET retry_count = retry_count + 1 WHERE id = ?');
|
|
102
|
+
this.deleteMaxRetriesStmt = this.db.prepare('DELETE FROM buffered_signals WHERE retry_count >= ?');
|
|
103
|
+
this.statsStmt = this.db.prepare('SELECT evidence_grade as grade, COUNT(*) as cnt FROM buffered_signals GROUP BY evidence_grade');
|
|
104
|
+
this.oldestStmt = this.db.prepare('SELECT MIN(timestamp) as oldest FROM buffered_signals');
|
|
105
|
+
}
|
|
106
|
+
extractEvidenceGrade(payload) {
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JSON.parse(payload);
|
|
109
|
+
return typeof parsed.evidenceGrade === 'string'
|
|
110
|
+
? parsed.evidenceGrade
|
|
111
|
+
: 'EMPTY';
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return 'EMPTY';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
insert(payload, timestamp) {
|
|
118
|
+
const grade = this.extractEvidenceGrade(payload);
|
|
119
|
+
this.insertStmt.run(payload, timestamp, grade);
|
|
120
|
+
}
|
|
121
|
+
getOldest(limit) {
|
|
122
|
+
return this.getOldestStmt.all(limit);
|
|
123
|
+
}
|
|
124
|
+
deleteById(id) {
|
|
125
|
+
this.deleteByIdStmt.run(id);
|
|
126
|
+
}
|
|
127
|
+
deleteOlderThan(cutoffMs) {
|
|
128
|
+
const result = this.pruneStmt.run(cutoffMs);
|
|
129
|
+
return result.changes;
|
|
130
|
+
}
|
|
131
|
+
deleteOldestN(n) {
|
|
132
|
+
this.deleteOldestNStmt.run(n);
|
|
133
|
+
}
|
|
134
|
+
deleteExceedingRetries(maxRetries) {
|
|
135
|
+
this.deleteMaxRetriesStmt.run(maxRetries);
|
|
136
|
+
}
|
|
137
|
+
incrementRetry(id) {
|
|
138
|
+
this.incrementRetryStmt.run(id);
|
|
139
|
+
}
|
|
140
|
+
count() {
|
|
141
|
+
const row = this.countStmt.get();
|
|
142
|
+
return row.count;
|
|
143
|
+
}
|
|
144
|
+
stats() {
|
|
145
|
+
const rows = this.statsStmt.all();
|
|
146
|
+
const byGrade = {};
|
|
147
|
+
for (const row of rows) {
|
|
148
|
+
byGrade[row.grade] = row.cnt;
|
|
149
|
+
}
|
|
150
|
+
const oldestRow = this.oldestStmt.get();
|
|
151
|
+
return {
|
|
152
|
+
total: this.count(),
|
|
153
|
+
byEvidenceGrade: byGrade,
|
|
154
|
+
oldestTimestampMs: oldestRow.oldest,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
close() {
|
|
158
|
+
this.db.close();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.SqliteStore = SqliteStore;
|
|
162
|
+
//# sourceMappingURL=SqliteStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqliteStore.js","sourceRoot":"","sources":["../src/SqliteStore.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ export { SocketManager } from './SocketManager';
|
|
|
5
5
|
export type { SocketManagerOptions } from './SocketManager';
|
|
6
6
|
export { VASWeightConfig } from './VASWeightConfig';
|
|
7
7
|
export { SignalBuffer } from './SignalBuffer';
|
|
8
|
+
export type { SignalStore, StoredSignal, SignalStoreStats } from './SignalStore';
|
|
9
|
+
export { JsonFileStore } from './JsonFileStore';
|
|
10
|
+
export { SqliteStore } from './SqliteStore';
|
|
8
11
|
export { SubsystemHealthRegistry } from './SubsystemHealthRegistry';
|
|
9
12
|
export { RecoveryLadder } from './RecoveryLadder';
|
|
10
13
|
export type { RecoveryCallbacks } from './RecoveryLadder';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EACL,yBAAyB,EACzB,KAAK,mBAAmB,GACzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EACL,yBAAyB,EACzB,KAAK,mBAAmB,GACzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.getAttenuationTier = exports.getShedOrder = exports.isModelActive = exports.getCapabilityMatrix = exports.computeTier = exports.classifyObservationSignal = exports.TelemetryScheduler = exports.RecoveryLadder = exports.SubsystemHealthRegistry = exports.SignalBuffer = exports.VASWeightConfig = exports.SocketManager = exports.SensingConfig = exports.DeviceIdentity = void 0;
|
|
18
|
+
exports.getAttenuationTier = exports.getShedOrder = exports.isModelActive = exports.getCapabilityMatrix = exports.computeTier = exports.classifyObservationSignal = exports.TelemetryScheduler = exports.RecoveryLadder = exports.SubsystemHealthRegistry = exports.SqliteStore = exports.JsonFileStore = exports.SignalBuffer = exports.VASWeightConfig = exports.SocketManager = exports.SensingConfig = exports.DeviceIdentity = void 0;
|
|
19
19
|
__exportStar(require("./types"), exports);
|
|
20
20
|
var DeviceIdentity_1 = require("./DeviceIdentity");
|
|
21
21
|
Object.defineProperty(exports, "DeviceIdentity", { enumerable: true, get: function () { return DeviceIdentity_1.DeviceIdentity; } });
|
|
@@ -27,6 +27,10 @@ var VASWeightConfig_1 = require("./VASWeightConfig");
|
|
|
27
27
|
Object.defineProperty(exports, "VASWeightConfig", { enumerable: true, get: function () { return VASWeightConfig_1.VASWeightConfig; } });
|
|
28
28
|
var SignalBuffer_1 = require("./SignalBuffer");
|
|
29
29
|
Object.defineProperty(exports, "SignalBuffer", { enumerable: true, get: function () { return SignalBuffer_1.SignalBuffer; } });
|
|
30
|
+
var JsonFileStore_1 = require("./JsonFileStore");
|
|
31
|
+
Object.defineProperty(exports, "JsonFileStore", { enumerable: true, get: function () { return JsonFileStore_1.JsonFileStore; } });
|
|
32
|
+
var SqliteStore_1 = require("./SqliteStore");
|
|
33
|
+
Object.defineProperty(exports, "SqliteStore", { enumerable: true, get: function () { return SqliteStore_1.SqliteStore; } });
|
|
30
34
|
var SubsystemHealthRegistry_1 = require("./SubsystemHealthRegistry");
|
|
31
35
|
Object.defineProperty(exports, "SubsystemHealthRegistry", { enumerable: true, get: function () { return SubsystemHealthRegistry_1.SubsystemHealthRegistry; } });
|
|
32
36
|
var RecoveryLadder_1 = require("./RecoveryLadder");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sFAAsF;;;;;;;;;;;;;;;;;AAEtF,0CAAwB;AACxB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sFAAsF;;;;;;;;;;;;;;;;;AAEtF,0CAAwB;AACxB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,qEAAoE;AAA3D,kIAAA,uBAAuB,OAAA;AAChC,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAE3B,6EAGuC;AAFrC,wIAAA,yBAAyB,OAAA;AAG3B,iDAMyB;AALvB,4GAAA,WAAW,OAAA;AACX,oHAAA,mBAAmB,OAAA;AACnB,8GAAA,aAAa,OAAA;AACb,6GAAA,YAAY,OAAA;AACZ,mHAAA,kBAAkB,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trillboards/edge-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Core identity, heartbeat, Socket.io, config, and signal buffer for Trillboards Edge AI SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
"prepublishOnly": "npm run build"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"better-sqlite3": "^11.0.0",
|
|
15
14
|
"socket.io-client": "^4.7.0",
|
|
16
15
|
"uuid": "^9.0.0"
|
|
17
16
|
},
|
|
17
|
+
"optionalDependencies": {
|
|
18
|
+
"better-sqlite3": "^11.0.0"
|
|
19
|
+
},
|
|
18
20
|
"devDependencies": {
|
|
19
21
|
"@types/better-sqlite3": "^7.6.0",
|
|
20
22
|
"@types/jest": "^29.5.0",
|