@camstack/addon-advanced-notifier 0.1.33 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,119 +1,154 @@
1
- "use strict";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const addon = require("./addon.js");
4
- class WebhookOutput {
5
- id = "webhook";
6
- name = "Webhook";
7
- icon = "webhook";
8
- url;
9
- constructor(url) {
10
- this.url = url;
11
- }
12
- async send(notification) {
13
- await fetch(this.url, {
14
- method: "POST",
15
- headers: { "Content-Type": "application/json" },
16
- body: JSON.stringify(notification)
17
- });
18
- }
19
- async sendTest() {
20
- try {
21
- await this.send({
22
- title: "Test Notification",
23
- message: "This is a test from CamStack Advanced Notifier",
24
- severity: "info",
25
- category: "test",
26
- timestamp: Date.now()
27
- });
28
- return { success: true };
29
- } catch (err) {
30
- return { success: false, error: String(err) };
31
- }
32
- }
2
+ const require_addon = require("./addon.js");
3
+ //#region src/outputs/http.ts
4
+ /**
5
+ * Outbound HTTP helper for notification outputs.
6
+ *
7
+ * Notification outputs POST to operator-supplied endpoints (webhooks, Home
8
+ * Assistant). A hung or very slow endpoint would otherwise leave `send()`
9
+ * pending indefinitely and stall the dispatch loop for every rule. Bound each
10
+ * request with an AbortController so a dead endpoint fails fast instead of
11
+ * wedging notifications.
12
+ */
13
+ /** Default per-request timeout for notification outputs. */
14
+ var DEFAULT_OUTPUT_TIMEOUT_MS = 1e4;
15
+ async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_OUTPUT_TIMEOUT_MS) {
16
+ const controller = new AbortController();
17
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
18
+ try {
19
+ return await fetch(url, {
20
+ ...init,
21
+ signal: controller.signal
22
+ });
23
+ } finally {
24
+ clearTimeout(timer);
25
+ }
33
26
  }
