@burdenoff/vibe-plugin-notify 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Webhook Delivery Service
3
+ *
4
+ * Handles sending webhooks with retry logic and delivery tracking.
5
+ */
6
+ import type { NotifyEvent, WebhookDelivery, StorageProvider, Logger, PluginConfig } from "../types.js";
7
+ import { WebhookManager } from "./webhook-manager.js";
8
+ export declare class WebhookDeliveryService {
9
+ private storage;
10
+ private logger;
11
+ private config;
12
+ private readonly DELIVERIES_KEY;
13
+ private readonly MAX_DELIVERIES;
14
+ private webhookManager;
15
+ constructor(storage: StorageProvider, logger: Logger, config: PluginConfig);
16
+ /**
17
+ * Generate delivery ID
18
+ */
19
+ private generateDeliveryId;
20
+ /**
21
+ * Process a notification event and deliver to matching webhooks
22
+ */
23
+ processEvent(event: NotifyEvent): Promise<void>;
24
+ /**
25
+ * Deliver event to a single webhook with retries
26
+ */
27
+ private deliverToWebhook;
28
+ /**
29
+ * Send HTTP request to webhook URL
30
+ */
31
+ private sendRequest;
32
+ /**
33
+ * Build webhook payload from event
34
+ */
35
+ private buildPayload;
36
+ /**
37
+ * Format payload for specific providers (Slack, Discord, etc.)
38
+ */
39
+ private formatPayloadForProvider;
40
+ /**
41
+ * Format message for Slack
42
+ */
43
+ private formatSlackMessage;
44
+ /**
45
+ * Format message for Discord
46
+ */
47
+ private formatDiscordMessage;
48
+ /**
49
+ * Send a test webhook
50
+ */
51
+ sendTestWebhook(webhookId: string): Promise<{
52
+ success: boolean;
53
+ statusCode?: number;
54
+ error?: string;
55
+ }>;
56
+ /**
57
+ * Save delivery record
58
+ */
59
+ private saveDelivery;
60
+ /**
61
+ * Get recent deliveries
62
+ */
63
+ getDeliveries(options?: {
64
+ webhookId?: string;
65
+ status?: WebhookDelivery["status"];
66
+ limit?: number;
67
+ }): Promise<WebhookDelivery[]>;
68
+ /**
69
+ * Get the webhook manager instance
70
+ */
71
+ getWebhookManager(): WebhookManager;
72
+ }
73
+ //# sourceMappingURL=webhook-delivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-delivery.d.ts","sourceRoot":"","sources":["../../src/services/webhook-delivery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,WAAW,EAGX,eAAe,EACf,eAAe,EACf,MAAM,EACN,YAAY,EACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,qBAAa,sBAAsB;IAM/B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IAPhB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAO;IACtC,OAAO,CAAC,cAAc,CAAiB;gBAG7B,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY;IAK9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCrD;;OAEG;YACW,gBAAgB;IAwE9B;;OAEG;YACW,WAAW;IAqBzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAyBhC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAoB5B;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAChD,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IAsCF;;OAEG;YACW,YAAY;IA0B1B;;OAEG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE;QAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;QACnC,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA4B9B;;OAEG;IACH,iBAAiB,IAAI,cAAc;CAGpC"}
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Webhook Delivery Service
3
+ *
4
+ * Handles sending webhooks with retry logic and delivery tracking.
5
+ */
6
+ import { STORAGE_NAMESPACE } from "../types.js";
7
+ import { WebhookManager } from "./webhook-manager.js";
8
+ export class WebhookDeliveryService {
9
+ storage;
10
+ logger;
11
+ config;
12
+ DELIVERIES_KEY = "deliveries";
13
+ MAX_DELIVERIES = 100; // Keep last 100 deliveries
14
+ webhookManager;
15
+ constructor(storage, logger, config) {
16
+ this.storage = storage;
17
+ this.logger = logger;
18
+ this.config = config;
19
+ this.webhookManager = new WebhookManager(storage, logger);
20
+ }
21
+ /**
22
+ * Generate delivery ID
23
+ */
24
+ generateDeliveryId() {
25
+ return `dlv_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
26
+ }
27
+ /**
28
+ * Process a notification event and deliver to matching webhooks
29
+ */
30
+ async processEvent(event) {
31
+ const webhooks = await this.webhookManager.getEnabledWebhooksForEvent(event.type);
32
+ if (webhooks.length === 0) {
33
+ this.logger.debug("notify", `No webhooks configured for event: ${event.type}`);
34
+ return;
35
+ }
36
+ this.logger.info("notify", `Delivering ${event.type} to ${webhooks.length} webhook(s)`);
37
+ // Deliver to all matching webhooks in parallel
38
+ const results = await Promise.allSettled(webhooks.map((webhook) => this.deliverToWebhook(webhook, event)));
39
+ // Log results
40
+ const succeeded = results.filter((r) => r.status === "fulfilled").length;
41
+ const failed = results.filter((r) => r.status === "rejected").length;
42
+ if (failed > 0) {
43
+ this.logger.warn("notify", `Webhook delivery: ${succeeded} succeeded, ${failed} failed`);
44
+ }
45
+ else {
46
+ this.logger.info("notify", `Webhook delivery: ${succeeded} succeeded`);
47
+ }
48
+ }
49
+ /**
50
+ * Deliver event to a single webhook with retries
51
+ */
52
+ async deliverToWebhook(webhook, event) {
53
+ const payload = this.buildPayload(event);
54
+ const delivery = {
55
+ id: this.generateDeliveryId(),
56
+ webhookId: webhook.id,
57
+ eventType: event.type,
58
+ payload: JSON.stringify(payload),
59
+ status: "pending",
60
+ attemptNumber: 0,
61
+ createdAt: new Date().toISOString(),
62
+ };
63
+ let lastError;
64
+ // Retry loop
65
+ for (let attempt = 1; attempt <= this.config.webhookRetryCount; attempt++) {
66
+ delivery.attemptNumber = attempt;
67
+ try {
68
+ const response = await this.sendRequest(webhook, payload);
69
+ if (response.ok) {
70
+ delivery.status = "delivered";
71
+ delivery.statusCode = response.status;
72
+ delivery.deliveredAt = new Date().toISOString();
73
+ this.logger.info("notify", `Webhook delivered: ${webhook.name} (${response.status})`);
74
+ await this.saveDelivery(delivery);
75
+ return delivery;
76
+ }
77
+ // Non-2xx response
78
+ lastError = `HTTP ${response.status}: ${response.statusText}`;
79
+ this.logger.warn("notify", `Webhook failed (attempt ${attempt}/${this.config.webhookRetryCount}): ${lastError}`);
80
+ }
81
+ catch (error) {
82
+ lastError = error instanceof Error ? error.message : String(error);
83
+ this.logger.warn("notify", `Webhook error (attempt ${attempt}/${this.config.webhookRetryCount}): ${lastError}`);
84
+ }
85
+ // Wait before retry (exponential backoff)
86
+ if (attempt < this.config.webhookRetryCount) {
87
+ const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
88
+ await new Promise((resolve) => setTimeout(resolve, delay));
89
+ }
90
+ }
91
+ // All retries failed
92
+ delivery.status = "failed";
93
+ delivery.error = lastError;
94
+ this.logger.error("notify", `Webhook abandoned after ${this.config.webhookRetryCount} attempts: ${webhook.name}`);
95
+ await this.saveDelivery(delivery);
96
+ return delivery;
97
+ }
98
+ /**
99
+ * Send HTTP request to webhook URL
100
+ */
101
+ async sendRequest(webhook, payload) {
102
+ const headers = {
103
+ "Content-Type": "application/json",
104
+ "User-Agent": "VibeControls-Notify/1.0",
105
+ ...webhook.headers,
106
+ };
107
+ // Detect webhook type and format accordingly
108
+ const body = this.formatPayloadForProvider(webhook.url, payload);
109
+ return fetch(webhook.url, {
110
+ method: "POST",
111
+ headers,
112
+ body: JSON.stringify(body),
113
+ signal: AbortSignal.timeout(this.config.webhookTimeoutMs),
114
+ });
115
+ }
116
+ /**
117
+ * Build webhook payload from event
118
+ */
119
+ buildPayload(event) {
120
+ return {
121
+ id: this.generateDeliveryId(),
122
+ timestamp: new Date().toISOString(),
123
+ event: {
124
+ type: event.type,
125
+ sessionId: event.properties?.sessionID,
126
+ sessionTitle: event.properties?.sessionTitle,
127
+ properties: event.properties || {},
128
+ },
129
+ source: {
130
+ agent: "vibecontrols-agent",
131
+ plugin: "notify",
132
+ version: "1.0.0",
133
+ tool: event.source || "unknown",
134
+ },
135
+ };
136
+ }
137
+ /**
138
+ * Format payload for specific providers (Slack, Discord, etc.)
139
+ */
140
+ formatPayloadForProvider(url, payload) {
141
+ const lowerUrl = url.toLowerCase();
142
+ // Slack webhook format
143
+ if (lowerUrl.includes("hooks.slack.com")) {
144
+ return {
145
+ text: this.formatSlackMessage(payload),
146
+ unfurl_links: false,
147
+ };
148
+ }
149
+ // Discord webhook format
150
+ if (lowerUrl.includes("discord.com/api/webhooks")) {
151
+ return {
152
+ content: this.formatDiscordMessage(payload),
153
+ };
154
+ }
155
+ // Generic webhook - send full payload
156
+ return payload;
157
+ }
158
+ /**
159
+ * Format message for Slack
160
+ */
161
+ formatSlackMessage(payload) {
162
+ const eventType = payload.event.type;
163
+ const title = payload.event.sessionTitle || "AI Task";
164
+ const tool = payload.source?.tool || "AI Tool";
165
+ if (eventType === "session.idle") {
166
+ return `:white_check_mark: *Task Completed* (${tool})\n>${title}`;
167
+ }
168
+ if (eventType === "session.error") {
169
+ return `:x: *Task Failed* (${tool})\n>${title}`;
170
+ }
171
+ if (eventType === "permission.asked") {
172
+ return `:bell: *Permission Required*\n${tool} needs your input`;
173
+ }
174
+ return `*${eventType}* (${tool})\n${title}`;
175
+ }
176
+ /**
177
+ * Format message for Discord
178
+ */
179
+ formatDiscordMessage(payload) {
180
+ const eventType = payload.event.type;
181
+ const title = payload.event.sessionTitle || "AI Task";
182
+ const tool = payload.source?.tool || "AI Tool";
183
+ if (eventType === "session.idle") {
184
+ return `**Task Completed** (${tool})\n> ${title}`;
185
+ }
186
+ if (eventType === "session.error") {
187
+ return `**Task Failed** (${tool})\n> ${title}`;
188
+ }
189
+ if (eventType === "permission.asked") {
190
+ return `**Permission Required**\n${tool} needs your input`;
191
+ }
192
+ return `**${eventType}** (${tool})\n${title}`;
193
+ }
194
+ /**
195
+ * Send a test webhook
196
+ */
197
+ async sendTestWebhook(webhookId) {
198
+ const webhook = await this.webhookManager.getWebhook(webhookId);
199
+ if (!webhook) {
200
+ return { success: false, error: "Webhook not found" };
201
+ }
202
+ const testPayload = {
203
+ id: this.generateDeliveryId(),
204
+ timestamp: new Date().toISOString(),
205
+ event: {
206
+ type: "test",
207
+ sessionId: "test-session",
208
+ sessionTitle: "Test notification from VibeControls",
209
+ properties: { test: true },
210
+ },
211
+ source: {
212
+ agent: "vibecontrols-agent",
213
+ plugin: "notify",
214
+ version: "1.0.0",
215
+ tool: "test",
216
+ },
217
+ };
218
+ try {
219
+ const response = await this.sendRequest(webhook, testPayload);
220
+ return {
221
+ success: response.ok,
222
+ statusCode: response.status,
223
+ error: response.ok ? undefined : `HTTP ${response.status}`,
224
+ };
225
+ }
226
+ catch (error) {
227
+ return {
228
+ success: false,
229
+ error: error instanceof Error ? error.message : String(error),
230
+ };
231
+ }
232
+ }
233
+ /**
234
+ * Save delivery record
235
+ */
236
+ async saveDelivery(delivery) {
237
+ try {
238
+ const data = await this.storage.get(STORAGE_NAMESPACE, this.DELIVERIES_KEY);
239
+ const deliveries = data ? JSON.parse(data) : [];
240
+ // Add new delivery at the beginning
241
+ deliveries.unshift(delivery);
242
+ // Keep only last N deliveries
243
+ const trimmed = deliveries.slice(0, this.MAX_DELIVERIES);
244
+ await this.storage.set(STORAGE_NAMESPACE, this.DELIVERIES_KEY, JSON.stringify(trimmed));
245
+ }
246
+ catch (error) {
247
+ this.logger.error("notify", "Failed to save delivery", {
248
+ error: String(error),
249
+ });
250
+ }
251
+ }
252
+ /**
253
+ * Get recent deliveries
254
+ */
255
+ async getDeliveries(options) {
256
+ try {
257
+ const data = await this.storage.get(STORAGE_NAMESPACE, this.DELIVERIES_KEY);
258
+ let deliveries = data ? JSON.parse(data) : [];
259
+ if (options?.webhookId) {
260
+ deliveries = deliveries.filter((d) => d.webhookId === options.webhookId);
261
+ }
262
+ if (options?.status) {
263
+ deliveries = deliveries.filter((d) => d.status === options.status);
264
+ }
265
+ if (options?.limit) {
266
+ deliveries = deliveries.slice(0, options.limit);
267
+ }
268
+ return deliveries;
269
+ }
270
+ catch {
271
+ return [];
272
+ }
273
+ }
274
+ /**
275
+ * Get the webhook manager instance
276
+ */
277
+ getWebhookManager() {
278
+ return this.webhookManager;
279
+ }
280
+ }
281
+ //# sourceMappingURL=webhook-delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-delivery.js","sourceRoot":"","sources":["../../src/services/webhook-delivery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Webhook Manager Service
3
+ *
4
+ * Handles CRUD operations for webhook endpoints.
5
+ * Stores webhooks in VibeControls storage provider.
6
+ */
7
+ import type { WebhookEndpoint, StorageProvider, Logger } from "../types.js";
8
+ export declare class WebhookManager {
9
+ private storage;
10
+ private logger;
11
+ private readonly WEBHOOKS_KEY;
12
+ constructor(storage: StorageProvider, logger: Logger);
13
+ /**
14
+ * Generate a unique webhook ID
15
+ */
16
+ private generateId;
17
+ /**
18
+ * Get all webhooks from storage
19
+ */
20
+ private getWebhooksFromStorage;
21
+ /**
22
+ * Save webhooks to storage
23
+ */
24
+ private saveWebhooksToStorage;
25
+ /**
26
+ * List all webhooks
27
+ */
28
+ listWebhooks(): Promise<WebhookEndpoint[]>;
29
+ /**
30
+ * Get a webhook by ID
31
+ */
32
+ getWebhook(id: string): Promise<WebhookEndpoint | null>;
33
+ /**
34
+ * Create a new webhook
35
+ */
36
+ createWebhook(input: {
37
+ url: string;
38
+ name?: string;
39
+ eventTypes?: string[];
40
+ headers?: Record<string, string>;
41
+ }): Promise<WebhookEndpoint>;
42
+ /**
43
+ * Update a webhook
44
+ */
45
+ updateWebhook(id: string, updates: Partial<Pick<WebhookEndpoint, "name" | "url" | "enabled" | "eventTypes" | "headers">>): Promise<WebhookEndpoint | null>;
46
+ /**
47
+ * Delete a webhook
48
+ */
49
+ deleteWebhook(id: string): Promise<boolean>;
50
+ /**
51
+ * Enable a webhook
52
+ */
53
+ enableWebhook(id: string): Promise<WebhookEndpoint | null>;
54
+ /**
55
+ * Disable a webhook
56
+ */
57
+ disableWebhook(id: string): Promise<WebhookEndpoint | null>;
58
+ /**
59
+ * Get enabled webhooks for a specific event type
60
+ */
61
+ getEnabledWebhooksForEvent(eventType: string): Promise<WebhookEndpoint[]>;
62
+ /**
63
+ * Extract a friendly name from URL
64
+ */
65
+ private extractNameFromUrl;
66
+ }
67
+ //# sourceMappingURL=webhook-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-manager.d.ts","sourceRoot":"","sources":["../../src/services/webhook-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG5E,qBAAa,cAAc;IAIvB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;gBAGjC,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM;IAGxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;YACW,sBAAsB;IAapC;;OAEG;YACW,qBAAqB;IAUnC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIhD;;OAEG;IACG,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAK7D;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE;QACzB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,GAAG,OAAO,CAAC,eAAe,CAAC;IAgC5B;;OAEG;IACG,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CACd,IAAI,CACF,eAAe,EACf,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CACtD,CACF,GACA,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAmBlC;;OAEG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAcjD;;OAEG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIhE;;OAEG;IACG,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIjE;;OAEG;IACG,0BAA0B,CAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,EAAE,CAAC;IAS7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAe3B"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Webhook Manager Service
3
+ *
4
+ * Handles CRUD operations for webhook endpoints.
5
+ * Stores webhooks in VibeControls storage provider.
6
+ */
7
+ import { STORAGE_NAMESPACE } from "../types.js";
8
+ export class WebhookManager {
9
+ storage;
10
+ logger;
11
+ WEBHOOKS_KEY = "webhooks";
12
+ constructor(storage, logger) {
13
+ this.storage = storage;
14
+ this.logger = logger;
15
+ }
16
+ /**
17
+ * Generate a unique webhook ID
18
+ */
19
+ generateId() {
20
+ return `wh_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
21
+ }
22
+ /**
23
+ * Get all webhooks from storage
24
+ */
25
+ async getWebhooksFromStorage() {
26
+ try {
27
+ const data = await this.storage.get(STORAGE_NAMESPACE, this.WEBHOOKS_KEY);
28
+ if (!data)
29
+ return [];
30
+ return JSON.parse(data);
31
+ }
32
+ catch (error) {
33
+ this.logger.error("notify", "Failed to read webhooks", {
34
+ error: String(error),
35
+ });
36
+ return [];
37
+ }
38
+ }
39
+ /**
40
+ * Save webhooks to storage
41
+ */
42
+ async saveWebhooksToStorage(webhooks) {
43
+ await this.storage.set(STORAGE_NAMESPACE, this.WEBHOOKS_KEY, JSON.stringify(webhooks));
44
+ }
45
+ /**
46
+ * List all webhooks
47
+ */
48
+ async listWebhooks() {
49
+ return this.getWebhooksFromStorage();
50
+ }
51
+ /**
52
+ * Get a webhook by ID
53
+ */
54
+ async getWebhook(id) {
55
+ const webhooks = await this.getWebhooksFromStorage();
56
+ return webhooks.find((w) => w.id === id) || null;
57
+ }
58
+ /**
59
+ * Create a new webhook
60
+ */
61
+ async createWebhook(input) {
62
+ const webhooks = await this.getWebhooksFromStorage();
63
+ // Check for duplicate URL
64
+ const existing = webhooks.find((w) => w.url === input.url);
65
+ if (existing) {
66
+ throw new Error(`Webhook with URL already exists: ${existing.id}`);
67
+ }
68
+ const now = new Date().toISOString();
69
+ const webhook = {
70
+ id: this.generateId(),
71
+ name: input.name || this.extractNameFromUrl(input.url),
72
+ url: input.url,
73
+ enabled: true,
74
+ eventTypes: input.eventTypes || ["session.idle"],
75
+ headers: input.headers,
76
+ createdAt: now,
77
+ updatedAt: now,
78
+ };
79
+ webhooks.push(webhook);
80
+ await this.saveWebhooksToStorage(webhooks);
81
+ this.logger.info("notify", `Webhook created: ${webhook.id}`, {
82
+ name: webhook.name,
83
+ url: webhook.url,
84
+ });
85
+ return webhook;
86
+ }
87
+ /**
88
+ * Update a webhook
89
+ */
90
+ async updateWebhook(id, updates) {
91
+ const webhooks = await this.getWebhooksFromStorage();
92
+ const index = webhooks.findIndex((w) => w.id === id);
93
+ if (index === -1)
94
+ return null;
95
+ webhooks[index] = {
96
+ ...webhooks[index],
97
+ ...updates,
98
+ updatedAt: new Date().toISOString(),
99
+ };
100
+ await this.saveWebhooksToStorage(webhooks);
101
+ this.logger.info("notify", `Webhook updated: ${id}`);
102
+ return webhooks[index];
103
+ }
104
+ /**
105
+ * Delete a webhook
106
+ */
107
+ async deleteWebhook(id) {
108
+ const webhooks = await this.getWebhooksFromStorage();
109
+ const index = webhooks.findIndex((w) => w.id === id);
110
+ if (index === -1)
111
+ return false;
112
+ webhooks.splice(index, 1);
113
+ await this.saveWebhooksToStorage(webhooks);
114
+ this.logger.info("notify", `Webhook deleted: ${id}`);
115
+ return true;
116
+ }
117
+ /**
118
+ * Enable a webhook
119
+ */
120
+ async enableWebhook(id) {
121
+ return this.updateWebhook(id, { enabled: true });
122
+ }
123
+ /**
124
+ * Disable a webhook
125
+ */
126
+ async disableWebhook(id) {
127
+ return this.updateWebhook(id, { enabled: false });
128
+ }
129
+ /**
130
+ * Get enabled webhooks for a specific event type
131
+ */
132
+ async getEnabledWebhooksForEvent(eventType) {
133
+ const webhooks = await this.getWebhooksFromStorage();
134
+ return webhooks.filter((w) => w.enabled &&
135
+ (w.eventTypes.includes(eventType) || w.eventTypes.includes("*")));
136
+ }
137
+ /**
138
+ * Extract a friendly name from URL
139
+ */
140
+ extractNameFromUrl(url) {
141
+ try {
142
+ const parsed = new URL(url);
143
+ const host = parsed.hostname;
144
+ if (host.includes("slack"))
145
+ return "Slack";
146
+ if (host.includes("discord"))
147
+ return "Discord";
148
+ if (host.includes("teams"))
149
+ return "Teams";
150
+ if (host.includes("telegram"))
151
+ return "Telegram";
152
+ return host.split(".")[0] || "Webhook";
153
+ }
154
+ catch {
155
+ return "Webhook";
156
+ }
157
+ }
158
+ }
159
+ //# sourceMappingURL=webhook-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-manager.js","sourceRoot":"","sources":["../../src/services/webhook-manager.ts"],"names":[],"mappings":"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"}