@camstack/addon-advanced-notifier 1.1.13 → 1.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/addon.mjs CHANGED
@@ -4628,7 +4628,7 @@ function _instanceof(cls, params = {}) {
4628
4628
  return inst;
4629
4629
  }
4630
4630
  //#endregion
4631
- //#region ../types/dist/sleep-C2M2zF7x.mjs
4631
+ //#region ../types/dist/sleep-MHm--th-.mjs
4632
4632
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4633
4633
  EventCategory["SystemBoot"] = "system.boot";
4634
4634
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5890,6 +5890,7 @@ var CamStreamKindSchema = _enum([
5890
5890
  "pull-rtsp",
5891
5891
  "pull-rtmp",
5892
5892
  "pull-http",
5893
+ "pull-flv",
5893
5894
  "pull-rfc4571",
5894
5895
  "push-annexb",
5895
5896
  "derived"
@@ -13213,7 +13214,7 @@ var AddBrokerInputSchema = object({
13213
13214
  });
13214
13215
  var AddBrokerResultSchema = object({ id: string() });
13215
13216
  var IdInputSchema = object({ id: string() });
13216
- var TestResultSchema = discriminatedUnion("ok", [object({
13217
+ var TestResultSchema$1 = discriminatedUnion("ok", [object({
13217
13218
  ok: literal(true),
13218
13219
  latencyMs: number()
13219
13220
  }), object({
@@ -13236,7 +13237,7 @@ var StatusSchema = object({
13236
13237
  brokerCount: number(),
13237
13238
  embeddedRunning: boolean()
13238
13239
  });
13239
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
13240
+ method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema$1, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
13240
13241
  var NetworkEndpointSchema = object({
13241
13242
  url: string(),
13242
13243
  hostname: string(),
@@ -13270,29 +13271,210 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
13270
13271
  sourcePort: number().optional()
13271
13272
  });
13272
13273
  method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
13274
+ /**
13275
+ * notification-output — canonical, capability-gated notification delivery.
13276
+ *
13277
+ * Apprise-derived model (see
13278
+ * `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
13279
+ * callers emit ONE canonical `Notification`; each provider declares a
13280
+ * per-kind capability descriptor (`TargetKind`), and the pure degrade
13281
+ * engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
13282
+ * message to what the kind supports — callers never special-case a service.
13283
+ *
13284
+ * DESIGN DECISIONS (locked):
13285
+ * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
13286
+ * `setTargetEnabled`), each provider persisting via the `settings-store`
13287
+ * cap. Rationale: the admin UI needs one uniform surface across the
13288
+ * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
13289
+ * alternative would fork the UI per addon and cannot host the
13290
+ * discovery→adopt flow.
13291
+ * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
13292
+ * the generated cap-mount auto-`concatCollection`-fans them across every
13293
+ * registered provider (notifiers addon + HA addon) so one catalog is
13294
+ * routable. `send` / `testTarget` / CRUD route to ONE provider by the
13295
+ * `addonId` the generated collection router extracts from the call input.
13296
+ * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
13297
+ * transformer) + UDS MsgPack both round-trip typed arrays — already used by
13298
+ * `storage` / `storage-provider` / `recording` caps over the same path. No
13299
+ * base64 fallback needed.
13300
+ *
13301
+ * TODO (deferred, closed-set change — separate decision): add
13302
+ * `providerKind: 'notify'` so notification providers surface on the unified
13303
+ * admin "Integrations" page.
13304
+ */
13305
+ /**
13306
+ * Zentik-derived typed-media enum — the superset across every kind. Each
13307
+ * adapter picks what it supports and the degrade engine filters the rest.
13308
+ */
13309
+ var AttachmentMediaTypeSchema = _enum([
13310
+ "image",
13311
+ "video",
13312
+ "gif",
13313
+ "audio",
13314
+ "icon"
13315
+ ]);
13316
+ /**
13317
+ * A single attachment. Exactly one of `url` (remote source, most adapters
13318
+ * prefer this) or `bytes` (inline source; required for Pushover-style
13319
+ * bytes-only kinds) MUST be present — the degrade engine expresses a
13320
+ * url→bytes fetch as a `needsFetch` directive the adapter executes.
13321
+ */
13322
+ var AttachmentSchema = object({
13323
+ mediaType: AttachmentMediaTypeSchema,
13324
+ url: string().optional(),
13325
+ bytes: _instanceof(Uint8Array).optional(),
13326
+ mime: string().optional(),
13327
+ name: string().optional()
13328
+ }).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
13329
+ var NotificationFormatSchema = _enum([
13330
+ "text",
13331
+ "markdown",
13332
+ "html"
13333
+ ]);
13334
+ /** A single tap-through action button. */
13335
+ var NotificationActionSchema = object({
13336
+ id: string(),
13337
+ label: string(),
13338
+ url: string().optional()
13339
+ });
13340
+ /**
13341
+ * The canonical notification. `body` is the only hard field (Apprise model).
13342
+ * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
13343
+ * NOT a fixed severity enum — each kind declares its own `caps.levels` and
13344
+ * the adapter maps this ordinal onto its native level. `level?` is an
13345
+ * optional kind-native level id (`emergency`, `silent`, …) that overrides
13346
+ * `priority` for that one target.
13347
+ */
13348
+ var NotificationSchema = object({
13349
+ body: string(),
13350
+ title: string().optional(),
13351
+ format: NotificationFormatSchema.default("text"),
13352
+ priority: number().int().min(1).max(5).default(3),
13353
+ level: string().optional(),
13354
+ attachments: array(AttachmentSchema).optional(),
13355
+ clickUrl: string().optional(),
13356
+ actions: array(NotificationActionSchema).optional(),
13357
+ sound: string().optional(),
13358
+ ttl: number().optional(),
13359
+ tag: string().optional(),
13360
+ deviceId: number().optional(),
13361
+ eventId: string().optional(),
13362
+ metadata: record(string(), unknown()).optional()
13363
+ });
13364
+ /** One declared native severity/priority level for a kind. */
13365
+ var TargetKindLevelSchema = object({
13366
+ id: string(),
13367
+ label: string(),
13368
+ /** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
13369
+ ordinal: number().int().min(1).max(5).nullable(),
13370
+ flags: object({
13371
+ critical: boolean().optional(),
13372
+ silent: boolean().optional(),
13373
+ noPush: boolean().optional()
13374
+ }).optional(),
13375
+ /** e.g. Pushover `emergency` requires `retry` / `expire`. */
13376
+ requires: array(string()).optional(),
13377
+ description: string().optional()
13378
+ });
13379
+ /** The full capability block consulted before dispatch. */
13380
+ var TargetKindCapsSchema = object({
13381
+ attachments: object({
13382
+ mediaTypes: array(AttachmentMediaTypeSchema),
13383
+ mode: _enum([
13384
+ "url",
13385
+ "bytes",
13386
+ "both"
13387
+ ]),
13388
+ max: number().int().nonnegative(),
13389
+ maxBytes: number().int().positive().optional()
13390
+ }),
13391
+ /** Max action buttons (0 = none). */
13392
+ actions: number().int().nonnegative(),
13393
+ levels: array(TargetKindLevelSchema),
13394
+ format: array(NotificationFormatSchema),
13395
+ clickUrl: boolean(),
13396
+ sound: boolean(),
13397
+ ttl: boolean(),
13398
+ bodyMaxLen: number().int().positive()
13399
+ });
13400
+ /**
13401
+ * `configSchema` is a `ConfigUISchema` tree passed through to the admin
13402
+ * FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
13403
+ * `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
13404
+ * the union is large and not meant for runtime validation here; the exported
13405
+ * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
13406
+ */
13407
+ var ConfigSchemaPassthrough = unknown();
13408
+ var TargetKindSchema = object({
13409
+ kind: string(),
13410
+ label: string(),
13411
+ icon: string(),
13412
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
13413
+ addonId: string(),
13414
+ configSchema: ConfigSchemaPassthrough,
13415
+ supportsDiscovery: boolean(),
13416
+ caps: TargetKindCapsSchema
13417
+ });
13418
+ /**
13419
+ * A persisted target. `config` holds secrets; providers REDACT secret fields
13420
+ * (return a presence marker only) when serving `listTargets` — never
13421
+ * round-trip a stored secret to the UI.
13422
+ */
13423
+ var TargetSchema = object({
13424
+ id: string(),
13425
+ name: string(),
13426
+ kind: string(),
13427
+ addonId: string(),
13428
+ enabled: boolean(),
13429
+ config: record(string(), unknown())
13430
+ });
13431
+ /** A discovery-surfaced candidate (config is partial + non-secret). */
13432
+ var DiscoveredTargetSchema = object({
13433
+ kind: string(),
13434
+ suggestedName: string(),
13435
+ config: record(string(), unknown())
13436
+ });
13437
+ /** The degrade engine's report — what was resolved / dropped / degraded. */
13438
+ var RenderedAsSchema = object({
13439
+ level: string(),
13440
+ format: NotificationFormatSchema,
13441
+ attachmentsSent: number().int().nonnegative(),
13442
+ actionsSent: number().int().nonnegative(),
13443
+ truncated: boolean(),
13444
+ dropped: array(string())
13445
+ });
13446
+ var SendResultSchema = object({
13447
+ success: boolean(),
13448
+ error: string().optional(),
13449
+ renderedAs: RenderedAsSchema.optional()
13450
+ });
13451
+ /** Same shape as SendResult — kept as a distinct name for the test panel. */
13452
+ var TestResultSchema = SendResultSchema;
13273
13453
  var notificationOutputCapability = {
13274
13454
  name: "notification-output",
13275
13455
  scope: "system",
13276
13456
  mode: "collection",
13277
13457
  methods: {
13458
+ listTargetKinds: method(object({}), array(TargetKindSchema)),
13459
+ listTargets: method(object({}), array(TargetSchema)),
13460
+ discoverTargets: method(object({
13461
+ kind: string(),
13462
+ config: record(string(), unknown()).optional()
13463
+ }), array(DiscoveredTargetSchema)),
13278
13464
  send: method(object({
13279
- title: string(),
13280
- body: string(),
13281
- imageUrl: string().optional(),
13282
- deviceId: number().optional(),
13283
- eventId: string().optional(),
13284
- priority: _enum([
13285
- "low",
13286
- "normal",
13287
- "high",
13288
- "critical"
13289
- ]).default("normal"),
13290
- metadata: record(string(), unknown()).optional()
13291
- }), _void(), { kind: "mutation" }),
13292
- sendTest: method(_void(), object({
13293
- success: boolean(),
13294
- error: string().optional()
13295
- }), { kind: "mutation" })
13465
+ targetId: string(),
13466
+ notification: NotificationSchema
13467
+ }), SendResultSchema, { kind: "mutation" }),
13468
+ testTarget: method(object({
13469
+ targetId: string(),
13470
+ sample: NotificationSchema.optional()
13471
+ }), TestResultSchema, { kind: "mutation" }),
13472
+ upsertTarget: method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }),
13473
+ deleteTarget: method(object({ targetId: string() }), _void(), { kind: "mutation" }),
13474
+ setTargetEnabled: method(object({
13475
+ targetId: string(),
13476
+ enabled: boolean()
13477
+ }), _void(), { kind: "mutation" })
13296
13478
  }
13297
13479
  };
13298
13480
  /**
@@ -19289,13 +19471,49 @@ Object.freeze({
19289
19471
  addonId: null,
19290
19472
  access: "create"
19291
19473
  },
19474
+ "notificationOutput.deleteTarget": {
19475
+ capName: "notification-output",
19476
+ capScope: "system",
19477
+ addonId: null,
19478
+ access: "delete"
19479
+ },
19480
+ "notificationOutput.discoverTargets": {
19481
+ capName: "notification-output",
19482
+ capScope: "system",
19483
+ addonId: null,
19484
+ access: "view"
19485
+ },
19486
+ "notificationOutput.listTargetKinds": {
19487
+ capName: "notification-output",
19488
+ capScope: "system",
19489
+ addonId: null,
19490
+ access: "view"
19491
+ },
19492
+ "notificationOutput.listTargets": {
19493
+ capName: "notification-output",
19494
+ capScope: "system",
19495
+ addonId: null,
19496
+ access: "view"
19497
+ },
19292
19498
  "notificationOutput.send": {
19293
19499
  capName: "notification-output",
19294
19500
  capScope: "system",
19295
19501
  addonId: null,
19296
19502
  access: "create"
19297
19503
  },
19298
- "notificationOutput.sendTest": {
19504
+ "notificationOutput.setTargetEnabled": {
19505
+ capName: "notification-output",
19506
+ capScope: "system",
19507
+ addonId: null,
19508
+ access: "create"
19509
+ },
19510
+ "notificationOutput.testTarget": {
19511
+ capName: "notification-output",
19512
+ capScope: "system",
19513
+ addonId: null,
19514
+ access: "create"
19515
+ },
19516
+ "notificationOutput.upsertTarget": {
19299
19517
  capName: "notification-output",
19300
19518
  capScope: "system",
19301
19519
  addonId: null,
@@ -21281,42 +21499,120 @@ object({
21281
21499
  schemaVersion: literal(1)
21282
21500
  });
21283
21501
  //#endregion
21284
- //#region src/rules/rule-store.ts
21502
+ //#region src/history/audit-log.ts
21285
21503
  var COLLECTION$1 = "addon-settings";
21286
- var KEY = "advanced-notifier:rules";
21287
- var RuleStore = class {
21504
+ var LOG_KEY = "notifier-history:log";
21505
+ var AuditLog = class {
21288
21506
  api;
21289
- constructor(api) {
21507
+ maxEntries;
21508
+ constructor(api, maxEntries = 1e3) {
21290
21509
  this.api = api;
21510
+ this.maxEntries = maxEntries;
21291
21511
  }
21292
- async getRules() {
21512
+ async record(entry) {
21513
+ const updated = [...await this.getAll(), entry];
21514
+ const trimmed = updated.length > this.maxEntries ? updated.slice(updated.length - this.maxEntries) : updated;
21515
+ await this.api.settingsStore.set.mutate({
21516
+ collection: COLLECTION$1,
21517
+ key: LOG_KEY,
21518
+ value: trimmed
21519
+ });
21520
+ }
21521
+ async getHistory(filter) {
21522
+ let entries = await this.getAll();
21523
+ if (filter?.ruleId) entries = entries.filter((e) => e.ruleId === filter.ruleId);
21524
+ if (filter?.deviceId) {
21525
+ const deviceId = filter.deviceId;
21526
+ entries = entries.filter((e) => e.deviceId === deviceId);
21527
+ }
21528
+ if (filter?.from !== void 0) {
21529
+ const from = filter.from;
21530
+ entries = entries.filter((e) => e.timestamp >= from);
21531
+ }
21532
+ if (filter?.to !== void 0) {
21533
+ const to = filter.to;
21534
+ entries = entries.filter((e) => e.timestamp <= to);
21535
+ }
21536
+ if (filter?.limit) entries = entries.slice(-filter.limit);
21537
+ return entries;
21538
+ }
21539
+ async getAll() {
21293
21540
  const raw = await this.api.settingsStore.get.query({
21294
21541
  collection: COLLECTION$1,
21295
- key: KEY
21542
+ key: LOG_KEY
21296
21543
  });
21297
21544
  if (!raw || !Array.isArray(raw)) return [];
21298
21545
  return raw;
21299
21546
  }
21300
- async saveRules(rules) {
21301
- await this.api.settingsStore.set.mutate({
21302
- collection: COLLECTION$1,
21303
- key: KEY,
21304
- value: [...rules]
21547
+ };
21548
+ //#endregion
21549
+ //#region src/outputs/console.ts
21550
+ var ConsoleOutput = class {
21551
+ id = "console";
21552
+ name = "Console Log";
21553
+ icon = "terminal";
21554
+ logger;
21555
+ constructor(logger) {
21556
+ this.logger = logger;
21557
+ }
21558
+ async send(notification) {
21559
+ this.logger.info(`[p${notification.priority}] ${notification.title ?? ""}: ${notification.body}`, notification.deviceId !== void 0 ? { tags: { deviceId: notification.deviceId } } : void 0);
21560
+ }
21561
+ async sendTest() {
21562
+ await this.send({
21563
+ title: "Test",
21564
+ body: "Console output working",
21565
+ format: "text",
21566
+ priority: 3
21305
21567
  });
21568
+ return { success: true };
21306
21569
  }
21307
- async upsertRule(rule) {
21308
- const rules = await this.getRules();
21309
- const idx = rules.findIndex((r) => r.id === rule.id);
21310
- if (idx >= 0) rules[idx] = rule;
21311
- else rules.push(rule);
21312
- await this.saveRules(rules);
21570
+ };
21571
+ //#endregion
21572
+ //#region src/rules/cooldown.ts
21573
+ var CooldownTracker = class {
21574
+ lastFired = /* @__PURE__ */ new Map();
21575
+ canFire(ruleId, cooldownSeconds) {
21576
+ const last = this.lastFired.get(ruleId);
21577
+ if (last === void 0) return true;
21578
+ return (Date.now() - last) / 1e3 >= cooldownSeconds;
21313
21579
  }
21314
- async deleteRule(ruleId) {
21315
- const rules = await this.getRules();
21316
- await this.saveRules(rules.filter((r) => r.id !== ruleId));
21580
+ recordFire(ruleId) {
21581
+ this.lastFired.set(ruleId, Date.now());
21582
+ }
21583
+ reset() {
21584
+ this.lastFired.clear();
21317
21585
  }
21318
21586
  };
21319
21587
  //#endregion
21588
+ //#region src/rules/recent-events.ts
21589
+ /**
21590
+ * Rehydrate serialized recent events into `SystemEvent`s and drop any that
21591
+ * fall before `since`. Order is preserved (the hub returns oldest → newest).
21592
+ */
21593
+ function reconstructRecentEvents(serialized, since) {
21594
+ const sinceMs = since.getTime();
21595
+ const events = [];
21596
+ for (const e of serialized) {
21597
+ const timestamp = new Date(e.timestamp);
21598
+ if (timestamp.getTime() < sinceMs) continue;
21599
+ events.push({
21600
+ id: e.id,
21601
+ timestamp,
21602
+ source: {
21603
+ type: e.source.type,
21604
+ id: e.source.id,
21605
+ ...e.source.nodeId !== void 0 ? { nodeId: e.source.nodeId } : {},
21606
+ ...e.source.addonId !== void 0 ? { addonId: e.source.addonId } : {},
21607
+ ...e.source.deviceId !== void 0 ? { deviceId: e.source.deviceId } : {}
21608
+ },
21609
+ category: e.category,
21610
+ data: e.data
21611
+ });
21612
+ }
21613
+ return events;
21614
+ }
21615
+ //#endregion
21320
21616
  //#region src/rules/rule-engine.ts
21321
21617
  var RuleEngine = class {
21322
21618
  clip;
@@ -21389,19 +21685,39 @@ var RuleEngine = class {
21389
21685
  }
21390
21686
  };
21391
21687
  //#endregion
21392
- //#region src/rules/cooldown.ts
21393
- var CooldownTracker = class {
21394
- lastFired = /* @__PURE__ */ new Map();
21395
- canFire(ruleId, cooldownSeconds) {
21396
- const last = this.lastFired.get(ruleId);
21397
- if (last === void 0) return true;
21398
- return (Date.now() - last) / 1e3 >= cooldownSeconds;
21688
+ //#region src/rules/rule-store.ts
21689
+ var COLLECTION = "addon-settings";
21690
+ var KEY = "advanced-notifier:rules";
21691
+ var RuleStore = class {
21692
+ api;
21693
+ constructor(api) {
21694
+ this.api = api;
21399
21695
  }
21400
- recordFire(ruleId) {
21401
- this.lastFired.set(ruleId, Date.now());
21696
+ async getRules() {
21697
+ const raw = await this.api.settingsStore.get.query({
21698
+ collection: COLLECTION,
21699
+ key: KEY
21700
+ });
21701
+ if (!raw || !Array.isArray(raw)) return [];
21702
+ return raw;
21402
21703
  }
21403
- reset() {
21404
- this.lastFired.clear();
21704
+ async saveRules(rules) {
21705
+ await this.api.settingsStore.set.mutate({
21706
+ collection: COLLECTION,
21707
+ key: KEY,
21708
+ value: [...rules]
21709
+ });
21710
+ }
21711
+ async upsertRule(rule) {
21712
+ const rules = await this.getRules();
21713
+ const idx = rules.findIndex((r) => r.id === rule.id);
21714
+ if (idx >= 0) rules[idx] = rule;
21715
+ else rules.push(rule);
21716
+ await this.saveRules(rules);
21717
+ }
21718
+ async deleteRule(ruleId) {
21719
+ const rules = await this.getRules();
21720
+ await this.saveRules(rules.filter((r) => r.id !== ruleId));
21405
21721
  }
21406
21722
  };
21407
21723
  //#endregion
@@ -21413,77 +21729,6 @@ function renderTemplate(template, variables) {
21413
21729
  });
21414
21730
  }
21415
21731
  //#endregion
21416
- //#region src/outputs/console.ts
21417
- var ConsoleOutput = class {
21418
- id = "console";
21419
- name = "Console Log";
21420
- icon = "terminal";
21421
- logger;
21422
- constructor(logger) {
21423
- this.logger = logger;
21424
- }
21425
- async send(notification) {
21426
- this.logger.info(`[${notification.severity}] ${notification.title}: ${notification.message}`, notification.deviceId !== void 0 ? { tags: { deviceId: notification.deviceId } } : void 0);
21427
- }
21428
- async sendTest() {
21429
- await this.send({
21430
- title: "Test",
21431
- message: "Console output working",
21432
- severity: "info",
21433
- category: "test",
21434
- timestamp: Date.now()
21435
- });
21436
- return { success: true };
21437
- }
21438
- };
21439
- //#endregion
21440
- //#region src/history/audit-log.ts
21441
- var COLLECTION = "addon-settings";
21442
- var LOG_KEY = "notifier-history:log";
21443
- var AuditLog = class {
21444
- api;
21445
- maxEntries;
21446
- constructor(api, maxEntries = 1e3) {
21447
- this.api = api;
21448
- this.maxEntries = maxEntries;
21449
- }
21450
- async record(entry) {
21451
- const updated = [...await this.getAll(), entry];
21452
- const trimmed = updated.length > this.maxEntries ? updated.slice(updated.length - this.maxEntries) : updated;
21453
- await this.api.settingsStore.set.mutate({
21454
- collection: COLLECTION,
21455
- key: LOG_KEY,
21456
- value: trimmed
21457
- });
21458
- }
21459
- async getHistory(filter) {
21460
- let entries = await this.getAll();
21461
- if (filter?.ruleId) entries = entries.filter((e) => e.ruleId === filter.ruleId);
21462
- if (filter?.deviceId) {
21463
- const deviceId = filter.deviceId;
21464
- entries = entries.filter((e) => e.deviceId === deviceId);
21465
- }
21466
- if (filter?.from !== void 0) {
21467
- const from = filter.from;
21468
- entries = entries.filter((e) => e.timestamp >= from);
21469
- }
21470
- if (filter?.to !== void 0) {
21471
- const to = filter.to;
21472
- entries = entries.filter((e) => e.timestamp <= to);
21473
- }
21474
- if (filter?.limit) entries = entries.slice(-filter.limit);
21475
- return entries;
21476
- }
21477
- async getAll() {
21478
- const raw = await this.api.settingsStore.get.query({
21479
- collection: COLLECTION,
21480
- key: LOG_KEY
21481
- });
21482
- if (!raw || !Array.isArray(raw)) return [];
21483
- return raw;
21484
- }
21485
- };
21486
- //#endregion
21487
21732
  //#region src/addon.ts
21488
21733
  var EVENT_CATEGORIES = [
21489
21734
  EventCategory.DetectionRaw,
@@ -21535,7 +21780,9 @@ var AdvancedNotifierAddon = class extends BaseAddon {
21535
21780
  const rule = this.cachedRules.find((r) => r.id === ruleId);
21536
21781
  if (!rule) return { results: [] };
21537
21782
  const since = /* @__PURE__ */ new Date(Date.now() - lookbackMinutes * 60 * 1e3);
21538
- return { results: this.ctx.eventBus.getRecent({ category: void 0 }, 1e3).filter((e) => e.timestamp >= since).map((event) => {
21783
+ const api = this.ctx.api;
21784
+ if (!api) return { results: [] };
21785
+ return { results: reconstructRecentEvents(await api.eventBusProxy.getRecent.query({ limit: 1e3 }), since).map((event) => {
21539
21786
  const matched = this.ruleEngine.evaluate(event, [rule]);
21540
21787
  return {
21541
21788
  ruleId,
@@ -21699,12 +21946,11 @@ var AdvancedNotifierAddon = class extends BaseAddon {
21699
21946
  const deviceId = Number.isFinite(deviceIdNum) ? deviceIdNum : void 0;
21700
21947
  const notification = {
21701
21948
  title,
21702
- message,
21703
- severity: this.priorityToSeverity(rule.priority),
21704
- category: event.category,
21949
+ body: message,
21950
+ format: "text",
21951
+ priority: this.priorityToOrdinal(rule.priority),
21705
21952
  deviceId,
21706
- data: event.data,
21707
- timestamp: event.timestamp.getTime()
21953
+ metadata: event.data
21708
21954
  };
21709
21955
  let success = true;
21710
21956
  let dispatchError;
@@ -21749,11 +21995,19 @@ var AdvancedNotifierAddon = class extends BaseAddon {
21749
21995
  timestamp: event.timestamp.toISOString()
21750
21996
  };
21751
21997
  }
21752
- priorityToSeverity(priority) {
21753
- if (priority === "critical") return "critical";
21754
- if (priority === "high") return "warning";
21755
- return "info";
21998
+ /**
21999
+ * Map a rule's qualitative priority onto the canonical 1..5 ordinal.
22000
+ * Callers now pass ordinal priority; each `notification-output` provider
22001
+ * maps the ordinal onto its declared native level.
22002
+ */
22003
+ priorityToOrdinal(priority) {
22004
+ switch (priority) {
22005
+ case "critical": return 5;
22006
+ case "high": return 4;
22007
+ case "low": return 2;
22008
+ default: return 3;
22009
+ }
21756
22010
  }
21757
22011
  };
21758
22012
  //#endregion
21759
- export { AdvancedNotifierAddon, AdvancedNotifierAddon as default, RuleEngine as a, CooldownTracker as i, ConsoleOutput as n, RuleStore as o, renderTemplate as r, AuditLog as t };
22013
+ export { AdvancedNotifierAddon, AdvancedNotifierAddon as default, ConsoleOutput as a, CooldownTracker as i, RuleStore as n, AuditLog as o, RuleEngine as r, renderTemplate as t };