34
- class HomeAssistantOutput {
35
- id = "home-assistant";
36
- name = "Home Assistant";
37
- icon = "home";
38
- url;
39
- token;
40
- constructor(url, token) {
41
- this.url = url.replace(/\/$/, "");
42
- this.token = token;
43
- }
44
- async send(notification) {
45
- await fetch(`${this.url}/api/events/camstack_notification`, {
46
- method: "POST",
47
- headers: {
48
- "Content-Type": "application/json",
49
- Authorization: `Bearer ${this.token}`
50
- },
51
- body: JSON.stringify({
52
- title: notification.title,
53
- message: notification.message,
54
- severity: notification.severity,
55
- category: notification.category,
56
- device_id: notification.deviceId,
57
- data: notification.data
58
- })
59
- });
60
- }
61
- async sendTest() {
62
- try {
63
- await this.send({
64
- title: "CamStack Test",
65
- message: "Connection verified",
66
- severity: "info",
67
- category: "test",
68
- timestamp: Date.now()
69
- });
70
- return { success: true };
71
- } catch (err) {
72
- return { success: false, error: String(err) };
73
- }
74
- }
75
- }
76
- class NotificationBatcher {
77
- windowMs;
78
- handler;
79
- batches = /* @__PURE__ */ new Map();
80
- constructor(windowMs, handler) {
81
- this.windowMs = windowMs;
82
- this.handler = handler;
83
- }
84
- add(frameKey, event) {
85
- let batch = this.batches.get(frameKey);
86
- if (!batch) {
87
- batch = {
88
- events: [],
89
- timer: setTimeout(() => this.flush(frameKey), this.windowMs)
90
- };
91
- this.batches.set(frameKey, batch);
92
- }
93
- batch.events.push(event);
94
- }
95
- flush(frameKey) {
96
- const batch = this.batches.get(frameKey);
97
- if (!batch) return;
98
- this.batches.delete(frameKey);
99
- this.handler(frameKey, batch.events);
100
- }
101
- shutdown() {
102
- for (const [key, batch] of this.batches) {
103
- clearTimeout(batch.timer);
104
- this.handler(key, batch.events);
105
- }
106
- this.batches.clear();
107
- }
108
- }
109
- exports.AdvancedNotifierAddon = addon.AdvancedNotifierAddon;
110
- exports.AuditLog = addon.AuditLog;
111
- exports.ConsoleOutput = addon.ConsoleOutput;
112
- exports.CooldownTracker = addon.CooldownTracker;
113
- exports.RuleEngine = addon.RuleEngine;
114
- exports.RuleStore = addon.RuleStore;
115
- exports.renderTemplate = addon.renderTemplate;
27
+ //#endregion
28
+ //#region src/outputs/webhook.ts
29
+ var WebhookOutput = class {
30
+ id = "webhook";
31
+ name = "Webhook";
32
+ icon = "webhook";
33
+ url;
34
+ constructor(url) {
35
+ this.url = url;
36
+ }
37
+ async send(notification) {
38
+ await fetchWithTimeout(this.url, {
39
+ method: "POST",
40
+ headers: { "Content-Type": "application/json" },
41
+ body: JSON.stringify(notification)
42
+ });
43
+ }
44
+ async sendTest() {
45
+ try {
46
+ await this.send({
47
+ title: "Test Notification",
48
+ message: "This is a test from CamStack Advanced Notifier",
49
+ severity: "info",
50
+ category: "test",
51
+ timestamp: Date.now()
52
+ });
53
+ return { success: true };
54
+ } catch (err) {
55
+ return {
56
+ success: false,
57
+ error: String(err)
58
+ };
59
+ }
60
+ }
61
+ };
62
+ //#endregion
63
+ //#region src/outputs/home-assistant.ts
64
+ var HomeAssistantOutput = class {
65
+ id = "home-assistant";
66
+ name = "Home Assistant";
67
+ icon = "home";
68
+ url;
69
+ token;
70
+ constructor(url, token) {
71
+ this.url = url.replace(/\/$/, "");
72
+ this.token = token;
73
+ }
74
+ async send(notification) {
75
+ await fetchWithTimeout(`${this.url}/api/events/camstack_notification`, {
76
+ method: "POST",
77
+ headers: {
78
+ "Content-Type": "application/json",
79
+ Authorization: `Bearer ${this.token}`
80
+ },
81
+ body: JSON.stringify({
82
+ title: notification.title,
83
+ message: notification.message,
84
+ severity: notification.severity,
85
+ category: notification.category,
86
+ device_id: notification.deviceId,
87
+ data: notification.data
88
+ })
89
+ });
90
+ }
91
+ async sendTest() {
92
+ try {
93
+ await this.send({
94
+ title: "CamStack Test",
95
+ message: "Connection verified",
96
+ severity: "info",
97
+ category: "test",
98
+ timestamp: Date.now()
99
+ });
100
+ return { success: true };
101
+ } catch (err) {
102
+ return {
103
+ success: false,
104
+ error: String(err)
105
+ };
106
+ }
107
+ }
108
+ };
109
+ //#endregion
110
+ //#region src/batching/batcher.ts
111
+ var NotificationBatcher = class {
112
+ windowMs;
113
+ handler;
114
+ batches = /* @__PURE__ */ new Map();
115
+ constructor(windowMs, handler) {
116
+ this.windowMs = windowMs;
117
+ this.handler = handler;
118
+ }
119
+ add(frameKey, event) {
120
+ let batch = this.batches.get(frameKey);
121
+ if (!batch) {
122
+ batch = {
123
+ events: [],
124
+ timer: setTimeout(() => this.flush(frameKey), this.windowMs)
125
+ };
126
+ this.batches.set(frameKey, batch);
127
+ }
128
+ batch.events.push(event);
129
+ }
130
+ flush(frameKey) {
131
+ const batch = this.batches.get(frameKey);
132
+ if (!batch) return;
133
+ this.batches.delete(frameKey);
134
+ this.handler(frameKey, batch.events);
135
+ }
136
+ shutdown() {
137
+ for (const [key, batch] of this.batches) {
138
+ clearTimeout(batch.timer);
139
+ this.handler(key, batch.events);
140
+ }
141
+ this.batches.clear();
142
+ }
143
+ };
144
+ //#endregion
145
+ exports.AdvancedNotifierAddon = require_addon.AdvancedNotifierAddon;
146
+ exports.AuditLog = require_addon.AuditLog;
147
+ exports.ConsoleOutput = require_addon.ConsoleOutput;
148
+ exports.CooldownTracker = require_addon.CooldownTracker;
116
149
  exports.HomeAssistantOutput = HomeAssistantOutput;
117
150
  exports.NotificationBatcher = NotificationBatcher;
151
+ exports.RuleEngine = require_addon.RuleEngine;
152
+ exports.RuleStore = require_addon.RuleStore;
118
153
  exports.WebhookOutput = WebhookOutput;
