@camstack/addon-advanced-notifier 0.1.3 → 0.1.4

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.
@@ -0,0 +1,365 @@
1
+ // src/rules/rule-store.ts
2
+ var COLLECTION = "addon-settings";
3
+ var KEY = "advanced-notifier:rules";
4
+ var RuleStore = class {
5
+ backend;
6
+ constructor(backend) {
7
+ this.backend = backend;
8
+ }
9
+ async getRules() {
10
+ const raw = await this.backend.get(COLLECTION, KEY);
11
+ if (!raw || !Array.isArray(raw)) return [];
12
+ return raw;
13
+ }
14
+ async saveRules(rules) {
15
+ await this.backend.set(COLLECTION, KEY, [...rules]);
16
+ }
17
+ async upsertRule(rule) {
18
+ const rules = await this.getRules();
19
+ const idx = rules.findIndex((r) => r.id === rule.id);
20
+ if (idx >= 0) {
21
+ rules[idx] = rule;
22
+ } else {
23
+ rules.push(rule);
24
+ }
25
+ await this.saveRules(rules);
26
+ }
27
+ async deleteRule(ruleId) {
28
+ const rules = await this.getRules();
29
+ await this.saveRules(rules.filter((r) => r.id !== ruleId));
30
+ }
31
+ };
32
+
33
+ // src/rules/rule-engine.ts
34
+ var RuleEngine = class {
35
+ evaluate(event, rules) {
36
+ return rules.filter((rule) => this.matchesRule(event, rule));
37
+ }
38
+ matchesRule(event, rule) {
39
+ if (!rule.enabled) return false;
40
+ if (!rule.eventTypes.includes(event.category)) return false;
41
+ return this.evaluateConditions(event, rule);
42
+ }
43
+ evaluateConditions(event, rule) {
44
+ const { conditions } = rule;
45
+ const data = event.data;
46
+ if (conditions.deviceIds?.length) {
47
+ const deviceId = data["deviceId"] ?? event.source.id;
48
+ if (!conditions.deviceIds.includes(deviceId)) return false;
49
+ }
50
+ if (conditions.classNames?.length) {
51
+ const className = data["className"];
52
+ if (!className || !conditions.classNames.includes(className)) return false;
53
+ }
54
+ if (conditions.zoneIds?.length) {
55
+ const zoneId = data["zoneId"];
56
+ if (!zoneId || !conditions.zoneIds.includes(zoneId)) return false;
57
+ }
58
+ if (conditions.minConfidence !== void 0) {
59
+ const confidence = data["confidence"];
60
+ if (confidence === void 0 || confidence < conditions.minConfidence) return false;
61
+ }
62
+ if (conditions.schedule) {
63
+ const now = /* @__PURE__ */ new Date();
64
+ const { days, startHour, endHour } = conditions.schedule;
65
+ if (!days.includes(now.getDay())) return false;
66
+ const hour = now.getHours();
67
+ if (hour < startHour || hour >= endHour) return false;
68
+ }
69
+ return true;
70
+ }
71
+ };
72
+
73
+ // src/rules/cooldown.ts
74
+ var CooldownTracker = class {
75
+ lastFired = /* @__PURE__ */ new Map();
76
+ canFire(ruleId, cooldownSeconds) {
77
+ const last = this.lastFired.get(ruleId);
78
+ if (last === void 0) return true;
79
+ return (Date.now() - last) / 1e3 >= cooldownSeconds;
80
+ }
81
+ recordFire(ruleId) {
82
+ this.lastFired.set(ruleId, Date.now());
83
+ }
84
+ reset() {
85
+ this.lastFired.clear();
86
+ }
87
+ };
88
+
89
+ // src/template/renderer.ts
90
+ function renderTemplate(template, variables) {
91
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
92
+ const value = variables[key];
93
+ return value !== void 0 ? value : match;
94
+ });
95
+ }
96
+
97
+ // src/outputs/console.ts
98
+ var ConsoleOutput = class {
99
+ id = "console";
100
+ name = "Console Log";
101
+ icon = "terminal";
102
+ logger;
103
+ constructor(logger) {
104
+ this.logger = logger;
105
+ }
106
+ async send(notification) {
107
+ this.logger.info(
108
+ `[${notification.severity}] ${notification.title}: ${notification.message}` + (notification.deviceId ? ` (device=${notification.deviceId})` : "")
109
+ );
110
+ }
111
+ async sendTest() {
112
+ await this.send({
113
+ title: "Test",
114
+ message: "Console output working",
115
+ severity: "info",
116
+ category: "test",
117
+ timestamp: Date.now()
118
+ });
119
+ return { success: true };
120
+ }
121
+ };
122
+
123
+ // src/history/audit-log.ts
124
+ var COLLECTION2 = "addon-settings";
125
+ var LOG_KEY = "notifier-history:log";
126
+ var AuditLog = class {
127
+ backend;
128
+ maxEntries;
129
+ constructor(backend, maxEntries = 1e3) {
130
+ this.backend = backend;
131
+ this.maxEntries = maxEntries;
132
+ }
133
+ async record(entry) {
134
+ const entries = await this.getAll();
135
+ const updated = [...entries, entry];
136
+ const trimmed = updated.length > this.maxEntries ? updated.slice(updated.length - this.maxEntries) : updated;
137
+ await this.backend.set(COLLECTION2, LOG_KEY, trimmed);
138
+ }
139
+ async getHistory(filter) {
140
+ let entries = await this.getAll();
141
+ if (filter?.ruleId) {
142
+ entries = entries.filter((e) => e.ruleId === filter.ruleId);
143
+ }
144
+ if (filter?.deviceId) {
145
+ const deviceId = filter.deviceId;
146
+ entries = entries.filter((e) => e["deviceId"] === deviceId);
147
+ }
148
+ if (filter?.from !== void 0) {
149
+ const from = filter.from;
150
+ entries = entries.filter((e) => e.timestamp >= from);
151
+ }
152
+ if (filter?.to !== void 0) {
153
+ const to = filter.to;
154
+ entries = entries.filter((e) => e.timestamp <= to);
155
+ }
156
+ if (filter?.limit) {
157
+ entries = entries.slice(-filter.limit);
158
+ }
159
+ return entries;
160
+ }
161
+ async getAll() {
162
+ const raw = await this.backend.get(COLLECTION2, LOG_KEY);
163
+ if (!raw || !Array.isArray(raw)) return [];
164
+ return raw;
165
+ }
166
+ };
167
+
168
+ // src/addon.ts
169
+ import { randomUUID } from "crypto";
170
+ var EVENT_CATEGORIES = ["detection.raw", "detection.result", "detection.camera-native"];
171
+ var AdvancedNotifierAddon = class {
172
+ manifest = {
173
+ id: "advanced-notifier",
174
+ name: "Advanced Notifier",
175
+ version: "0.1.0",
176
+ capabilities: [
177
+ { name: "advanced-notifier", mode: "singleton" },
178
+ { name: "notification-output", mode: "collection" }
179
+ ]
180
+ };
181
+ context;
182
+ // Rule management
183
+ ruleStore;
184
+ ruleEngine;
185
+ cooldown;
186
+ cachedRules = [];
187
+ // Outputs
188
+ consoleOutput;
189
+ outputs = [];
190
+ // Audit log
191
+ auditLog;
192
+ // Event bus unsubscribe handles
193
+ unsubscribers = [];
194
+ // IAdvancedNotifier implementation (exposed as capability)
195
+ notifier = {
196
+ getRules: () => this.cachedRules,
197
+ upsertRule: (rule) => {
198
+ this.ruleStore.upsertRule(rule).then(() => {
199
+ const idx = this.cachedRules.findIndex((r) => r.id === rule.id);
200
+ if (idx >= 0) {
201
+ this.cachedRules = [
202
+ ...this.cachedRules.slice(0, idx),
203
+ rule,
204
+ ...this.cachedRules.slice(idx + 1)
205
+ ];
206
+ } else {
207
+ this.cachedRules = [...this.cachedRules, rule];
208
+ }
209
+ }).catch((err) => {
210
+ this.context.logger.error("Failed to upsert rule", { error: String(err) });
211
+ });
212
+ },
213
+ deleteRule: (ruleId) => {
214
+ this.ruleStore.deleteRule(ruleId).then(() => {
215
+ this.cachedRules = this.cachedRules.filter((r) => r.id !== ruleId);
216
+ }).catch((err) => {
217
+ this.context.logger.error("Failed to delete rule", { error: String(err) });
218
+ });
219
+ },
220
+ testRule: async (ruleId, lookbackMinutes) => {
221
+ const rule = this.cachedRules.find((r) => r.id === ruleId);
222
+ if (!rule) return [];
223
+ const since = new Date(Date.now() - lookbackMinutes * 60 * 1e3);
224
+ const recentEvents = this.context.eventBus.getRecent(
225
+ { category: void 0 },
226
+ 1e3
227
+ ).filter((e) => e.timestamp >= since);
228
+ return recentEvents.map((event) => {
229
+ const matched = this.ruleEngine.evaluate(event, [rule]);
230
+ return {
231
+ ruleId,
232
+ eventId: event.id,
233
+ timestamp: event.timestamp.getTime(),
234
+ wouldFire: matched.length > 0,
235
+ reason: matched.length === 0 ? "Conditions not met" : void 0
236
+ };
237
+ });
238
+ },
239
+ getHistory: async (filter) => {
240
+ if (!this.auditLog) return [];
241
+ return this.auditLog.getHistory(filter);
242
+ }
243
+ };
244
+ async initialize(context) {
245
+ this.context = context;
246
+ this.ruleEngine = new RuleEngine();
247
+ this.cooldown = new CooldownTracker();
248
+ this.consoleOutput = new ConsoleOutput(context.logger.child("console-output"));
249
+ this.outputs = [this.consoleOutput];
250
+ if (context.settingsBackend) {
251
+ this.ruleStore = new RuleStore(context.settingsBackend);
252
+ this.auditLog = new AuditLog(context.settingsBackend);
253
+ this.cachedRules = await this.ruleStore.getRules();
254
+ this.context.logger.info(`Loaded ${this.cachedRules.length} notification rules`);
255
+ } else {
256
+ this.context.logger.warn("No settingsBackend \u2014 rules will not be persisted");
257
+ }
258
+ for (const category of EVENT_CATEGORIES) {
259
+ const unsubscribe = context.eventBus.subscribe(
260
+ { category },
261
+ (event) => {
262
+ void this.handleEvent(event);
263
+ }
264
+ );
265
+ this.unsubscribers.push(unsubscribe);
266
+ }
267
+ this.context.logger.info("AdvancedNotifierAddon initialized");
268
+ }
269
+ async shutdown() {
270
+ for (const unsub of this.unsubscribers) {
271
+ unsub();
272
+ }
273
+ this.unsubscribers = [];
274
+ this.context.logger.info("AdvancedNotifierAddon shut down");
275
+ }
276
+ getCapabilityProvider(name) {
277
+ if (name === "advanced-notifier") {
278
+ return this.notifier;
279
+ }
280
+ if (name === "notification-output") {
281
+ return this.consoleOutput;
282
+ }
283
+ return null;
284
+ }
285
+ async handleEvent(event) {
286
+ const matchedRules = this.ruleEngine.evaluate(event, this.cachedRules);
287
+ for (const rule of matchedRules) {
288
+ const cooldownSeconds = rule.conditions.cooldownSeconds ?? 0;
289
+ if (!this.cooldown.canFire(rule.id, cooldownSeconds)) {
290
+ this.context.logger.debug(`Rule ${rule.id} skipped \u2014 in cooldown`);
291
+ continue;
292
+ }
293
+ this.cooldown.recordFire(rule.id);
294
+ const variables = this.buildTemplateVariables(event);
295
+ const title = rule.template ? renderTemplate(rule.template.title, variables) : `CamStack Alert: ${rule.name}`;
296
+ const message = rule.template ? renderTemplate(rule.template.body, variables) : `Event ${event.category} from ${event.source.id}`;
297
+ const notification = {
298
+ title,
299
+ message,
300
+ severity: this.priorityToSeverity(rule.priority),
301
+ category: event.category,
302
+ deviceId: event.data["deviceId"] ?? event.source.id,
303
+ data: event.data,
304
+ timestamp: event.timestamp.getTime()
305
+ };
306
+ let success = true;
307
+ let dispatchError;
308
+ for (const output of this.outputs) {
309
+ try {
310
+ await output.send(notification);
311
+ } catch (err) {
312
+ success = false;
313
+ dispatchError = String(err);
314
+ this.context.logger.error(`Output ${output.id} failed`, { error: dispatchError });
315
+ }
316
+ }
317
+ if (this.auditLog) {
318
+ const entry = {
319
+ id: randomUUID(),
320
+ ruleId: rule.id,
321
+ ruleName: rule.name,
322
+ eventId: event.id,
323
+ timestamp: event.timestamp.getTime(),
324
+ outputs: this.outputs.map((o) => o.id),
325
+ success,
326
+ error: dispatchError
327
+ };
328
+ await this.auditLog.record(entry).catch((err) => {
329
+ this.context.logger.error("Failed to record audit log entry", { error: String(err) });
330
+ });
331
+ }
332
+ }
333
+ }
334
+ buildTemplateVariables(event) {
335
+ const data = event.data;
336
+ return {
337
+ deviceId: data["deviceId"] ?? event.source.id,
338
+ deviceName: data["deviceName"] ?? event.source.id,
339
+ className: data["className"] ?? "",
340
+ confidence: String(data["confidence"] ?? ""),
341
+ zoneId: data["zoneId"] ?? "",
342
+ zoneName: data["zoneName"] ?? "",
343
+ category: event.category,
344
+ timestamp: event.timestamp.toISOString()
345
+ };
346
+ }
347
+ priorityToSeverity(priority) {
348
+ if (priority === "critical") return "critical";
349
+ if (priority === "high") return "warning";
350
+ return "info";
351
+ }
352
+ };
353
+ var addon_default = AdvancedNotifierAddon;
354
+
355
+ export {
356
+ RuleStore,
357
+ RuleEngine,
358
+ CooldownTracker,
359
+ renderTemplate,
360
+ ConsoleOutput,
361
+ AuditLog,
362
+ AdvancedNotifierAddon,
363
+ addon_default
364
+ };
365
+ //# sourceMappingURL=chunk-HYUFV4O5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/rules/rule-store.ts","../src/rules/rule-engine.ts","../src/rules/cooldown.ts","../src/template/renderer.ts","../src/outputs/console.ts","../src/history/audit-log.ts","../src/addon.ts"],"sourcesContent":["import type { ISettingsBackend, NotificationRule } from '@camstack/types'\n\nconst COLLECTION = 'addon-settings' as const\nconst KEY = 'advanced-notifier:rules'\n\nexport class RuleStore {\n private readonly backend: ISettingsBackend\n\n constructor(backend: ISettingsBackend) {\n this.backend = backend\n }\n\n async getRules(): Promise<NotificationRule[]> {\n const raw = await this.backend.get(COLLECTION, KEY)\n if (!raw || !Array.isArray(raw)) return []\n return raw as NotificationRule[]\n }\n\n async saveRules(rules: readonly NotificationRule[]): Promise<void> {\n await this.backend.set(COLLECTION, KEY, [...rules])\n }\n\n async upsertRule(rule: NotificationRule): Promise<void> {\n const rules = await this.getRules()\n const idx = rules.findIndex(r => r.id === rule.id)\n if (idx >= 0) {\n rules[idx] = rule\n } else {\n rules.push(rule)\n }\n await this.saveRules(rules)\n }\n\n async deleteRule(ruleId: string): Promise<void> {\n const rules = await this.getRules()\n await this.saveRules(rules.filter(r => r.id !== ruleId))\n }\n}\n","import type { NotificationRule } from '@camstack/types'\n\ninterface EventData {\n readonly id: string\n readonly timestamp: Date\n readonly source: { readonly type: string; readonly id: string }\n readonly category: string\n readonly data: Record<string, unknown>\n}\n\nexport class RuleEngine {\n evaluate(event: EventData, rules: readonly NotificationRule[]): NotificationRule[] {\n return rules.filter(rule => this.matchesRule(event, rule))\n }\n\n private matchesRule(event: EventData, rule: NotificationRule): boolean {\n if (!rule.enabled) return false\n if (!rule.eventTypes.includes(event.category)) return false\n return this.evaluateConditions(event, rule)\n }\n\n private evaluateConditions(event: EventData, rule: NotificationRule): boolean {\n const { conditions } = rule\n const data = event.data\n\n if (conditions.deviceIds?.length) {\n const deviceId = (data['deviceId'] as string) ?? event.source.id\n if (!conditions.deviceIds.includes(deviceId)) return false\n }\n\n if (conditions.classNames?.length) {\n const className = data['className'] as string | undefined\n if (!className || !conditions.classNames.includes(className)) return false\n }\n\n if (conditions.zoneIds?.length) {\n const zoneId = data['zoneId'] as string | undefined\n if (!zoneId || !conditions.zoneIds.includes(zoneId)) return false\n }\n\n if (conditions.minConfidence !== undefined) {\n const confidence = data['confidence'] as number | undefined\n if (confidence === undefined || confidence < conditions.minConfidence) return false\n }\n\n if (conditions.schedule) {\n const now = new Date()\n const { days, startHour, endHour } = conditions.schedule\n if (!days.includes(now.getDay())) return false\n const hour = now.getHours()\n if (hour < startHour || hour >= endHour) return false\n }\n\n return true\n }\n}\n","export class CooldownTracker {\n private readonly lastFired = new Map<string, number>()\n\n canFire(ruleId: string, cooldownSeconds: number): boolean {\n const last = this.lastFired.get(ruleId)\n if (last === undefined) return true\n return (Date.now() - last) / 1000 >= cooldownSeconds\n }\n\n recordFire(ruleId: string): void {\n this.lastFired.set(ruleId, Date.now())\n }\n\n reset(): void {\n this.lastFired.clear()\n }\n}\n","export function renderTemplate(template: string, variables: Record<string, string>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key: string) => {\n const value: string | undefined = variables[key]\n return value !== undefined ? value : match\n })\n}\n","import type { INotificationOutput, Notification, IScopedLogger } from '@camstack/types'\n\nexport class ConsoleOutput implements INotificationOutput {\n readonly id = 'console'\n readonly name = 'Console Log'\n readonly icon = 'terminal'\n\n private readonly logger: IScopedLogger\n\n constructor(logger: IScopedLogger) {\n this.logger = logger\n }\n\n async send(notification: Notification): Promise<void> {\n this.logger.info(\n `[${notification.severity}] ${notification.title}: ${notification.message}` +\n (notification.deviceId ? ` (device=${notification.deviceId})` : ''),\n )\n }\n\n async sendTest(): Promise<{ success: boolean; error?: string }> {\n await this.send({\n title: 'Test',\n message: 'Console output working',\n severity: 'info',\n category: 'test',\n timestamp: Date.now(),\n })\n return { success: true }\n }\n}\n","import type {\n ISettingsBackend,\n NotificationHistoryEntry,\n NotificationHistoryFilter,\n} from '@camstack/types'\n\nconst COLLECTION = 'addon-settings' as const\nconst LOG_KEY = 'notifier-history:log'\n\nexport class AuditLog {\n private readonly backend: ISettingsBackend\n private readonly maxEntries: number\n\n constructor(backend: ISettingsBackend, maxEntries = 1000) {\n this.backend = backend\n this.maxEntries = maxEntries\n }\n\n async record(entry: NotificationHistoryEntry): Promise<void> {\n const entries = await this.getAll()\n const updated = [...entries, entry]\n const trimmed =\n updated.length > this.maxEntries ? updated.slice(updated.length - this.maxEntries) : updated\n await this.backend.set(COLLECTION, LOG_KEY, trimmed)\n }\n\n async getHistory(filter?: NotificationHistoryFilter): Promise<NotificationHistoryEntry[]> {\n let entries = await this.getAll()\n if (filter?.ruleId) {\n entries = entries.filter(e => e.ruleId === filter.ruleId)\n }\n if (filter?.deviceId) {\n const deviceId = filter.deviceId\n entries = entries.filter(e => (e as unknown as Record<string, unknown>)['deviceId'] === deviceId)\n }\n if (filter?.from !== undefined) {\n const from = filter.from\n entries = entries.filter(e => e.timestamp >= from)\n }\n if (filter?.to !== undefined) {\n const to = filter.to\n entries = entries.filter(e => e.timestamp <= to)\n }\n if (filter?.limit) {\n entries = entries.slice(-filter.limit)\n }\n return entries\n }\n\n private async getAll(): Promise<NotificationHistoryEntry[]> {\n const raw = await this.backend.get(COLLECTION, LOG_KEY)\n if (!raw || !Array.isArray(raw)) return []\n return raw as NotificationHistoryEntry[]\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n IAdvancedNotifier,\n INotificationOutput,\n NotificationRule,\n NotificationTestResult,\n NotificationHistoryEntry,\n NotificationHistoryFilter,\n SystemEvent,\n CapabilityProviderMap,\n} from '@camstack/types'\nimport { RuleStore } from './rules/rule-store.js'\nimport { RuleEngine } from './rules/rule-engine.js'\nimport { CooldownTracker } from './rules/cooldown.js'\nimport { renderTemplate } from './template/renderer.js'\nimport { ConsoleOutput } from './outputs/console.js'\nimport { AuditLog } from './history/audit-log.js'\nimport { randomUUID } from 'node:crypto'\n\nconst EVENT_CATEGORIES = ['detection.raw', 'detection.result', 'detection.camera-native'] as const\n\nexport class AdvancedNotifierAddon implements ICamstackAddon {\n readonly manifest: AddonManifest = {\n id: 'advanced-notifier',\n name: 'Advanced Notifier',\n version: '0.1.0',\n capabilities: [\n { name: 'advanced-notifier', mode: 'singleton' as const },\n { name: 'notification-output', mode: 'collection' as const },\n ],\n }\n\n private context!: AddonContext\n\n // Rule management\n private ruleStore!: RuleStore\n private ruleEngine!: RuleEngine\n private cooldown!: CooldownTracker\n private cachedRules: NotificationRule[] = []\n\n // Outputs\n private consoleOutput!: ConsoleOutput\n private outputs: INotificationOutput[] = []\n\n // Audit log\n private auditLog!: AuditLog\n\n // Event bus unsubscribe handles\n private unsubscribers: Array<() => void> = []\n\n // IAdvancedNotifier implementation (exposed as capability)\n private readonly notifier: IAdvancedNotifier = {\n getRules: () => this.cachedRules as readonly NotificationRule[],\n\n upsertRule: (rule: NotificationRule): void => {\n // Fire-and-forget with error logging\n this.ruleStore.upsertRule(rule).then(() => {\n const idx = this.cachedRules.findIndex(r => r.id === rule.id)\n if (idx >= 0) {\n this.cachedRules = [\n ...this.cachedRules.slice(0, idx),\n rule,\n ...this.cachedRules.slice(idx + 1),\n ]\n } else {\n this.cachedRules = [...this.cachedRules, rule]\n }\n }).catch(err => {\n this.context.logger.error('Failed to upsert rule', { error: String(err) })\n })\n },\n\n deleteRule: (ruleId: string): void => {\n this.ruleStore.deleteRule(ruleId).then(() => {\n this.cachedRules = this.cachedRules.filter(r => r.id !== ruleId)\n }).catch(err => {\n this.context.logger.error('Failed to delete rule', { error: String(err) })\n })\n },\n\n testRule: async (ruleId: string, lookbackMinutes: number): Promise<NotificationTestResult[]> => {\n const rule = this.cachedRules.find(r => r.id === ruleId)\n if (!rule) return []\n const since = new Date(Date.now() - lookbackMinutes * 60 * 1000)\n const recentEvents = this.context.eventBus.getRecent(\n { category: undefined },\n 1000,\n ).filter(e => e.timestamp >= since)\n\n return recentEvents.map(event => {\n const matched = this.ruleEngine.evaluate(event, [rule])\n return {\n ruleId,\n eventId: event.id,\n timestamp: event.timestamp.getTime(),\n wouldFire: matched.length > 0,\n reason: matched.length === 0 ? 'Conditions not met' : undefined,\n }\n })\n },\n\n getHistory: async (filter?: NotificationHistoryFilter): Promise<NotificationHistoryEntry[]> => {\n if (!this.auditLog) return []\n return this.auditLog.getHistory(filter)\n },\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.context = context\n this.ruleEngine = new RuleEngine()\n this.cooldown = new CooldownTracker()\n this.consoleOutput = new ConsoleOutput(context.logger.child('console-output'))\n this.outputs = [this.consoleOutput]\n\n // Load rules from persistence if settings backend is available\n if (context.settingsBackend) {\n this.ruleStore = new RuleStore(context.settingsBackend)\n this.auditLog = new AuditLog(context.settingsBackend)\n this.cachedRules = await this.ruleStore.getRules()\n this.context.logger.info(`Loaded ${this.cachedRules.length} notification rules`)\n } else {\n this.context.logger.warn('No settingsBackend — rules will not be persisted')\n }\n\n // Subscribe to detection event categories\n for (const category of EVENT_CATEGORIES) {\n const unsubscribe = context.eventBus.subscribe(\n { category },\n (event: SystemEvent) => { void this.handleEvent(event) },\n )\n this.unsubscribers.push(unsubscribe)\n }\n\n this.context.logger.info('AdvancedNotifierAddon initialized')\n }\n\n async shutdown(): Promise<void> {\n for (const unsub of this.unsubscribers) {\n unsub()\n }\n this.unsubscribers = []\n this.context.logger.info('AdvancedNotifierAddon shut down')\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'advanced-notifier') {\n return this.notifier as CapabilityProviderMap[K]\n }\n if (name === 'notification-output') {\n return this.consoleOutput as CapabilityProviderMap[K]\n }\n return null\n }\n\n private async handleEvent(event: SystemEvent): Promise<void> {\n const matchedRules = this.ruleEngine.evaluate(event, this.cachedRules)\n\n for (const rule of matchedRules) {\n const cooldownSeconds = rule.conditions.cooldownSeconds ?? 0\n if (!this.cooldown.canFire(rule.id, cooldownSeconds)) {\n this.context.logger.debug(`Rule ${rule.id} skipped — in cooldown`)\n continue\n }\n this.cooldown.recordFire(rule.id)\n\n const variables = this.buildTemplateVariables(event)\n const title = rule.template\n ? renderTemplate(rule.template.title, variables)\n : `CamStack Alert: ${rule.name}`\n const message = rule.template\n ? renderTemplate(rule.template.body, variables)\n : `Event ${event.category} from ${event.source.id}`\n\n const notification = {\n title,\n message,\n severity: this.priorityToSeverity(rule.priority),\n category: event.category,\n deviceId: (event.data['deviceId'] as string | undefined) ?? event.source.id,\n data: event.data,\n timestamp: event.timestamp.getTime(),\n } as const\n\n let success = true\n let dispatchError: string | undefined\n\n for (const output of this.outputs) {\n try {\n await output.send(notification)\n } catch (err) {\n success = false\n dispatchError = String(err)\n this.context.logger.error(`Output ${output.id} failed`, { error: dispatchError })\n }\n }\n\n if (this.auditLog) {\n const entry: NotificationHistoryEntry = {\n id: randomUUID(),\n ruleId: rule.id,\n ruleName: rule.name,\n eventId: event.id,\n timestamp: event.timestamp.getTime(),\n outputs: this.outputs.map(o => o.id),\n success,\n error: dispatchError,\n }\n await this.auditLog.record(entry).catch(err => {\n this.context.logger.error('Failed to record audit log entry', { error: String(err) })\n })\n }\n }\n }\n\n private buildTemplateVariables(event: SystemEvent): Record<string, string> {\n const data = event.data\n return {\n deviceId: (data['deviceId'] as string | undefined) ?? event.source.id,\n deviceName: (data['deviceName'] as string | undefined) ?? event.source.id,\n className: (data['className'] as string | undefined) ?? '',\n confidence: String(data['confidence'] ?? ''),\n zoneId: (data['zoneId'] as string | undefined) ?? '',\n zoneName: (data['zoneName'] as string | undefined) ?? '',\n category: event.category,\n timestamp: event.timestamp.toISOString(),\n }\n }\n\n private priorityToSeverity(\n priority: NotificationRule['priority'],\n ): 'info' | 'warning' | 'critical' {\n if (priority === 'critical') return 'critical'\n if (priority === 'high') return 'warning'\n return 'info'\n }\n}\n\nexport default AdvancedNotifierAddon\n"],"mappings":"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","names":["COLLECTION"]}
package/dist/index.d.mts CHANGED
@@ -1,24 +1,5 @@
1
- import { ICamstackAddon, AddonManifest, AddonContext, CapabilityProviderMap, NotificationRule, ISettingsBackend, INotificationOutput, Notification, IScopedLogger, NotificationHistoryEntry, NotificationHistoryFilter } from '@camstack/types';
2
-
3
- declare class AdvancedNotifierAddon implements ICamstackAddon {
4
- readonly manifest: AddonManifest;
5
- private context;
6
- private ruleStore;
7
- private ruleEngine;
8
- private cooldown;
9
- private cachedRules;
10
- private consoleOutput;
11
- private outputs;
12
- private auditLog;
13
- private unsubscribers;
14
- private readonly notifier;
15
- initialize(context: AddonContext): Promise<void>;
16
- shutdown(): Promise<void>;
17
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
18
- private handleEvent;
19
- private buildTemplateVariables;
20
- private priorityToSeverity;
21
- }
1
+ export { AdvancedNotifierAddon } from './addon.mjs';
2
+ import { NotificationRule, ISettingsBackend, INotificationOutput, Notification, IScopedLogger, NotificationHistoryEntry, NotificationHistoryFilter } from '@camstack/types';
22
3
 
