@camstack/addon-advanced-notifier 0.1.32 → 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/addon.js +20311 -14066
- package/dist/addon.mjs +20305 -14071
- package/dist/index.js +149 -114
- package/dist/index.mjs +142 -117
- package/package.json +3 -3
- package/dist/addon.js.map +0 -1
- package/dist/addon.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,119 +1,154 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
154
|
+
exports.renderTemplate = require_addon.renderTemplate;
|
package/dist/index.mjs
CHANGED
|
@@ -1,119 +1,144 @@
|
|
|
1
|
-
import { AdvancedNotifierAddon,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
//#
|
|
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.
|
|
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
|
-
"
|
|
56
|
-
"
|
|
55
|
+
"typescript": "~6.0.3",
|
|
56
|
+
"vite": "^8.0.11",
|
|
57
57
|
"vitest": "^3.0.0"
|
|
58
58
|
}
|
|
59
59
|
}
|