119
- //# sourceMappingURL=index.js.map
154
+ exports.renderTemplate = require_addon.renderTemplate;
package/dist/index.mjs CHANGED
@@ -1,119 +1,144 @@
1
- import { AdvancedNotifierAddon, A, C, a, R, b, r } from "./addon.mjs";
2
- class WebhookOutput {
3
- id = "webhook";
4
- name = "Webhook";
5
- icon = "webhook";
6
- url;
7
- constructor(url) {
8
- this.url = url;
9
- }
10
- async send(notification) {
11
- await fetch(this.url, {
12
- method: "POST",
13
- headers: { "Content-Type": "application/json" },
14
- body: JSON.stringify(notification)
15
- });
16
- }
17
- async sendTest() {
18
- try {
19
- await this.send({
20
- title: "Test Notification",
21
- message: "This is a test from CamStack Advanced Notifier",
22
- severity: "info",
23
- category: "test",
24
- timestamp: Date.now()
25
- });
26
- return { success: true };
27
- } catch (err) {
28
- return { success: false, error: String(err) };
29
- }
30
- }
1
+ import { AdvancedNotifierAddon, a as RuleEngine, i as CooldownTracker, n as ConsoleOutput, o as RuleStore, r as renderTemplate, t as AuditLog } from "./addon.mjs";
2
+ //#region src/outputs/http.ts
3
+ /**
4
+ * Outbound HTTP helper for notification outputs.
5
+ *
6
+ * Notification outputs POST to operator-supplied endpoints (webhooks, Home
7
+ * Assistant). A hung or very slow endpoint would otherwise leave `send()`
8
+ * pending indefinitely and stall the dispatch loop for every rule. Bound each
9
+ * request with an AbortController so a dead endpoint fails fast instead of
10
+ * wedging notifications.
11
+ */
12
+ /** Default per-request timeout for notification outputs. */
13
+ var DEFAULT_OUTPUT_TIMEOUT_MS = 1e4;
14
+ async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_OUTPUT_TIMEOUT_MS) {
15
+ const controller = new AbortController();
16
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
17
+ try {
18
+ return await fetch(url, {
19
+ ...init,
20
+ signal: controller.signal
21
+ });
22
+ } finally {
23
+ clearTimeout(timer);
24
+ }
31
25
  }