23
4
  declare function renderTemplate(template: string, variables: Record<string, string>): string;
24
5
 
@@ -113,4 +94,4 @@ declare class AuditLog {
113
94
  private getAll;
114
95
  }
115
96
 
116
- export { AdvancedNotifierAddon, AuditLog, ConsoleOutput, CooldownTracker, HomeAssistantOutput, NotificationBatcher, RuleEngine, RuleStore, WebhookOutput, renderTemplate };
97
+ export { AuditLog, ConsoleOutput, CooldownTracker, HomeAssistantOutput, NotificationBatcher, RuleEngine, RuleStore, WebhookOutput, renderTemplate };
package/dist/index.d.ts CHANGED
@@ -1,24 +1,5 @@
1
- import { ICamstackAddon, AddonManifest, AddonContext, CapabilityProviderMap, NotificationRule, ISettingsBackend, INotificationOutput, Notification, IScopedLogger, NotificationHistoryEntry, NotificationHistoryFilter } from '@camstack/types';
2
-
3
- declare class AdvancedNotifierAddon implements ICamstackAddon {
4
- readonly manifest: AddonManifest;
5
- private context;
6
- private ruleStore;
7
- private ruleEngine;
8
- private cooldown;
9
- private cachedRules;
10
- private consoleOutput;
11
- private outputs;
12
- private auditLog;
13
- private unsubscribers;
14
- private readonly notifier;
15
- initialize(context: AddonContext): Promise<void>;
16
- shutdown(): Promise<void>;
17
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
18
- private handleEvent;
19
- private buildTemplateVariables;
20
- private priorityToSeverity;
21
- }
1
+ export { AdvancedNotifierAddon } from './addon.js';
2
+ import { NotificationRule, ISettingsBackend, INotificationOutput, Notification, IScopedLogger, NotificationHistoryEntry, NotificationHistoryFilter } from '@camstack/types';
22
3
 
