forge-remote 0.1.13 → 0.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.
@@ -0,0 +1,111 @@
1
+ // Forge Remote Relay — Webhook Config Watcher
2
+ // Copyright (c) 2025-2026 Iron Forge Apps
3
+ // Created by Daniel Wendel, CEO/Founder of Iron Forge Apps
4
+
5
+ import { getDb } from "./firebase.js";
6
+ import * as log from "./logger.js";
7
+
8
+ /**
9
+ * In-memory cache of webhook configurations.
10
+ * Map<webhookId, config>
11
+ */
12
+ const webhookConfigs = new Map();
13
+
14
+ /** Firestore unsubscribe function. */
15
+ let unsubscribe = null;
16
+
17
+ /**
18
+ * Watch Firestore for webhook config changes and maintain an in-memory cache.
19
+ *
20
+ * @param {string} desktopId
21
+ * @param {string} tunnelBaseUrl — Public tunnel URL to build webhook URLs from
22
+ */
23
+ export function watchWebhookConfigs(desktopId, tunnelBaseUrl) {
24
+ const db = getDb();
25
+ const webhooksRef = db
26
+ .collection("desktops")
27
+ .doc(desktopId)
28
+ .collection("webhooks");
29
+
30
+ unsubscribe = webhooksRef.onSnapshot(
31
+ (snap) => {
32
+ for (const change of snap.docChanges()) {
33
+ const id = change.doc.id;
34
+ const data = change.doc.data();
35
+
36
+ if (change.type === "removed") {
37
+ webhookConfigs.delete(id);
38
+ log.info(`Webhook removed: ${id}`);
39
+ continue;
40
+ }
41
+
42
+ // added or modified
43
+ webhookConfigs.set(id, data);
44
+
45
+ if (change.type === "added") {
46
+ log.info(
47
+ `Webhook registered: ${id} (source: ${data.source || "custom"}, enabled: ${data.enabled !== false})`,
48
+ );
49
+ } else {
50
+ log.info(`Webhook updated: ${id}`);
51
+ }
52
+
53
+ // If the webhook doc doesn't have a webhookUrl yet, write it back.
54
+ if (!data.webhookUrl) {
55
+ const webhookUrl = `${tunnelBaseUrl}/hooks/${id}`;
56
+ webhooksRef
57
+ .doc(id)
58
+ .update({ webhookUrl })
59
+ .then(() => {
60
+ log.info(`Wrote webhook URL for ${id}: ${webhookUrl}`);
61
+ })
62
+ .catch((err) => {
63
+ log.error(
64
+ `Failed to write webhook URL for ${id}: ${err.message}`,
65
+ );
66
+ });
67
+ }
68
+ }
69
+ },
70
+ (err) => {
71
+ log.error(`Webhook watcher error: ${err.message}`);
72
+ },
73
+ );
74
+
75
+ log.info(`Watching webhook configs for desktop ${desktopId}`);
76
+ }
77
+
78
+ /**
79
+ * Get a webhook config from the in-memory cache.
80
+ *
81
+ * @param {string} webhookId
82
+ * @returns {object|null}
83
+ */
84
+ export function getWebhookConfig(webhookId) {
85
+ return webhookConfigs.get(webhookId) || null;
86
+ }
87
+
88
+ /**
89
+ * Get the count of enabled webhooks.
90
+ *
91
+ * @returns {number}
92
+ */
93
+ export function getActiveWebhookCount() {
94
+ let count = 0;
95
+ for (const config of webhookConfigs.values()) {
96
+ if (config.enabled !== false) count++;
97
+ }
98
+ return count;
99
+ }
100
+
101
+ /**
102
+ * Stop watching Firestore for webhook changes.
103
+ */
104
+ export function stopWatching() {
105
+ if (unsubscribe) {
106
+ unsubscribe();
107
+ unsubscribe = null;
108
+ log.info("Stopped watching webhook configs");
109
+ }
110
+ webhookConfigs.clear();
111
+ }