32
- class HomeAssistantOutput {
33
- id = "home-assistant";
34
- name = "Home Assistant";
35
- icon = "home";
36
- url;
37
- token;
38
- constructor(url, token) {
39
- this.url = url.replace(/\/$/, "");
40
- this.token = token;
41
- }
42
- async send(notification) {
43
- await fetch(`${this.url}/api/events/camstack_notification`, {
44
- method: "POST",
45
- headers: {
46
- "Content-Type": "application/json",
47
- Authorization: `Bearer ${this.token}`
48
- },
49
- body: JSON.stringify({
50
- title: notification.title,
51
- message: notification.message,
52
- severity: notification.severity,
53
- category: notification.category,
54
- device_id: notification.deviceId,
55
- data: notification.data
56
- })
57
- });
58
- }
59
- async sendTest() {
60
- try {
61
- await this.send({
62
- title: "CamStack Test",
63
- message: "Connection verified",
64
- severity: "info",
65
- category: "test",
66
- timestamp: Date.now()
67
- });
68
- return { success: true };
69
- } catch (err) {
70
- return { success: false, error: String(err) };
71
- }
72
- }
73
- }
74
- class NotificationBatcher {
75
- windowMs;
76
- handler;
77
- batches = /* @__PURE__ */ new Map();
78
- constructor(windowMs, handler) {
79
- this.windowMs = windowMs;
80
- this.handler = handler;
81
- }
82
- add(frameKey, event) {
83
- let batch = this.batches.get(frameKey);
84
- if (!batch) {
85
- batch = {
86
- events: [],
87
- timer: setTimeout(() => this.flush(frameKey), this.windowMs)
88
- };
89
- this.batches.set(frameKey, batch);
90
- }
91
- batch.events.push(event);
92
- }
93
- flush(frameKey) {
94
- const batch = this.batches.get(frameKey);
95
- if (!batch) return;
96
- this.batches.delete(frameKey);
97
- this.handler(frameKey, batch.events);
98
- }
99
- shutdown() {
100
- for (const [key, batch] of this.batches) {
101
- clearTimeout(batch.timer);
102
- this.handler(key, batch.events);
103
- }
104
- this.batches.clear();
105
- }
106
- }
107
- export {
108
- AdvancedNotifierAddon,
109
- A as AuditLog,
110
- C as ConsoleOutput,
111
- a as CooldownTracker,
112
- HomeAssistantOutput,
113
- NotificationBatcher,
114
- R as RuleEngine,
115
- b as RuleStore,
116
- WebhookOutput,
117
- r as renderTemplate
26
+ //#endregion
27
+ //#region src/outputs/webhook.ts
28
+ var WebhookOutput = class {
29
+ id = "webhook";
30
+ name = "Webhook";
31
+ icon = "webhook";
32
+ url;
33
+ constructor(url) {
34
+ this.url = url;
35
+ }
36
+ async send(notification) {
37
+ await fetchWithTimeout(this.url, {
38
+ method: "POST",
39
+ headers: { "Content-Type": "application/json" },
40
+ body: JSON.stringify(notification)
41
+ });
42
+ }
43
+ async sendTest() {
44
+ try {
45
+ await this.send({
46
+ title: "Test Notification",
47
+ message: "This is a test from CamStack Advanced Notifier",
48
+ severity: "info",
49
+ category: "test",
50
+ timestamp: Date.now()
51
+ });
52
+ return { success: true };
53
+ } catch (err) {
54
+ return {
55
+ success: false,
56
+ error: String(err)
57
+ };
58
+ }
59
+ }
60
+ };
61
+ //#endregion
62
+ //#region src/outputs/home-assistant.ts
63
+ var HomeAssistantOutput = class {
64
+ id = "home-assistant";
65
+ name = "Home Assistant";
66
+ icon = "home";
67
+ url;
68
+ token;
69
+ constructor(url, token) {
70
+ this.url = url.replace(/\/$/, "");
71
+ this.token = token;
72
+ }
73
+ async send(notification) {
74
+ await fetchWithTimeout(`${this.url}/api/events/camstack_notification`, {
75
+ method: "POST",
76
+ headers: {
77
+ "Content-Type": "application/json",
78
+ Authorization: `Bearer ${this.token}`
79
+ },
80
+ body: JSON.stringify({
81
+ title: notification.title,
82
+ message: notification.message,
83
+ severity: notification.severity,
84
+ category: notification.category,
85
+ device_id: notification.deviceId,
86
+ data: notification.data
87
+ })
88
+ });
89
+ }
90
+ async sendTest() {
91
+ try {
92
+ await this.send({
93
+ title: "CamStack Test",
94
+ message: "Connection verified",
95
+ severity: "info",
96
+ category: "test",
97
+ timestamp: Date.now()
98
+ });
99
+ return { success: true };
100
+ } catch (err) {
101
+ return {
102
+ success: false,
103
+ error: String(err)
104
+ };
105
+ }
106
+ }
107
+ };
108
+ //#endregion
109
+ //#region src/batching/batcher.ts
110
+ var NotificationBatcher = class {
111
+ windowMs;
112
+ handler;
113
+ batches = /* @__PURE__ */ new Map();
114
+ constructor(windowMs, handler) {
115
+ this.windowMs = windowMs;
116
+ this.handler = handler;
117
+ }
118
+ add(frameKey, event) {
119
+ let batch = this.batches.get(frameKey);
120
+ if (!batch) {
121
+ batch = {
122
+ events: [],
123
+ timer: setTimeout(() => this.flush(frameKey), this.windowMs)
124
+ };
125
+ this.batches.set(frameKey, batch);
126
+ }
127
+ batch.events.push(event);
128
+ }
129
+ flush(frameKey) {
130
+ const batch = this.batches.get(frameKey);
131
+ if (!batch) return;
132
+ this.batches.delete(frameKey);
133
+ this.handler(frameKey, batch.events);
134
+ }
135
+ shutdown() {
136
+ for (const [key, batch] of this.batches) {
137
+ clearTimeout(batch.timer);
138
+ this.handler(key, batch.events);
139
+ }
140
+ this.batches.clear();
141
+ }
118
142
  };
119
- //# sourceMappingURL=index.mjs.map
143
+ //#endregion
144
+ export { AdvancedNotifierAddon, AuditLog, ConsoleOutput, CooldownTracker, HomeAssistantOutput, NotificationBatcher, RuleEngine, RuleStore, WebhookOutput, renderTemplate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-advanced-notifier",
3
- "version": "0.1.33",
3
+ "version": "0.2.0",
4
4
  "description": "Rules-based notification engine for CamStack",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@camstack/types": "*",
55
- "tsup": "^8.0.0",
56
- "typescript": "~5.9.0",
55
+ "typescript": "~6.0.3",
56
+ "vite": "^8.0.11",
57
57
  "vitest": "^3.0.0"
58
58
  }
59
59
  }