23
4
  declare function renderTemplate(template: string, variables: Record<string, string>): string;
24
5
 
@@ -113,4 +94,4 @@ declare class AuditLog {
113
94
  private getAll;
114
95
  }
115
96
 
116
- export { AdvancedNotifierAddon, AuditLog, ConsoleOutput, CooldownTracker, HomeAssistantOutput, NotificationBatcher, RuleEngine, RuleStore, WebhookOutput, renderTemplate };
97
+ export { AuditLog, ConsoleOutput, CooldownTracker, HomeAssistantOutput, NotificationBatcher, RuleEngine, RuleStore, WebhookOutput, renderTemplate };
package/dist/index.js CHANGED
@@ -18,8 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
23
  AdvancedNotifierAddon: () => AdvancedNotifierAddon,
24
24
  AuditLog: () => AuditLog,
25
25
  ConsoleOutput: () => ConsoleOutput,
@@ -31,7 +31,7 @@ __export(src_exports, {
31
31
  WebhookOutput: () => WebhookOutput,
32
32
  renderTemplate: () => renderTemplate
33
33
  });
34
- module.exports = __toCommonJS(src_exports);
34
+ module.exports = __toCommonJS(index_exports);
35
35
 
36
36
  // src/rules/rule-store.ts
37
37
  var COLLECTION = "addon-settings";