@camstack/core 0.1.13 → 0.1.15
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/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +220 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js.map +1 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +9 -0
- package/dist/builtins/addon-pages-aggregator/index.js +222 -0
- package/dist/builtins/addon-pages-aggregator/index.js.map +1 -0
- package/dist/builtins/addon-pages-aggregator/index.mjs +9 -0
- package/dist/builtins/addon-pages-aggregator/index.mjs.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +200 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +9 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.js +202 -0
- package/dist/builtins/addon-widgets-aggregator/index.js.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.mjs +9 -0
- package/dist/builtins/addon-widgets-aggregator/index.mjs.map +1 -0
- package/dist/builtins/alerts/alerts.addon.js +443 -0
- package/dist/builtins/alerts/alerts.addon.js.map +1 -0
- package/dist/builtins/alerts/alerts.addon.mjs +9 -0
- package/dist/builtins/alerts/alerts.addon.mjs.map +1 -0
- package/dist/builtins/alerts/index.js +443 -0
- package/dist/builtins/alerts/index.js.map +1 -0
- package/dist/builtins/alerts/index.mjs +8 -0
- package/dist/builtins/alerts/index.mjs.map +1 -0
- package/dist/builtins/console-logging/index.js +242 -0
- package/dist/builtins/console-logging/index.js.map +1 -0
- package/dist/builtins/console-logging/index.mjs +11 -0
- package/dist/builtins/console-logging/index.mjs.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.js +2155 -0
- package/dist/builtins/device-manager/device-manager.addon.js.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.mjs +9 -0
- package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -0
- package/dist/builtins/device-manager/index.js +2157 -0
- package/dist/builtins/device-manager/index.js.map +1 -0
- package/dist/builtins/device-manager/index.mjs +10 -0
- package/dist/builtins/device-manager/index.mjs.map +1 -0
- package/dist/builtins/hub-forwarder/index.js +297 -0
- package/dist/builtins/hub-forwarder/index.js.map +1 -0
- package/dist/builtins/hub-forwarder/index.mjs +11 -0
- package/dist/builtins/hub-forwarder/index.mjs.map +1 -0
- package/dist/builtins/local-auth/index.js +623 -0
- package/dist/builtins/local-auth/index.js.map +1 -0
- package/dist/builtins/local-auth/index.mjs +8 -0
- package/dist/builtins/local-auth/index.mjs.map +1 -0
- package/dist/builtins/local-auth/local-auth.addon.js +623 -0
- package/dist/builtins/local-auth/local-auth.addon.js.map +1 -0
- package/dist/builtins/local-auth/local-auth.addon.mjs +9 -0
- package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -0
- package/dist/builtins/local-backup/index.js +53 -68
- package/dist/builtins/local-backup/index.js.map +1 -1
- package/dist/builtins/local-backup/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +898 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js.map +1 -0
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +7 -0
- package/dist/builtins/native-metrics/native-metrics.addon.mjs.map +1 -0
- package/dist/builtins/snapshot/index.js +504 -0
- package/dist/builtins/snapshot/index.js.map +1 -0
- package/dist/builtins/snapshot/index.mjs +477 -0
- package/dist/builtins/snapshot/index.mjs.map +1 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +16 -166
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js.map +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +554 -621
- package/dist/builtins/sqlite-storage/index.js.map +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +9 -11
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +368 -130
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js.map +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/system-config/index.js +189 -0
- package/dist/builtins/system-config/index.js.map +1 -0
- package/dist/builtins/system-config/index.mjs +10 -0
- package/dist/builtins/system-config/index.mjs.map +1 -0
- package/dist/builtins/system-config/system-config.addon.js +187 -0
- package/dist/builtins/system-config/system-config.addon.js.map +1 -0
- package/dist/builtins/system-config/system-config.addon.mjs +9 -0
- package/dist/builtins/system-config/system-config.addon.mjs.map +1 -0
- package/dist/builtins/winston-logging/index.js +185 -65
- package/dist/builtins/winston-logging/index.js.map +1 -1
- package/dist/builtins/winston-logging/index.mjs +2 -1
- package/dist/chunk-2CIYKDRN.mjs +1 -0
- package/dist/chunk-2CIYKDRN.mjs.map +1 -0
- package/dist/chunk-2F76X6NL.mjs +136 -0
- package/dist/chunk-2F76X6NL.mjs.map +1 -0
- package/dist/chunk-2QUFBZ7M.mjs +1 -0
- package/dist/chunk-2QUFBZ7M.mjs.map +1 -0
- package/dist/chunk-3BK2Y7GY.mjs +593 -0
- package/dist/chunk-3BK2Y7GY.mjs.map +1 -0
- package/dist/chunk-4OOHFJHT.mjs +421 -0
- package/dist/chunk-4OOHFJHT.mjs.map +1 -0
- package/dist/chunk-4XHB7IHT.mjs +809 -0
- package/dist/chunk-4XHB7IHT.mjs.map +1 -0
- package/dist/{chunk-2F3XZYRW.mjs → chunk-6M2HSSTQ.mjs} +16 -7
- package/dist/chunk-6M2HSSTQ.mjs.map +1 -0
- package/dist/{chunk-SO4LROOT.mjs → chunk-7FI7SQS7.mjs} +54 -69
- package/dist/chunk-7FI7SQS7.mjs.map +1 -0
- package/dist/chunk-ED57RCQE.mjs +171 -0
- package/dist/chunk-ED57RCQE.mjs.map +1 -0
- package/dist/chunk-FZN56HGQ.mjs +626 -0
- package/dist/chunk-FZN56HGQ.mjs.map +1 -0
- package/dist/chunk-GL4OOB25.mjs +51 -0
- package/dist/chunk-GL4OOB25.mjs.map +1 -0
- package/dist/chunk-KDG2NTDB.mjs +137 -0
- package/dist/chunk-KDG2NTDB.mjs.map +1 -0
- package/dist/chunk-NRBQWBDM.mjs +191 -0
- package/dist/chunk-NRBQWBDM.mjs.map +1 -0
- package/dist/chunk-O4V246GG.mjs +2137 -0
- package/dist/chunk-O4V246GG.mjs.map +1 -0
- package/dist/chunk-QT57H266.mjs +163 -0
- package/dist/chunk-QT57H266.mjs.map +1 -0
- package/dist/chunk-QX4RH25I.mjs +141 -0
- package/dist/chunk-QX4RH25I.mjs.map +1 -0
- package/dist/chunk-TB562PZX.mjs +86 -0
- package/dist/chunk-TB562PZX.mjs.map +1 -0
- package/dist/chunk-TDYPZXK5.mjs +1 -0
- package/dist/chunk-TDYPZXK5.mjs.map +1 -0
- package/dist/chunk-UJI4LN5P.mjs +36 -0
- package/dist/chunk-UJI4LN5P.mjs.map +1 -0
- package/dist/chunk-W6RTHQGP.mjs +1 -0
- package/dist/chunk-W6RTHQGP.mjs.map +1 -0
- package/dist/chunk-ZELBCPDC.mjs +369 -0
- package/dist/chunk-ZELBCPDC.mjs.map +1 -0
- package/dist/index.d.mts +1103 -544
- package/dist/index.d.ts +1103 -544
- package/dist/index.js +7032 -6033
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +568 -2226
- package/dist/index.mjs.map +1 -1
- package/dist/resource-monitor-UZUGPIAU.mjs +9 -0
- package/dist/resource-monitor-UZUGPIAU.mjs.map +1 -0
- package/dist/storage-location-manager-HFNB3PCS.mjs +7 -0
- package/dist/storage-location-manager-HFNB3PCS.mjs.map +1 -0
- package/package.json +123 -2
- package/dist/builtins/local-backup/index.d.mts +0 -42
- package/dist/builtins/local-backup/index.d.ts +0 -42
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.mts +0 -2
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +0 -2
- package/dist/builtins/sqlite-storage/index.d.mts +0 -4
- package/dist/builtins/sqlite-storage/index.d.ts +0 -4
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.mts +0 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +0 -2
- package/dist/builtins/winston-logging/index.d.mts +0 -30
- package/dist/builtins/winston-logging/index.d.ts +0 -30
- package/dist/chunk-2F3XZYRW.mjs.map +0 -1
- package/dist/chunk-LQFPAEQF.mjs +0 -147
- package/dist/chunk-LQFPAEQF.mjs.map +0 -1
- package/dist/chunk-R3DIIBBX.mjs +0 -532
- package/dist/chunk-R3DIIBBX.mjs.map +0 -1
- package/dist/chunk-SMNR44VG.mjs +0 -386
- package/dist/chunk-SMNR44VG.mjs.map +0 -1
- package/dist/chunk-SO4LROOT.mjs.map +0 -1
- package/dist/chunk-SPA4JBKN.mjs +0 -175
- package/dist/chunk-SPA4JBKN.mjs.map +0 -1
- package/dist/dist-3BY63UQ5.mjs +0 -2151
- package/dist/dist-3BY63UQ5.mjs.map +0 -1
- package/dist/filesystem-storage.addon-C42r589X.d.mts +0 -57
- package/dist/filesystem-storage.addon-C42r589X.d.ts +0 -57
- package/dist/sql-schema-CKz78rId.d.mts +0 -97
- package/dist/sql-schema-CKz78rId.d.ts +0 -97
- package/dist/sqlite-settings.addon-KwG-uKMP.d.mts +0 -79
- package/dist/sqlite-settings.addon-KwG-uKMP.d.ts +0 -79
- package/dist/storage-location-manager-KKDQNAKA.mjs +0 -7
- /package/dist/{storage-location-manager-KKDQNAKA.mjs.map → builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs.map} +0 -0
package/dist/chunk-SMNR44VG.mjs
DELETED
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
// src/builtins/sqlite-storage/sqlite-settings-backend.ts
|
|
2
|
-
import Database from "better-sqlite3";
|
|
3
|
-
import { randomUUID } from "crypto";
|
|
4
|
-
var SqliteSettingsBackend = class {
|
|
5
|
-
constructor(dbPath, runtimeDefaults) {
|
|
6
|
-
this.dbPath = dbPath;
|
|
7
|
-
this.runtimeDefaults = runtimeDefaults ?? {};
|
|
8
|
-
}
|
|
9
|
-
db = null;
|
|
10
|
-
ensuredTables = /* @__PURE__ */ new Set();
|
|
11
|
-
structuredTables = /* @__PURE__ */ new Set();
|
|
12
|
-
runtimeDefaults;
|
|
13
|
-
async initialize() {
|
|
14
|
-
const dir = this.dbPath.substring(0, this.dbPath.lastIndexOf("/"));
|
|
15
|
-
if (dir) {
|
|
16
|
-
const fs = await import("fs");
|
|
17
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
this.db = new Database(this.dbPath);
|
|
20
|
-
this.db.pragma("journal_mode = WAL");
|
|
21
|
-
this.db.pragma("foreign_keys = ON");
|
|
22
|
-
const isEmpty = await this.isEmpty("system-settings");
|
|
23
|
-
if (isEmpty) {
|
|
24
|
-
await this.seedDefaults();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
async shutdown() {
|
|
28
|
-
this.db?.close();
|
|
29
|
-
this.db = null;
|
|
30
|
-
}
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// ISettingsBackend implementation
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
async get(collection, key) {
|
|
35
|
-
this.ensureCollectionTable(collection);
|
|
36
|
-
const row = this.getDb().prepare(`SELECT data FROM "${collection}" WHERE id = ?`).get(key);
|
|
37
|
-
if (!row) return void 0;
|
|
38
|
-
return JSON.parse(row.data);
|
|
39
|
-
}
|
|
40
|
-
async set(collection, key, value) {
|
|
41
|
-
this.ensureCollectionTable(collection);
|
|
42
|
-
this.getDb().prepare(`INSERT INTO "${collection}" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`).run(key, JSON.stringify(value));
|
|
43
|
-
}
|
|
44
|
-
async query(collection, filter) {
|
|
45
|
-
this.ensureCollectionTable(collection);
|
|
46
|
-
let sql = `SELECT id, data FROM "${collection}"`;
|
|
47
|
-
const params = [];
|
|
48
|
-
const whereClauses = [];
|
|
49
|
-
if (filter?.where) {
|
|
50
|
-
for (const [field, value] of Object.entries(filter.where)) {
|
|
51
|
-
if (field === "id") {
|
|
52
|
-
whereClauses.push("id = ?");
|
|
53
|
-
params.push(value);
|
|
54
|
-
} else {
|
|
55
|
-
whereClauses.push(`json_extract(data, '$.${field}') = ?`);
|
|
56
|
-
params.push(typeof value === "object" ? JSON.stringify(value) : value);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
if (filter?.whereIn) {
|
|
61
|
-
for (const [field, values] of Object.entries(filter.whereIn)) {
|
|
62
|
-
const placeholders = values.map(() => "?").join(", ");
|
|
63
|
-
if (field === "id") {
|
|
64
|
-
whereClauses.push(`id IN (${placeholders})`);
|
|
65
|
-
} else {
|
|
66
|
-
whereClauses.push(`json_extract(data, '$.${field}') IN (${placeholders})`);
|
|
67
|
-
}
|
|
68
|
-
params.push(...values);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (filter?.whereBetween) {
|
|
72
|
-
for (const [field, [low, high]] of Object.entries(filter.whereBetween)) {
|
|
73
|
-
if (field === "id") {
|
|
74
|
-
whereClauses.push("id BETWEEN ? AND ?");
|
|
75
|
-
} else {
|
|
76
|
-
whereClauses.push(`json_extract(data, '$.${field}') BETWEEN ? AND ?`);
|
|
77
|
-
}
|
|
78
|
-
params.push(low, high);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (whereClauses.length > 0) {
|
|
82
|
-
sql += ` WHERE ${whereClauses.join(" AND ")}`;
|
|
83
|
-
}
|
|
84
|
-
if (filter?.orderBy) {
|
|
85
|
-
const dir = filter.orderBy.direction === "desc" ? "DESC" : "ASC";
|
|
86
|
-
if (filter.orderBy.field === "id") {
|
|
87
|
-
sql += ` ORDER BY id ${dir}`;
|
|
88
|
-
} else {
|
|
89
|
-
sql += ` ORDER BY json_extract(data, '$.${filter.orderBy.field}') ${dir}`;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (filter?.limit) {
|
|
93
|
-
sql += ` LIMIT ?`;
|
|
94
|
-
params.push(filter.limit);
|
|
95
|
-
}
|
|
96
|
-
if (filter?.offset) {
|
|
97
|
-
sql += ` OFFSET ?`;
|
|
98
|
-
params.push(filter.offset);
|
|
99
|
-
}
|
|
100
|
-
const rows = this.getDb().prepare(sql).all(...params);
|
|
101
|
-
return rows.map((row) => ({
|
|
102
|
-
id: row.id,
|
|
103
|
-
data: JSON.parse(row.data)
|
|
104
|
-
}));
|
|
105
|
-
}
|
|
106
|
-
async insert(collection, record) {
|
|
107
|
-
this.ensureCollectionTable(collection);
|
|
108
|
-
const id = record.id || randomUUID();
|
|
109
|
-
this.getDb().prepare(`INSERT INTO "${collection}" (id, data) VALUES (?, ?)`).run(id, JSON.stringify(record.data));
|
|
110
|
-
}
|
|
111
|
-
async update(collection, id, data) {
|
|
112
|
-
this.ensureCollectionTable(collection);
|
|
113
|
-
this.getDb().prepare(`UPDATE "${collection}" SET data = ? WHERE id = ?`).run(JSON.stringify(data), id);
|
|
114
|
-
}
|
|
115
|
-
async delete(collection, key) {
|
|
116
|
-
this.ensureCollectionTable(collection);
|
|
117
|
-
this.getDb().prepare(`DELETE FROM "${collection}" WHERE id = ?`).run(key);
|
|
118
|
-
}
|
|
119
|
-
async count(collection, filter) {
|
|
120
|
-
this.ensureCollectionTable(collection);
|
|
121
|
-
if (!filter) {
|
|
122
|
-
const row = this.getDb().prepare(`SELECT COUNT(*) AS cnt FROM "${collection}"`).get();
|
|
123
|
-
return row?.cnt ?? 0;
|
|
124
|
-
}
|
|
125
|
-
const rows = await this.query(collection, { ...filter, limit: void 0, offset: void 0 });
|
|
126
|
-
return rows.length;
|
|
127
|
-
}
|
|
128
|
-
async isEmpty(collection) {
|
|
129
|
-
this.ensureCollectionTable(collection);
|
|
130
|
-
const row = this.getDb().prepare(`SELECT COUNT(*) AS cnt FROM "${collection}"`).get();
|
|
131
|
-
return (row?.cnt ?? 0) === 0;
|
|
132
|
-
}
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
// Legacy SettingsStore compatibility (used by ConfigManager.setSettingsStore)
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
|
-
/** Get a system setting by dot-notation key */
|
|
137
|
-
getSystem(key) {
|
|
138
|
-
this.ensureCollectionTable("system-settings");
|
|
139
|
-
const row = this.getDb().prepare('SELECT data FROM "system-settings" WHERE id = ?').get(key);
|
|
140
|
-
if (!row) return void 0;
|
|
141
|
-
return JSON.parse(row.data);
|
|
142
|
-
}
|
|
143
|
-
/** Set a system setting */
|
|
144
|
-
setSystem(key, value) {
|
|
145
|
-
this.ensureCollectionTable("system-settings");
|
|
146
|
-
this.getDb().prepare('INSERT INTO "system-settings" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data').run(key, JSON.stringify(value));
|
|
147
|
-
}
|
|
148
|
-
/** Get all system settings as flat key-value */
|
|
149
|
-
getAllSystem() {
|
|
150
|
-
this.ensureCollectionTable("system-settings");
|
|
151
|
-
const rows = this.getDb().prepare('SELECT id, data FROM "system-settings"').all();
|
|
152
|
-
return Object.fromEntries(rows.map((r) => [r.id, JSON.parse(r.data)]));
|
|
153
|
-
}
|
|
154
|
-
/** Get all settings for an addon */
|
|
155
|
-
getAllAddon(addonId) {
|
|
156
|
-
this.ensureCollectionTable("addon-settings");
|
|
157
|
-
const rows = this.getDb().prepare(`SELECT id, data FROM "addon-settings" WHERE json_extract(data, '$.addonId') = ?`).all(addonId);
|
|
158
|
-
if (rows.length === 0) return {};
|
|
159
|
-
const result = {};
|
|
160
|
-
for (const row of rows) {
|
|
161
|
-
const parsed = JSON.parse(row.data);
|
|
162
|
-
const key = row.id.startsWith(`${addonId}.`) ? row.id.slice(addonId.length + 1) : row.id;
|
|
163
|
-
result[key] = parsed.value ?? parsed;
|
|
164
|
-
}
|
|
165
|
-
return result;
|
|
166
|
-
}
|
|
167
|
-
/** Bulk-set all settings for an addon */
|
|
168
|
-
setAllAddon(addonId, config) {
|
|
169
|
-
this.ensureCollectionTable("addon-settings");
|
|
170
|
-
const db = this.getDb();
|
|
171
|
-
const deleteStmt = db.prepare(`DELETE FROM "addon-settings" WHERE id LIKE ? || '%'`);
|
|
172
|
-
const insertStmt = db.prepare('INSERT INTO "addon-settings" (id, data) VALUES (?, ?)');
|
|
173
|
-
db.transaction(() => {
|
|
174
|
-
deleteStmt.run(`${addonId}.`);
|
|
175
|
-
for (const [key, value] of Object.entries(config)) {
|
|
176
|
-
insertStmt.run(`${addonId}.${key}`, JSON.stringify({ addonId, key, value }));
|
|
177
|
-
}
|
|
178
|
-
})();
|
|
179
|
-
}
|
|
180
|
-
/** Get all settings for a provider */
|
|
181
|
-
getAllProvider(providerId) {
|
|
182
|
-
return this.getAllScoped("provider-settings", providerId);
|
|
183
|
-
}
|
|
184
|
-
/** Set a provider setting */
|
|
185
|
-
setProvider(providerId, key, value) {
|
|
186
|
-
this.setScopedKey("provider-settings", providerId, key, value);
|
|
187
|
-
}
|
|
188
|
-
/** Get all settings for a device */
|
|
189
|
-
getAllDevice(deviceId) {
|
|
190
|
-
return this.getAllScoped("device-settings", deviceId);
|
|
191
|
-
}
|
|
192
|
-
/** Set a device setting */
|
|
193
|
-
setDevice(deviceId, key, value) {
|
|
194
|
-
this.setScopedKey("device-settings", deviceId, key, value);
|
|
195
|
-
}
|
|
196
|
-
/** Seed system-settings with runtime defaults (first boot) */
|
|
197
|
-
async seedDefaults() {
|
|
198
|
-
this.ensureCollectionTable("system-settings");
|
|
199
|
-
const insert = this.getDb().prepare(
|
|
200
|
-
'INSERT OR IGNORE INTO "system-settings" (id, data) VALUES (?, ?)'
|
|
201
|
-
);
|
|
202
|
-
this.getDb().transaction(() => {
|
|
203
|
-
for (const [key, value] of Object.entries(this.runtimeDefaults)) {
|
|
204
|
-
insert.run(key, JSON.stringify(value));
|
|
205
|
-
}
|
|
206
|
-
})();
|
|
207
|
-
}
|
|
208
|
-
// ---------------------------------------------------------------------------
|
|
209
|
-
// Private helpers
|
|
210
|
-
// ---------------------------------------------------------------------------
|
|
211
|
-
getDb() {
|
|
212
|
-
if (!this.db) throw new Error("SqliteSettingsBackend not initialized \u2014 call initialize() first");
|
|
213
|
-
return this.db;
|
|
214
|
-
}
|
|
215
|
-
ensureCollectionTable(collection) {
|
|
216
|
-
if (this.ensuredTables.has(collection)) return;
|
|
217
|
-
this.getDb().exec(
|
|
218
|
-
`CREATE TABLE IF NOT EXISTS "${collection}" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`
|
|
219
|
-
);
|
|
220
|
-
this.ensuredTables.add(collection);
|
|
221
|
-
}
|
|
222
|
-
getAllScoped(collection, scopeId) {
|
|
223
|
-
this.ensureCollectionTable(collection);
|
|
224
|
-
const rows = this.getDb().prepare(`SELECT id, data FROM "${collection}" WHERE id LIKE ? || '.%'`).all(scopeId);
|
|
225
|
-
const result = {};
|
|
226
|
-
for (const row of rows) {
|
|
227
|
-
const key = row.id.slice(scopeId.length + 1);
|
|
228
|
-
const parsed = JSON.parse(row.data);
|
|
229
|
-
result[key] = parsed.value ?? parsed;
|
|
230
|
-
}
|
|
231
|
-
return result;
|
|
232
|
-
}
|
|
233
|
-
setScopedKey(collection, scopeId, key, value) {
|
|
234
|
-
this.ensureCollectionTable(collection);
|
|
235
|
-
this.getDb().prepare(`INSERT INTO "${collection}" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`).run(`${scopeId}.${key}`, JSON.stringify({ scopeId, key, value }));
|
|
236
|
-
}
|
|
237
|
-
// ── Structured table operations ────────────────────────────────────
|
|
238
|
-
async ensureTable(table, schema) {
|
|
239
|
-
if (!schema) {
|
|
240
|
-
if (!this.ensuredTables.has(table)) {
|
|
241
|
-
this.getDb().exec(`CREATE TABLE IF NOT EXISTS "${table}" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`);
|
|
242
|
-
this.ensuredTables.add(table);
|
|
243
|
-
}
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (this.structuredTables.has(table)) return;
|
|
247
|
-
const colDefs = schema.columns.map((col) => {
|
|
248
|
-
const parts = [`"${col.name}" ${col.type}`];
|
|
249
|
-
if (col.primaryKey) parts.push("PRIMARY KEY");
|
|
250
|
-
if (col.notNull) parts.push("NOT NULL");
|
|
251
|
-
if (col.unique) parts.push("UNIQUE");
|
|
252
|
-
if (col.defaultValue !== void 0) {
|
|
253
|
-
parts.push(`DEFAULT ${typeof col.defaultValue === "string" ? `'${col.defaultValue}'` : col.defaultValue === null ? "NULL" : String(col.defaultValue)}`);
|
|
254
|
-
}
|
|
255
|
-
return parts.join(" ");
|
|
256
|
-
});
|
|
257
|
-
this.getDb().exec(`CREATE TABLE IF NOT EXISTS "${table}" (${colDefs.join(", ")})`);
|
|
258
|
-
if (schema.indexes) {
|
|
259
|
-
for (const idx of schema.indexes) {
|
|
260
|
-
const unique = idx.unique ? "UNIQUE " : "";
|
|
261
|
-
const cols = idx.columns.map((c) => `"${c}"`).join(", ");
|
|
262
|
-
this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS "${idx.name}" ON "${table}" (${cols})`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
this.structuredTables.add(table);
|
|
266
|
-
}
|
|
267
|
-
async tableInsert(table, row) {
|
|
268
|
-
const keys = Object.keys(row);
|
|
269
|
-
const cols = keys.map((k) => `"${k}"`).join(", ");
|
|
270
|
-
const placeholders = keys.map(() => "?").join(", ");
|
|
271
|
-
const values = keys.map((k) => {
|
|
272
|
-
const v = row[k];
|
|
273
|
-
return typeof v === "object" && v !== null ? JSON.stringify(v) : v;
|
|
274
|
-
});
|
|
275
|
-
this.getDb().prepare(`INSERT INTO "${table}" (${cols}) VALUES (${placeholders})`).run(...values);
|
|
276
|
-
}
|
|
277
|
-
async tableUpdate(table, filter, updates) {
|
|
278
|
-
const setClauses = [];
|
|
279
|
-
const setValues = [];
|
|
280
|
-
for (const [k, v] of Object.entries(updates)) {
|
|
281
|
-
setClauses.push(`"${k}" = ?`);
|
|
282
|
-
setValues.push(typeof v === "object" && v !== null ? JSON.stringify(v) : v);
|
|
283
|
-
}
|
|
284
|
-
const { whereSql, whereValues } = this.buildWhere(filter);
|
|
285
|
-
const result = this.getDb().prepare(`UPDATE "${table}" SET ${setClauses.join(", ")}${whereSql}`).run(...setValues, ...whereValues);
|
|
286
|
-
return result.changes;
|
|
287
|
-
}
|
|
288
|
-
async tableDelete(table, filter) {
|
|
289
|
-
const { whereSql, whereValues } = this.buildWhere(filter);
|
|
290
|
-
const result = this.getDb().prepare(`DELETE FROM "${table}"${whereSql}`).run(...whereValues);
|
|
291
|
-
return result.changes;
|
|
292
|
-
}
|
|
293
|
-
async tableQuery(table, options) {
|
|
294
|
-
let sql = `SELECT * FROM "${table}"`;
|
|
295
|
-
const values = [];
|
|
296
|
-
if (options?.where) {
|
|
297
|
-
const { whereSql, whereValues } = this.buildWhere(options.where);
|
|
298
|
-
sql += whereSql;
|
|
299
|
-
values.push(...whereValues);
|
|
300
|
-
}
|
|
301
|
-
if (options?.orderBy) {
|
|
302
|
-
sql += ` ORDER BY "${options.orderBy.field}" ${options.orderBy.direction === "desc" ? "DESC" : "ASC"}`;
|
|
303
|
-
}
|
|
304
|
-
if (options?.limit !== void 0) {
|
|
305
|
-
sql += ` LIMIT ?`;
|
|
306
|
-
values.push(options.limit);
|
|
307
|
-
}
|
|
308
|
-
if (options?.offset !== void 0) {
|
|
309
|
-
sql += ` OFFSET ?`;
|
|
310
|
-
values.push(options.offset);
|
|
311
|
-
}
|
|
312
|
-
return this.getDb().prepare(sql).all(...values);
|
|
313
|
-
}
|
|
314
|
-
async tableGet(table, filter) {
|
|
315
|
-
const { whereSql, whereValues } = this.buildWhere(filter);
|
|
316
|
-
const row = this.getDb().prepare(`SELECT * FROM "${table}"${whereSql} LIMIT 1`).get(...whereValues);
|
|
317
|
-
return row ?? null;
|
|
318
|
-
}
|
|
319
|
-
async tableCount(table, filter) {
|
|
320
|
-
let sql = `SELECT COUNT(*) as count FROM "${table}"`;
|
|
321
|
-
const values = [];
|
|
322
|
-
if (filter) {
|
|
323
|
-
const { whereSql, whereValues } = this.buildWhere(filter);
|
|
324
|
-
sql += whereSql;
|
|
325
|
-
values.push(...whereValues);
|
|
326
|
-
}
|
|
327
|
-
const row = this.getDb().prepare(sql).get(...values);
|
|
328
|
-
return row.count;
|
|
329
|
-
}
|
|
330
|
-
buildWhere(filter) {
|
|
331
|
-
const conditions = [];
|
|
332
|
-
const values = [];
|
|
333
|
-
for (const [k, v] of Object.entries(filter)) {
|
|
334
|
-
conditions.push(`"${k}" = ?`);
|
|
335
|
-
values.push(typeof v === "object" && v !== null ? JSON.stringify(v) : v);
|
|
336
|
-
}
|
|
337
|
-
const whereSql = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
338
|
-
return { whereSql, whereValues: values };
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
// src/builtins/sqlite-storage/sqlite-settings.addon.ts
|
|
343
|
-
var SqliteSettingsAddon = class {
|
|
344
|
-
manifest = {
|
|
345
|
-
id: "sqlite-settings",
|
|
346
|
-
name: "SQLite Settings",
|
|
347
|
-
version: "1.0.0",
|
|
348
|
-
capabilities: [{ name: "settings-store", mode: "singleton" }]
|
|
349
|
-
};
|
|
350
|
-
backend = null;
|
|
351
|
-
async initialize(context) {
|
|
352
|
-
const dbPath = context.storageProvider ? context.storageProvider.resolve("addons-data", `${context.id.replace("addon:", "")}/camstack.db`) : context.dataDir ? `${context.dataDir}/camstack.db` : "camstack-data/addons-data/sqlite-settings/camstack.db";
|
|
353
|
-
const runtimeDefaults = context.addonConfig._runtimeDefaults ?? {};
|
|
354
|
-
this.backend = new SqliteSettingsBackend(dbPath, runtimeDefaults);
|
|
355
|
-
await this.backend.initialize();
|
|
356
|
-
context.logger.info(`SQLite settings initialized at ${dbPath}`);
|
|
357
|
-
}
|
|
358
|
-
async shutdown() {
|
|
359
|
-
await this.backend?.shutdown();
|
|
360
|
-
}
|
|
361
|
-
getBackend() {
|
|
362
|
-
return this.backend;
|
|
363
|
-
}
|
|
364
|
-
getCapabilityProvider(name) {
|
|
365
|
-
if (name === "settings-store" && this.backend) {
|
|
366
|
-
return this.backend;
|
|
367
|
-
}
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
getConfigSchema() {
|
|
371
|
-
return { sections: [] };
|
|
372
|
-
}
|
|
373
|
-
getConfig() {
|
|
374
|
-
return {};
|
|
375
|
-
}
|
|
376
|
-
async onConfigChange(_config) {
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
var sqlite_settings_addon_default = SqliteSettingsAddon;
|
|
380
|
-
|
|
381
|
-
export {
|
|
382
|
-
SqliteSettingsBackend,
|
|
383
|
-
SqliteSettingsAddon,
|
|
384
|
-
sqlite_settings_addon_default
|
|
385
|
-
};
|
|
386
|
-
//# sourceMappingURL=chunk-SMNR44VG.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builtins/sqlite-storage/sqlite-settings-backend.ts","../src/builtins/sqlite-storage/sqlite-settings.addon.ts"],"sourcesContent":["import Database from 'better-sqlite3'\nimport { randomUUID } from 'node:crypto'\nimport type {\n ISettingsBackend,\n SettingsCollection,\n SettingsRecord,\n QueryFilter,\n TableSchema,\n TableQueryOptions,\n} from '@camstack/types'\n\n/**\n * SQLite implementation of ISettingsBackend.\n *\n * One table per collection, auto-created on first access.\n * All data stored as JSON in a TEXT column.\n * WAL mode for concurrent reads.\n */\nexport class SqliteSettingsBackend implements ISettingsBackend {\n private db: Database.Database | null = null\n private readonly ensuredTables = new Set<string>()\n private readonly structuredTables = new Set<string>()\n private readonly runtimeDefaults: Record<string, unknown>\n\n constructor(private readonly dbPath: string, runtimeDefaults?: Record<string, unknown>) {\n this.runtimeDefaults = runtimeDefaults ?? {}\n }\n\n async initialize(): Promise<void> {\n // Ensure parent directory exists\n const dir = this.dbPath.substring(0, this.dbPath.lastIndexOf('/'))\n if (dir) {\n const fs = await import('node:fs')\n fs.mkdirSync(dir, { recursive: true })\n }\n this.db = new Database(this.dbPath)\n this.db.pragma('journal_mode = WAL')\n this.db.pragma('foreign_keys = ON')\n\n // Seed system-settings on first boot\n const isEmpty = await this.isEmpty('system-settings')\n if (isEmpty) {\n await this.seedDefaults()\n }\n }\n\n async shutdown(): Promise<void> {\n this.db?.close()\n this.db = null\n }\n\n // ---------------------------------------------------------------------------\n // ISettingsBackend implementation\n // ---------------------------------------------------------------------------\n\n async get(collection: SettingsCollection, key: string): Promise<unknown> {\n this.ensureCollectionTable(collection)\n const row = this.getDb()\n .prepare<[string], { data: string }>(`SELECT data FROM \"${collection}\" WHERE id = ?`)\n .get(key)\n if (!row) return undefined\n return JSON.parse(row.data)\n }\n\n async set(collection: SettingsCollection, key: string, value: unknown): Promise<void> {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`)\n .run(key, JSON.stringify(value))\n }\n\n async query(collection: SettingsCollection, filter?: QueryFilter): Promise<readonly SettingsRecord[]> {\n this.ensureCollectionTable(collection)\n let sql = `SELECT id, data FROM \"${collection}\"`\n const params: unknown[] = []\n\n const whereClauses: string[] = []\n\n if (filter?.where) {\n for (const [field, value] of Object.entries(filter.where)) {\n if (field === 'id') {\n whereClauses.push('id = ?')\n params.push(value)\n } else {\n whereClauses.push(`json_extract(data, '$.${field}') = ?`)\n params.push(typeof value === 'object' ? JSON.stringify(value) : value)\n }\n }\n }\n\n if (filter?.whereIn) {\n for (const [field, values] of Object.entries(filter.whereIn)) {\n const placeholders = values.map(() => '?').join(', ')\n if (field === 'id') {\n whereClauses.push(`id IN (${placeholders})`)\n } else {\n whereClauses.push(`json_extract(data, '$.${field}') IN (${placeholders})`)\n }\n params.push(...values)\n }\n }\n\n if (filter?.whereBetween) {\n for (const [field, [low, high]] of Object.entries(filter.whereBetween)) {\n if (field === 'id') {\n whereClauses.push('id BETWEEN ? AND ?')\n } else {\n whereClauses.push(`json_extract(data, '$.${field}') BETWEEN ? AND ?`)\n }\n params.push(low, high)\n }\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(' AND ')}`\n }\n\n if (filter?.orderBy) {\n const dir = filter.orderBy.direction === 'desc' ? 'DESC' : 'ASC'\n if (filter.orderBy.field === 'id') {\n sql += ` ORDER BY id ${dir}`\n } else {\n sql += ` ORDER BY json_extract(data, '$.${filter.orderBy.field}') ${dir}`\n }\n }\n\n if (filter?.limit) {\n sql += ` LIMIT ?`\n params.push(filter.limit)\n }\n\n if (filter?.offset) {\n sql += ` OFFSET ?`\n params.push(filter.offset)\n }\n\n const rows = this.getDb()\n .prepare<unknown[], { id: string; data: string }>(sql)\n .all(...params)\n\n return rows.map(row => ({\n id: row.id,\n data: JSON.parse(row.data),\n }))\n }\n\n async insert(collection: SettingsCollection, record: SettingsRecord): Promise<void> {\n this.ensureCollectionTable(collection)\n const id = record.id || randomUUID()\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?)`)\n .run(id, JSON.stringify(record.data))\n }\n\n async update(collection: SettingsCollection, id: string, data: Record<string, unknown>): Promise<void> {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`UPDATE \"${collection}\" SET data = ? WHERE id = ?`)\n .run(JSON.stringify(data), id)\n }\n\n async delete(collection: SettingsCollection, key: string): Promise<void> {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`DELETE FROM \"${collection}\" WHERE id = ?`)\n .run(key)\n }\n\n async count(collection: SettingsCollection, filter?: QueryFilter): Promise<number> {\n this.ensureCollectionTable(collection)\n if (!filter) {\n const row = this.getDb()\n .prepare<[], { cnt: number }>(`SELECT COUNT(*) AS cnt FROM \"${collection}\"`)\n .get()\n return row?.cnt ?? 0\n }\n const rows = await this.query(collection, { ...filter, limit: undefined, offset: undefined })\n return rows.length\n }\n\n async isEmpty(collection: SettingsCollection): Promise<boolean> {\n this.ensureCollectionTable(collection)\n const row = this.getDb()\n .prepare<[], { cnt: number }>(`SELECT COUNT(*) AS cnt FROM \"${collection}\"`)\n .get()\n return (row?.cnt ?? 0) === 0\n }\n\n // ---------------------------------------------------------------------------\n // Legacy SettingsStore compatibility (used by ConfigManager.setSettingsStore)\n // ---------------------------------------------------------------------------\n\n /** Get a system setting by dot-notation key */\n getSystem(key: string): unknown {\n this.ensureCollectionTable('system-settings')\n const row = this.getDb()\n .prepare<[string], { data: string }>('SELECT data FROM \"system-settings\" WHERE id = ?')\n .get(key)\n if (!row) return undefined\n return JSON.parse(row.data)\n }\n\n /** Set a system setting */\n setSystem(key: string, value: unknown): void {\n this.ensureCollectionTable('system-settings')\n this.getDb()\n .prepare('INSERT INTO \"system-settings\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data')\n .run(key, JSON.stringify(value))\n }\n\n /** Get all system settings as flat key-value */\n getAllSystem(): Record<string, unknown> {\n this.ensureCollectionTable('system-settings')\n const rows = this.getDb()\n .prepare<[], { id: string; data: string }>('SELECT id, data FROM \"system-settings\"')\n .all()\n return Object.fromEntries(rows.map(r => [r.id, JSON.parse(r.data)]))\n }\n\n /** Get all settings for an addon */\n getAllAddon(addonId: string): Record<string, unknown> {\n this.ensureCollectionTable('addon-settings')\n const rows = this.getDb()\n .prepare<[string], { id: string; data: string }>('SELECT id, data FROM \"addon-settings\" WHERE json_extract(data, \\'$.addonId\\') = ?')\n .all(addonId)\n if (rows.length === 0) return {}\n // addon-settings stores all keys for an addon as separate rows with id = \"addonId.key\"\n const result: Record<string, unknown> = {}\n for (const row of rows) {\n const parsed = JSON.parse(row.data)\n const key = row.id.startsWith(`${addonId}.`) ? row.id.slice(addonId.length + 1) : row.id\n result[key] = parsed.value ?? parsed\n }\n return result\n }\n\n /** Bulk-set all settings for an addon */\n setAllAddon(addonId: string, config: Record<string, unknown>): void {\n this.ensureCollectionTable('addon-settings')\n const db = this.getDb()\n const deleteStmt = db.prepare('DELETE FROM \"addon-settings\" WHERE id LIKE ? || \\'%\\'')\n const insertStmt = db.prepare('INSERT INTO \"addon-settings\" (id, data) VALUES (?, ?)')\n db.transaction(() => {\n deleteStmt.run(`${addonId}.`)\n for (const [key, value] of Object.entries(config)) {\n insertStmt.run(`${addonId}.${key}`, JSON.stringify({ addonId, key, value }))\n }\n })()\n }\n\n /** Get all settings for a provider */\n getAllProvider(providerId: string): Record<string, unknown> {\n return this.getAllScoped('provider-settings', providerId)\n }\n\n /** Set a provider setting */\n setProvider(providerId: string, key: string, value: unknown): void {\n this.setScopedKey('provider-settings', providerId, key, value)\n }\n\n /** Get all settings for a device */\n getAllDevice(deviceId: string): Record<string, unknown> {\n return this.getAllScoped('device-settings', deviceId)\n }\n\n /** Set a device setting */\n setDevice(deviceId: string, key: string, value: unknown): void {\n this.setScopedKey('device-settings', deviceId, key, value)\n }\n\n /** Seed system-settings with runtime defaults (first boot) */\n private async seedDefaults(): Promise<void> {\n this.ensureCollectionTable('system-settings')\n const insert = this.getDb().prepare(\n 'INSERT OR IGNORE INTO \"system-settings\" (id, data) VALUES (?, ?)',\n )\n this.getDb().transaction(() => {\n for (const [key, value] of Object.entries(this.runtimeDefaults)) {\n insert.run(key, JSON.stringify(value))\n }\n })()\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private getDb(): Database.Database {\n if (!this.db) throw new Error('SqliteSettingsBackend not initialized — call initialize() first')\n return this.db\n }\n\n private ensureCollectionTable(collection: string): void {\n if (this.ensuredTables.has(collection)) return\n this.getDb().exec(\n `CREATE TABLE IF NOT EXISTS \"${collection}\" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`,\n )\n this.ensuredTables.add(collection)\n }\n\n private getAllScoped(collection: string, scopeId: string): Record<string, unknown> {\n this.ensureCollectionTable(collection)\n const rows = this.getDb()\n .prepare<[string], { id: string; data: string }>(`SELECT id, data FROM \"${collection}\" WHERE id LIKE ? || '.%'`)\n .all(scopeId)\n const result: Record<string, unknown> = {}\n for (const row of rows) {\n const key = row.id.slice(scopeId.length + 1)\n const parsed = JSON.parse(row.data)\n result[key] = parsed.value ?? parsed\n }\n return result\n }\n\n private setScopedKey(collection: string, scopeId: string, key: string, value: unknown): void {\n this.ensureCollectionTable(collection)\n this.getDb()\n .prepare(`INSERT INTO \"${collection}\" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`)\n .run(`${scopeId}.${key}`, JSON.stringify({ scopeId, key, value }))\n }\n\n // ── Structured table operations ────────────────────────────────────\n\n async ensureTable(table: string, schema?: TableSchema): Promise<void> {\n if (!schema) {\n // Legacy: ensure JSON-blob collection table\n if (!this.ensuredTables.has(table)) {\n this.getDb().exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`)\n this.ensuredTables.add(table)\n }\n return\n }\n if (this.structuredTables.has(table)) return\n\n const colDefs = schema.columns.map(col => {\n const parts = [`\"${col.name}\" ${col.type}`]\n if (col.primaryKey) parts.push('PRIMARY KEY')\n if (col.notNull) parts.push('NOT NULL')\n if (col.unique) parts.push('UNIQUE')\n if (col.defaultValue !== undefined) {\n parts.push(`DEFAULT ${typeof col.defaultValue === 'string' ? `'${col.defaultValue}'` : col.defaultValue === null ? 'NULL' : String(col.defaultValue)}`)\n }\n return parts.join(' ')\n })\n\n this.getDb().exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs.join(', ')})`)\n\n if (schema.indexes) {\n for (const idx of schema.indexes) {\n const unique = idx.unique ? 'UNIQUE ' : ''\n const cols = idx.columns.map(c => `\"${c}\"`).join(', ')\n this.getDb().exec(`CREATE ${unique}INDEX IF NOT EXISTS \"${idx.name}\" ON \"${table}\" (${cols})`)\n }\n }\n\n this.structuredTables.add(table)\n }\n\n async tableInsert(table: string, row: Record<string, unknown>): Promise<void> {\n const keys = Object.keys(row)\n const cols = keys.map(k => `\"${k}\"`).join(', ')\n const placeholders = keys.map(() => '?').join(', ')\n const values = keys.map(k => {\n const v = row[k]\n return typeof v === 'object' && v !== null ? JSON.stringify(v) : v\n })\n this.getDb().prepare(`INSERT INTO \"${table}\" (${cols}) VALUES (${placeholders})`).run(...values)\n }\n\n async tableUpdate(table: string, filter: Record<string, unknown>, updates: Record<string, unknown>): Promise<number> {\n const setClauses: string[] = []\n const setValues: unknown[] = []\n for (const [k, v] of Object.entries(updates)) {\n setClauses.push(`\"${k}\" = ?`)\n setValues.push(typeof v === 'object' && v !== null ? JSON.stringify(v) : v)\n }\n\n const { whereSql, whereValues } = this.buildWhere(filter)\n const result = this.getDb()\n .prepare(`UPDATE \"${table}\" SET ${setClauses.join(', ')}${whereSql}`)\n .run(...setValues, ...whereValues)\n return result.changes\n }\n\n async tableDelete(table: string, filter: Record<string, unknown>): Promise<number> {\n const { whereSql, whereValues } = this.buildWhere(filter)\n const result = this.getDb().prepare(`DELETE FROM \"${table}\"${whereSql}`).run(...whereValues)\n return result.changes\n }\n\n async tableQuery(table: string, options?: TableQueryOptions): Promise<readonly Record<string, unknown>[]> {\n let sql = `SELECT * FROM \"${table}\"`\n const values: unknown[] = []\n\n if (options?.where) {\n const { whereSql, whereValues } = this.buildWhere(options.where)\n sql += whereSql\n values.push(...whereValues)\n }\n\n if (options?.orderBy) {\n sql += ` ORDER BY \"${options.orderBy.field}\" ${options.orderBy.direction === 'desc' ? 'DESC' : 'ASC'}`\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT ?`\n values.push(options.limit)\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET ?`\n values.push(options.offset)\n }\n\n return this.getDb().prepare(sql).all(...values) as Record<string, unknown>[]\n }\n\n async tableGet(table: string, filter: Record<string, unknown>): Promise<Record<string, unknown> | null> {\n const { whereSql, whereValues } = this.buildWhere(filter)\n const row = this.getDb().prepare(`SELECT * FROM \"${table}\"${whereSql} LIMIT 1`).get(...whereValues)\n return (row as Record<string, unknown>) ?? null\n }\n\n async tableCount(table: string, filter?: Record<string, unknown>): Promise<number> {\n let sql = `SELECT COUNT(*) as count FROM \"${table}\"`\n const values: unknown[] = []\n\n if (filter) {\n const { whereSql, whereValues } = this.buildWhere(filter)\n sql += whereSql\n values.push(...whereValues)\n }\n\n const row = this.getDb().prepare(sql).get(...values) as { count: number }\n return row.count\n }\n\n private buildWhere(filter: Record<string, unknown>): { whereSql: string; whereValues: unknown[] } {\n const conditions: string[] = []\n const values: unknown[] = []\n for (const [k, v] of Object.entries(filter)) {\n conditions.push(`\"${k}\" = ?`)\n values.push(typeof v === 'object' && v !== null ? JSON.stringify(v) : v)\n }\n const whereSql = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : ''\n return { whereSql, whereValues: values }\n }\n}\n\nexport default SqliteSettingsBackend\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n IConfigurable,\n ConfigUISchema,\n CapabilityProviderMap,\n} from '@camstack/types'\nimport { SqliteSettingsBackend } from './sqlite-settings-backend'\n\n/**\n * SQLite Settings addon — provides persistent settings storage.\n * Capability: 'settings-store' (singleton)\n *\n * Depends on 'storage' capability for resolving the DB file path.\n */\nexport class SqliteSettingsAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'sqlite-settings',\n name: 'SQLite Settings',\n version: '1.0.0',\n capabilities: [{ name: 'settings-store', mode: 'singleton' }],\n }\n\n private backend: SqliteSettingsBackend | null = null\n\n async initialize(context: AddonContext): Promise<void> {\n // Resolve DB path from storage provider (addons-data location)\n const dbPath = context.storageProvider\n ? context.storageProvider.resolve('addons-data', `${context.id.replace('addon:', '')}/camstack.db`)\n : context.dataDir\n ? `${context.dataDir}/camstack.db`\n : 'camstack-data/addons-data/sqlite-settings/camstack.db'\n\n const runtimeDefaults = (context.addonConfig._runtimeDefaults as Record<string, unknown>) ?? {}\n this.backend = new SqliteSettingsBackend(dbPath, runtimeDefaults)\n await this.backend.initialize()\n context.logger.info(`SQLite settings initialized at ${dbPath}`)\n }\n\n async shutdown(): Promise<void> {\n await this.backend?.shutdown()\n }\n\n getBackend(): SqliteSettingsBackend | null {\n return this.backend\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === ('settings-store' as string) && this.backend) {\n return this.backend as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return { sections: [] }\n }\n\n getConfig(): Record<string, unknown> {\n return {}\n }\n\n async onConfigChange(_config: Record<string, unknown>): Promise<void> {\n // DB path changes require restart\n }\n}\n\nexport default SqliteSettingsAddon\n"],"mappings":";AAAA,OAAO,cAAc;AACrB,SAAS,kBAAkB;AAiBpB,IAAM,wBAAN,MAAwD;AAAA,EAM7D,YAA6B,QAAgB,iBAA2C;AAA3D;AAC3B,SAAK,kBAAkB,mBAAmB,CAAC;AAAA,EAC7C;AAAA,EAPQ,KAA+B;AAAA,EACtB,gBAAgB,oBAAI,IAAY;AAAA,EAChC,mBAAmB,oBAAI,IAAY;AAAA,EACnC;AAAA,EAMjB,MAAM,aAA4B;AAEhC,UAAM,MAAM,KAAK,OAAO,UAAU,GAAG,KAAK,OAAO,YAAY,GAAG,CAAC;AACjE,QAAI,KAAK;AACP,YAAM,KAAK,MAAM,OAAO,IAAS;AACjC,SAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACvC;AACA,SAAK,KAAK,IAAI,SAAS,KAAK,MAAM;AAClC,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,GAAG,OAAO,mBAAmB;AAGlC,UAAM,UAAU,MAAM,KAAK,QAAQ,iBAAiB;AACpD,QAAI,SAAS;AACX,YAAM,KAAK,aAAa;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,SAAK,IAAI,MAAM;AACf,SAAK,KAAK;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,YAAgC,KAA+B;AACvE,SAAK,sBAAsB,UAAU;AACrC,UAAM,MAAM,KAAK,MAAM,EACpB,QAAoC,qBAAqB,UAAU,gBAAgB,EACnF,IAAI,GAAG;AACV,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EAC5B;AAAA,EAEA,MAAM,IAAI,YAAgC,KAAa,OAA+B;AACpF,SAAK,sBAAsB,UAAU;AACrC,SAAK,MAAM,EACR,QAAQ,gBAAgB,UAAU,+EAA+E,EACjH,IAAI,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EACnC;AAAA,EAEA,MAAM,MAAM,YAAgC,QAA0D;AACpG,SAAK,sBAAsB,UAAU;AACrC,QAAI,MAAM,yBAAyB,UAAU;AAC7C,UAAM,SAAoB,CAAC;AAE3B,UAAM,eAAyB,CAAC;AAEhC,QAAI,QAAQ,OAAO;AACjB,iBAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,OAAO,KAAK,GAAG;AACzD,YAAI,UAAU,MAAM;AAClB,uBAAa,KAAK,QAAQ;AAC1B,iBAAO,KAAK,KAAK;AAAA,QACnB,OAAO;AACL,uBAAa,KAAK,yBAAyB,KAAK,QAAQ;AACxD,iBAAO,KAAK,OAAO,UAAU,WAAW,KAAK,UAAU,KAAK,IAAI,KAAK;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS;AACnB,iBAAW,CAAC,OAAO,MAAM,KAAK,OAAO,QAAQ,OAAO,OAAO,GAAG;AAC5D,cAAM,eAAe,OAAO,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACpD,YAAI,UAAU,MAAM;AAClB,uBAAa,KAAK,UAAU,YAAY,GAAG;AAAA,QAC7C,OAAO;AACL,uBAAa,KAAK,yBAAyB,KAAK,UAAU,YAAY,GAAG;AAAA,QAC3E;AACA,eAAO,KAAK,GAAG,MAAM;AAAA,MACvB;AAAA,IACF;AAEA,QAAI,QAAQ,cAAc;AACxB,iBAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,KAAK,OAAO,QAAQ,OAAO,YAAY,GAAG;AACtE,YAAI,UAAU,MAAM;AAClB,uBAAa,KAAK,oBAAoB;AAAA,QACxC,OAAO;AACL,uBAAa,KAAK,yBAAyB,KAAK,oBAAoB;AAAA,QACtE;AACA,eAAO,KAAK,KAAK,IAAI;AAAA,MACvB;AAAA,IACF;AAEA,QAAI,aAAa,SAAS,GAAG;AAC3B,aAAO,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,IAC7C;AAEA,QAAI,QAAQ,SAAS;AACnB,YAAM,MAAM,OAAO,QAAQ,cAAc,SAAS,SAAS;AAC3D,UAAI,OAAO,QAAQ,UAAU,MAAM;AACjC,eAAO,gBAAgB,GAAG;AAAA,MAC5B,OAAO;AACL,eAAO,mCAAmC,OAAO,QAAQ,KAAK,MAAM,GAAG;AAAA,MACzE;AAAA,IACF;AAEA,QAAI,QAAQ,OAAO;AACjB,aAAO;AACP,aAAO,KAAK,OAAO,KAAK;AAAA,IAC1B;AAEA,QAAI,QAAQ,QAAQ;AAClB,aAAO;AACP,aAAO,KAAK,OAAO,MAAM;AAAA,IAC3B;AAEA,UAAM,OAAO,KAAK,MAAM,EACrB,QAAiD,GAAG,EACpD,IAAI,GAAG,MAAM;AAEhB,WAAO,KAAK,IAAI,UAAQ;AAAA,MACtB,IAAI,IAAI;AAAA,MACR,MAAM,KAAK,MAAM,IAAI,IAAI;AAAA,IAC3B,EAAE;AAAA,EACJ;AAAA,EAEA,MAAM,OAAO,YAAgC,QAAuC;AAClF,SAAK,sBAAsB,UAAU;AACrC,UAAM,KAAK,OAAO,MAAM,WAAW;AACnC,SAAK,MAAM,EACR,QAAQ,gBAAgB,UAAU,4BAA4B,EAC9D,IAAI,IAAI,KAAK,UAAU,OAAO,IAAI,CAAC;AAAA,EACxC;AAAA,EAEA,MAAM,OAAO,YAAgC,IAAY,MAA8C;AACrG,SAAK,sBAAsB,UAAU;AACrC,SAAK,MAAM,EACR,QAAQ,WAAW,UAAU,6BAA6B,EAC1D,IAAI,KAAK,UAAU,IAAI,GAAG,EAAE;AAAA,EACjC;AAAA,EAEA,MAAM,OAAO,YAAgC,KAA4B;AACvE,SAAK,sBAAsB,UAAU;AACrC,SAAK,MAAM,EACR,QAAQ,gBAAgB,UAAU,gBAAgB,EAClD,IAAI,GAAG;AAAA,EACZ;AAAA,EAEA,MAAM,MAAM,YAAgC,QAAuC;AACjF,SAAK,sBAAsB,UAAU;AACrC,QAAI,CAAC,QAAQ;AACX,YAAM,MAAM,KAAK,MAAM,EACpB,QAA6B,gCAAgC,UAAU,GAAG,EAC1E,IAAI;AACP,aAAO,KAAK,OAAO;AAAA,IACrB;AACA,UAAM,OAAO,MAAM,KAAK,MAAM,YAAY,EAAE,GAAG,QAAQ,OAAO,QAAW,QAAQ,OAAU,CAAC;AAC5F,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAQ,YAAkD;AAC9D,SAAK,sBAAsB,UAAU;AACrC,UAAM,MAAM,KAAK,MAAM,EACpB,QAA6B,gCAAgC,UAAU,GAAG,EAC1E,IAAI;AACP,YAAQ,KAAK,OAAO,OAAO;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,KAAsB;AAC9B,SAAK,sBAAsB,iBAAiB;AAC5C,UAAM,MAAM,KAAK,MAAM,EACpB,QAAoC,iDAAiD,EACrF,IAAI,GAAG;AACV,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EAC5B;AAAA;AAAA,EAGA,UAAU,KAAa,OAAsB;AAC3C,SAAK,sBAAsB,iBAAiB;AAC5C,SAAK,MAAM,EACR,QAAQ,2GAA2G,EACnH,IAAI,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EACnC;AAAA;AAAA,EAGA,eAAwC;AACtC,SAAK,sBAAsB,iBAAiB;AAC5C,UAAM,OAAO,KAAK,MAAM,EACrB,QAA0C,wCAAwC,EAClF,IAAI;AACP,WAAO,OAAO,YAAY,KAAK,IAAI,OAAK,CAAC,EAAE,IAAI,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,EACrE;AAAA;AAAA,EAGA,YAAY,SAA0C;AACpD,SAAK,sBAAsB,gBAAgB;AAC3C,UAAM,OAAO,KAAK,MAAM,EACrB,QAAgD,iFAAmF,EACnI,IAAI,OAAO;AACd,QAAI,KAAK,WAAW,EAAG,QAAO,CAAC;AAE/B,UAAM,SAAkC,CAAC;AACzC,eAAW,OAAO,MAAM;AACtB,YAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,YAAM,MAAM,IAAI,GAAG,WAAW,GAAG,OAAO,GAAG,IAAI,IAAI,GAAG,MAAM,QAAQ,SAAS,CAAC,IAAI,IAAI;AACtF,aAAO,GAAG,IAAI,OAAO,SAAS;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,YAAY,SAAiB,QAAuC;AAClE,SAAK,sBAAsB,gBAAgB;AAC3C,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,aAAa,GAAG,QAAQ,qDAAuD;AACrF,UAAM,aAAa,GAAG,QAAQ,uDAAuD;AACrF,OAAG,YAAY,MAAM;AACnB,iBAAW,IAAI,GAAG,OAAO,GAAG;AAC5B,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,mBAAW,IAAI,GAAG,OAAO,IAAI,GAAG,IAAI,KAAK,UAAU,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC;AAAA,MAC7E;AAAA,IACF,CAAC,EAAE;AAAA,EACL;AAAA;AAAA,EAGA,eAAe,YAA6C;AAC1D,WAAO,KAAK,aAAa,qBAAqB,UAAU;AAAA,EAC1D;AAAA;AAAA,EAGA,YAAY,YAAoB,KAAa,OAAsB;AACjE,SAAK,aAAa,qBAAqB,YAAY,KAAK,KAAK;AAAA,EAC/D;AAAA;AAAA,EAGA,aAAa,UAA2C;AACtD,WAAO,KAAK,aAAa,mBAAmB,QAAQ;AAAA,EACtD;AAAA;AAAA,EAGA,UAAU,UAAkB,KAAa,OAAsB;AAC7D,SAAK,aAAa,mBAAmB,UAAU,KAAK,KAAK;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAc,eAA8B;AAC1C,SAAK,sBAAsB,iBAAiB;AAC5C,UAAM,SAAS,KAAK,MAAM,EAAE;AAAA,MAC1B;AAAA,IACF;AACA,SAAK,MAAM,EAAE,YAAY,MAAM;AAC7B,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,eAAe,GAAG;AAC/D,eAAO,IAAI,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,MACvC;AAAA,IACF,CAAC,EAAE;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMQ,QAA2B;AACjC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,sEAAiE;AAC/F,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,sBAAsB,YAA0B;AACtD,QAAI,KAAK,cAAc,IAAI,UAAU,EAAG;AACxC,SAAK,MAAM,EAAE;AAAA,MACX,+BAA+B,UAAU;AAAA,IAC3C;AACA,SAAK,cAAc,IAAI,UAAU;AAAA,EACnC;AAAA,EAEQ,aAAa,YAAoB,SAA0C;AACjF,SAAK,sBAAsB,UAAU;AACrC,UAAM,OAAO,KAAK,MAAM,EACrB,QAAgD,yBAAyB,UAAU,2BAA2B,EAC9G,IAAI,OAAO;AACd,UAAM,SAAkC,CAAC;AACzC,eAAW,OAAO,MAAM;AACtB,YAAM,MAAM,IAAI,GAAG,MAAM,QAAQ,SAAS,CAAC;AAC3C,YAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,aAAO,GAAG,IAAI,OAAO,SAAS;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,YAAoB,SAAiB,KAAa,OAAsB;AAC3F,SAAK,sBAAsB,UAAU;AACrC,SAAK,MAAM,EACR,QAAQ,gBAAgB,UAAU,+EAA+E,EACjH,IAAI,GAAG,OAAO,IAAI,GAAG,IAAI,KAAK,UAAU,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC;AAAA,EACrE;AAAA;AAAA,EAIA,MAAM,YAAY,OAAe,QAAqC;AACpE,QAAI,CAAC,QAAQ;AAEX,UAAI,CAAC,KAAK,cAAc,IAAI,KAAK,GAAG;AAClC,aAAK,MAAM,EAAE,KAAK,+BAA+B,KAAK,6CAA6C;AACnG,aAAK,cAAc,IAAI,KAAK;AAAA,MAC9B;AACA;AAAA,IACF;AACA,QAAI,KAAK,iBAAiB,IAAI,KAAK,EAAG;AAEtC,UAAM,UAAU,OAAO,QAAQ,IAAI,SAAO;AACxC,YAAM,QAAQ,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE;AAC1C,UAAI,IAAI,WAAY,OAAM,KAAK,aAAa;AAC5C,UAAI,IAAI,QAAS,OAAM,KAAK,UAAU;AACtC,UAAI,IAAI,OAAQ,OAAM,KAAK,QAAQ;AACnC,UAAI,IAAI,iBAAiB,QAAW;AAClC,cAAM,KAAK,WAAW,OAAO,IAAI,iBAAiB,WAAW,IAAI,IAAI,YAAY,MAAM,IAAI,iBAAiB,OAAO,SAAS,OAAO,IAAI,YAAY,CAAC,EAAE;AAAA,MACxJ;AACA,aAAO,MAAM,KAAK,GAAG;AAAA,IACvB,CAAC;AAED,SAAK,MAAM,EAAE,KAAK,+BAA+B,KAAK,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG;AAEjF,QAAI,OAAO,SAAS;AAClB,iBAAW,OAAO,OAAO,SAAS;AAChC,cAAM,SAAS,IAAI,SAAS,YAAY;AACxC,cAAM,OAAO,IAAI,QAAQ,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACrD,aAAK,MAAM,EAAE,KAAK,UAAU,MAAM,wBAAwB,IAAI,IAAI,SAAS,KAAK,MAAM,IAAI,GAAG;AAAA,MAC/F;AAAA,IACF;AAEA,SAAK,iBAAiB,IAAI,KAAK;AAAA,EACjC;AAAA,EAEA,MAAM,YAAY,OAAe,KAA6C;AAC5E,UAAM,OAAO,OAAO,KAAK,GAAG;AAC5B,UAAM,OAAO,KAAK,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AAC9C,UAAM,eAAe,KAAK,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AAClD,UAAM,SAAS,KAAK,IAAI,OAAK;AAC3B,YAAM,IAAI,IAAI,CAAC;AACf,aAAO,OAAO,MAAM,YAAY,MAAM,OAAO,KAAK,UAAU,CAAC,IAAI;AAAA,IACnE,CAAC;AACD,SAAK,MAAM,EAAE,QAAQ,gBAAgB,KAAK,MAAM,IAAI,aAAa,YAAY,GAAG,EAAE,IAAI,GAAG,MAAM;AAAA,EACjG;AAAA,EAEA,MAAM,YAAY,OAAe,QAAiC,SAAmD;AACnH,UAAM,aAAuB,CAAC;AAC9B,UAAM,YAAuB,CAAC;AAC9B,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC5C,iBAAW,KAAK,IAAI,CAAC,OAAO;AAC5B,gBAAU,KAAK,OAAO,MAAM,YAAY,MAAM,OAAO,KAAK,UAAU,CAAC,IAAI,CAAC;AAAA,IAC5E;AAEA,UAAM,EAAE,UAAU,YAAY,IAAI,KAAK,WAAW,MAAM;AACxD,UAAM,SAAS,KAAK,MAAM,EACvB,QAAQ,WAAW,KAAK,SAAS,WAAW,KAAK,IAAI,CAAC,GAAG,QAAQ,EAAE,EACnE,IAAI,GAAG,WAAW,GAAG,WAAW;AACnC,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,YAAY,OAAe,QAAkD;AACjF,UAAM,EAAE,UAAU,YAAY,IAAI,KAAK,WAAW,MAAM;AACxD,UAAM,SAAS,KAAK,MAAM,EAAE,QAAQ,gBAAgB,KAAK,IAAI,QAAQ,EAAE,EAAE,IAAI,GAAG,WAAW;AAC3F,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,WAAW,OAAe,SAA0E;AACxG,QAAI,MAAM,kBAAkB,KAAK;AACjC,UAAM,SAAoB,CAAC;AAE3B,QAAI,SAAS,OAAO;AAClB,YAAM,EAAE,UAAU,YAAY,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC/D,aAAO;AACP,aAAO,KAAK,GAAG,WAAW;AAAA,IAC5B;AAEA,QAAI,SAAS,SAAS;AACpB,aAAO,cAAc,QAAQ,QAAQ,KAAK,KAAK,QAAQ,QAAQ,cAAc,SAAS,SAAS,KAAK;AAAA,IACtG;AAEA,QAAI,SAAS,UAAU,QAAW;AAChC,aAAO;AACP,aAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AAEA,QAAI,SAAS,WAAW,QAAW;AACjC,aAAO;AACP,aAAO,KAAK,QAAQ,MAAM;AAAA,IAC5B;AAEA,WAAO,KAAK,MAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAAA,EAChD;AAAA,EAEA,MAAM,SAAS,OAAe,QAA0E;AACtG,UAAM,EAAE,UAAU,YAAY,IAAI,KAAK,WAAW,MAAM;AACxD,UAAM,MAAM,KAAK,MAAM,EAAE,QAAQ,kBAAkB,KAAK,IAAI,QAAQ,UAAU,EAAE,IAAI,GAAG,WAAW;AAClG,WAAQ,OAAmC;AAAA,EAC7C;AAAA,EAEA,MAAM,WAAW,OAAe,QAAmD;AACjF,QAAI,MAAM,kCAAkC,KAAK;AACjD,UAAM,SAAoB,CAAC;AAE3B,QAAI,QAAQ;AACV,YAAM,EAAE,UAAU,YAAY,IAAI,KAAK,WAAW,MAAM;AACxD,aAAO;AACP,aAAO,KAAK,GAAG,WAAW;AAAA,IAC5B;AAEA,UAAM,MAAM,KAAK,MAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AACnD,WAAO,IAAI;AAAA,EACb;AAAA,EAEQ,WAAW,QAA+E;AAChG,UAAM,aAAuB,CAAC;AAC9B,UAAM,SAAoB,CAAC;AAC3B,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,iBAAW,KAAK,IAAI,CAAC,OAAO;AAC5B,aAAO,KAAK,OAAO,MAAM,YAAY,MAAM,OAAO,KAAK,UAAU,CAAC,IAAI,CAAC;AAAA,IACzE;AACA,UAAM,WAAW,WAAW,SAAS,IAAI,UAAU,WAAW,KAAK,OAAO,CAAC,KAAK;AAChF,WAAO,EAAE,UAAU,aAAa,OAAO;AAAA,EACzC;AACF;;;AC/aO,IAAM,sBAAN,MAAmE;AAAA,EAC/D,WAA0B;AAAA,IACjC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,cAAc,CAAC,EAAE,MAAM,kBAAkB,MAAM,YAAY,CAAC;AAAA,EAC9D;AAAA,EAEQ,UAAwC;AAAA,EAEhD,MAAM,WAAW,SAAsC;AAErD,UAAM,SAAS,QAAQ,kBACnB,QAAQ,gBAAgB,QAAQ,eAAe,GAAG,QAAQ,GAAG,QAAQ,UAAU,EAAE,CAAC,cAAc,IAChG,QAAQ,UACN,GAAG,QAAQ,OAAO,iBAClB;AAEN,UAAM,kBAAmB,QAAQ,YAAY,oBAAgD,CAAC;AAC9F,SAAK,UAAU,IAAI,sBAAsB,QAAQ,eAAe;AAChE,UAAM,KAAK,QAAQ,WAAW;AAC9B,YAAQ,OAAO,KAAK,kCAAkC,MAAM,EAAE;AAAA,EAChE;AAAA,EAEA,MAAM,WAA0B;AAC9B,UAAM,KAAK,SAAS,SAAS;AAAA,EAC/B;AAAA,EAEA,aAA2C;AACzC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,sBACE,MACiC;AACjC,QAAI,SAAU,oBAA+B,KAAK,SAAS;AACzD,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EAEA,kBAAkC;AAChC,WAAO,EAAE,UAAU,CAAC,EAAE;AAAA,EACxB;AAAA,EAEA,YAAqC;AACnC,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,MAAM,eAAe,SAAiD;AAAA,EAEtE;AACF;AAEA,IAAO,gCAAQ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builtins/local-backup/local-backup.ts","../src/builtins/local-backup/local-backup.addon.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, IStorageLocation, BackupManifest } from '@camstack/types'\n\nexport type { BackupManifest }\n\nexport interface BackupConfig {\n readonly backupDir: string\n readonly retentionCount: number\n}\n\nexport class LocalBackupService {\n private manifests: BackupManifest[] = []\n\n constructor(\n private readonly config: BackupConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Create a backup of specified locations */\n async backup(options?: {\n locations?: string[]\n label?: string\n }): Promise<BackupManifest> {\n const id = randomUUID()\n const timestamp = Date.now()\n const locations = options?.locations ?? ['config', 'events', 'logs']\n\n this.logger.info(`Starting backup ${id} (${locations.join(', ')})`)\n\n const manifest: BackupManifest = {\n id,\n timestamp,\n label: options?.label,\n locations,\n sizeMB: 0,\n path: `${this.config.backupDir}/${id}`,\n }\n\n const updated = [...this.manifests, manifest]\n this.manifests = updated\n\n await this.pruneOldBackups()\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: 'backup.completed',\n data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB },\n })\n\n this.logger.info(`Backup ${id} completed`)\n return manifest\n }\n\n /** Restore from a backup */\n async restore(backupId: string): Promise<void> {\n const manifest = this.manifests.find((m) => m.id === backupId)\n if (!manifest) throw new Error(`Backup ${backupId} not found`)\n\n this.logger.info(`Restoring from backup ${backupId}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: 'backup.restored',\n data: { backupId },\n })\n }\n\n /** List all backups sorted by timestamp descending */\n list(): readonly BackupManifest[] {\n return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp)\n }\n\n /** Delete a specific backup */\n async delete(backupId: string): Promise<void> {\n this.manifests = this.manifests.filter((m) => m.id !== backupId)\n }\n\n private async pruneOldBackups(): Promise<void> {\n const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp)\n\n while (sorted.length > this.config.retentionCount) {\n const oldest = sorted.shift()\n if (oldest) {\n this.logger.info(`Pruning old backup ${oldest.id}`)\n this.manifests = this.manifests.filter((m) => m.id !== oldest.id)\n }\n }\n }\n}\n","import * as path from 'node:path'\nimport type {\n ICamstackAddon, AddonManifest, AddonContext,\n IConfigurable, ConfigUISchema, CapabilityProviderMap,\n} from '@camstack/types'\nimport { LocalBackupService } from './local-backup'\nimport type { BackupConfig } from './local-backup'\n\nexport class LocalBackupAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'local-backup',\n name: 'Local Backup',\n version: '1.0.0',\n capabilities: ['backup'],\n }\n\n private service: LocalBackupService | null = null\n private currentConfig = {\n retentionCount: 7,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n retentionCount: (context.addonConfig.retentionCount as number) ?? this.currentConfig.retentionCount,\n }\n const backupConfig: BackupConfig = {\n backupDir: path.join(context.locationPaths.data, 'backups'),\n retentionCount: this.currentConfig.retentionCount,\n }\n this.service = new LocalBackupService(\n backupConfig,\n context.logger,\n context.eventBus,\n context.storage,\n )\n context.logger.info('Local Backup initialized')\n }\n\n async shutdown(): Promise<void> {\n this.service = null\n }\n\n getService(): LocalBackupService {\n if (!this.service) throw new Error('Local Backup not initialized')\n return this.service\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'backup' as string && this.service) {\n return this.service as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'backup-retention',\n title: 'Backup Retention',\n description: 'How many local backup snapshots to keep on disk.',\n columns: 1,\n fields: [\n {\n type: 'number',\n key: 'retentionCount',\n label: 'Retention Count',\n description: 'Number of backup snapshots to keep before deleting the oldest',\n min: 1,\n max: 100,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n retentionCount: (config.retentionCount as number) ?? this.currentConfig.retentionCount,\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-SPA4JBKN.mjs
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
// src/builtins/sqlite-storage/filesystem-storage-provider.ts
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
var STORAGE_LOCATION_TYPES = [
|
|
5
|
-
"recordings-high",
|
|
6
|
-
"recordings-low",
|
|
7
|
-
"recordings-clips",
|
|
8
|
-
"event-images",
|
|
9
|
-
"models",
|
|
10
|
-
"addons-data",
|
|
11
|
-
"cache",
|
|
12
|
-
"logs"
|
|
13
|
-
];
|
|
14
|
-
var DEFAULT_LOCATION_SUBDIRS = {
|
|
15
|
-
"recordings-high": "recordings-high",
|
|
16
|
-
"recordings-low": "recordings-low",
|
|
17
|
-
"recordings-clips": "recordings-clips",
|
|
18
|
-
"event-images": "event-images",
|
|
19
|
-
"models": "models",
|
|
20
|
-
"addons-data": "addons-data",
|
|
21
|
-
"cache": "/tmp/camstack-cache",
|
|
22
|
-
"logs": "logs"
|
|
23
|
-
};
|
|
24
|
-
var FilesystemStorageProvider = class {
|
|
25
|
-
id = "local";
|
|
26
|
-
name = "Local Filesystem";
|
|
27
|
-
supportedLocations = [...STORAGE_LOCATION_TYPES];
|
|
28
|
-
rootPath;
|
|
29
|
-
locationPaths;
|
|
30
|
-
constructor(rootPath, overrides) {
|
|
31
|
-
this.rootPath = path.resolve(rootPath);
|
|
32
|
-
this.locationPaths = /* @__PURE__ */ new Map();
|
|
33
|
-
for (const loc of STORAGE_LOCATION_TYPES) {
|
|
34
|
-
const override = overrides?.[loc];
|
|
35
|
-
if (override) {
|
|
36
|
-
this.locationPaths.set(loc, path.resolve(override));
|
|
37
|
-
} else {
|
|
38
|
-
const subdir = DEFAULT_LOCATION_SUBDIRS[loc];
|
|
39
|
-
this.locationPaths.set(
|
|
40
|
-
loc,
|
|
41
|
-
path.isAbsolute(subdir) ? subdir : path.join(this.rootPath, subdir)
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
resolve(location, relativePath) {
|
|
47
|
-
const base = this.locationPaths.get(location);
|
|
48
|
-
if (!base) throw new Error(`Unknown storage location: ${location}`);
|
|
49
|
-
return path.join(base, relativePath);
|
|
50
|
-
}
|
|
51
|
-
async write(location, relativePath, data) {
|
|
52
|
-
const filePath = this.resolve(location, relativePath);
|
|
53
|
-
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
54
|
-
if (Buffer.isBuffer(data)) {
|
|
55
|
-
await fs.promises.writeFile(filePath, data);
|
|
56
|
-
} else {
|
|
57
|
-
const writeStream = fs.createWriteStream(filePath);
|
|
58
|
-
await new Promise((resolve2, reject) => {
|
|
59
|
-
data.pipe(writeStream);
|
|
60
|
-
writeStream.on("finish", resolve2);
|
|
61
|
-
writeStream.on("error", reject);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
async read(location, relativePath) {
|
|
66
|
-
return fs.promises.readFile(this.resolve(location, relativePath));
|
|
67
|
-
}
|
|
68
|
-
async exists(location, relativePath) {
|
|
69
|
-
try {
|
|
70
|
-
await fs.promises.access(this.resolve(location, relativePath));
|
|
71
|
-
return true;
|
|
72
|
-
} catch {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async list(location, prefix) {
|
|
77
|
-
const base = this.locationPaths.get(location);
|
|
78
|
-
if (!base) return [];
|
|
79
|
-
const dir = prefix ? path.join(base, prefix) : base;
|
|
80
|
-
try {
|
|
81
|
-
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
82
|
-
return entries.map((e) => prefix ? `${prefix}/${e.name}` : e.name);
|
|
83
|
-
} catch {
|
|
84
|
-
return [];
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
async delete(location, relativePath) {
|
|
88
|
-
const filePath = this.resolve(location, relativePath);
|
|
89
|
-
await fs.promises.rm(filePath, { force: true });
|
|
90
|
-
}
|
|
91
|
-
async getAvailableSpace(location) {
|
|
92
|
-
const base = this.locationPaths.get(location);
|
|
93
|
-
if (!base) return null;
|
|
94
|
-
try {
|
|
95
|
-
const stats = await fs.promises.statfs(base);
|
|
96
|
-
return stats.bavail * stats.bsize;
|
|
97
|
-
} catch {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
async initialize() {
|
|
102
|
-
for (const [, dirPath] of this.locationPaths) {
|
|
103
|
-
await fs.promises.mkdir(dirPath, { recursive: true });
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
async shutdown() {
|
|
107
|
-
}
|
|
108
|
-
/** Get the resolved path for a location type */
|
|
109
|
-
getLocationPath(location) {
|
|
110
|
-
const p = this.locationPaths.get(location);
|
|
111
|
-
if (!p) throw new Error(`Unknown storage location: ${location}`);
|
|
112
|
-
return p;
|
|
113
|
-
}
|
|
114
|
-
/** Get the root path */
|
|
115
|
-
getRootPath() {
|
|
116
|
-
return this.rootPath;
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// src/builtins/sqlite-storage/filesystem-storage.addon.ts
|
|
121
|
-
var FilesystemStorageAddon = class {
|
|
122
|
-
manifest = {
|
|
123
|
-
id: "filesystem-storage",
|
|
124
|
-
name: "Local Filesystem Storage",
|
|
125
|
-
version: "1.0.0",
|
|
126
|
-
capabilities: [{ name: "storage", mode: "collection" }]
|
|
127
|
-
};
|
|
128
|
-
provider = null;
|
|
129
|
-
currentConfig = {
|
|
130
|
-
rootPath: "camstack-data"
|
|
131
|
-
};
|
|
132
|
-
async initialize(context) {
|
|
133
|
-
const rootPath = context.addonConfig.rootPath ?? this.currentConfig.rootPath;
|
|
134
|
-
this.currentConfig.rootPath = rootPath;
|
|
135
|
-
const overrides = {};
|
|
136
|
-
for (const key of Object.keys(context.addonConfig)) {
|
|
137
|
-
if (key.startsWith("override.")) {
|
|
138
|
-
const loc = key.slice("override.".length);
|
|
139
|
-
overrides[loc] = context.addonConfig[key];
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
this.provider = new FilesystemStorageProvider(rootPath, overrides);
|
|
143
|
-
await this.provider.initialize();
|
|
144
|
-
context.logger.info(`Filesystem storage initialized at ${this.provider.getRootPath()}`);
|
|
145
|
-
}
|
|
146
|
-
async shutdown() {
|
|
147
|
-
await this.provider?.shutdown();
|
|
148
|
-
}
|
|
149
|
-
getCapabilityProvider(name) {
|
|
150
|
-
if (name === "storage" && this.provider) {
|
|
151
|
-
return this.provider;
|
|
152
|
-
}
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
getProvider() {
|
|
156
|
-
return this.provider;
|
|
157
|
-
}
|
|
158
|
-
getConfigSchema() {
|
|
159
|
-
return { sections: [] };
|
|
160
|
-
}
|
|
161
|
-
getConfig() {
|
|
162
|
-
return { ...this.currentConfig };
|
|
163
|
-
}
|
|
164
|
-
async onConfigChange(config) {
|
|
165
|
-
this.currentConfig.rootPath = config.rootPath ?? this.currentConfig.rootPath;
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
var filesystem_storage_addon_default = FilesystemStorageAddon;
|
|
169
|
-
|
|
170
|
-
export {
|
|
171
|
-
FilesystemStorageProvider,
|
|
172
|
-
FilesystemStorageAddon,
|
|
173
|
-
filesystem_storage_addon_default
|
|
174
|
-
};
|
|
175
|
-
//# sourceMappingURL=chunk-SPA4JBKN.mjs.map
|