@serve.zone/dcrouter 11.0.27 → 11.0.29

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.
Files changed (55) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/dist_ts/config/classes.route-config-manager.js +231 -0
  3. package/dist_ts/config/validator.d.ts +104 -0
  4. package/dist_ts/config/validator.js +152 -0
  5. package/dist_ts/errors/base.errors.d.ts +224 -0
  6. package/dist_ts/errors/base.errors.js +320 -0
  7. package/dist_ts/errors/error.codes.d.ts +115 -0
  8. package/dist_ts/errors/error.codes.js +136 -0
  9. package/dist_ts/monitoring/classes.metricsmanager.d.ts +178 -0
  10. package/dist_ts/monitoring/classes.metricsmanager.js +642 -0
  11. package/dist_ts/monitoring/index.d.ts +1 -0
  12. package/dist_ts/monitoring/index.js +2 -0
  13. package/dist_ts/opsserver/classes.opsserver.d.ts +37 -0
  14. package/dist_ts/opsserver/classes.opsserver.js +85 -0
  15. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
  16. package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
  17. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +32 -0
  18. package/dist_ts/opsserver/handlers/certificate.handler.js +421 -0
  19. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
  20. package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
  21. package/dist_ts/opsserver/handlers/index.d.ts +11 -0
  22. package/dist_ts/opsserver/handlers/index.js +12 -0
  23. package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
  24. package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
  25. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
  26. package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
  27. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
  28. package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
  29. package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
  30. package/dist_ts/opsserver/handlers/security.handler.js +231 -0
  31. package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
  32. package/dist_ts/opsserver/handlers/stats.handler.js +399 -0
  33. package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
  34. package/dist_ts/opsserver/helpers/guards.js +43 -0
  35. package/dist_ts/opsserver/index.d.ts +1 -0
  36. package/dist_ts/opsserver/index.js +2 -0
  37. package/dist_ts/radius/classes.accounting.manager.d.ts +218 -0
  38. package/dist_ts/radius/classes.accounting.manager.js +417 -0
  39. package/dist_ts/radius/classes.radius.server.d.ts +171 -0
  40. package/dist_ts/radius/classes.radius.server.js +385 -0
  41. package/dist_ts/radius/classes.vlan.manager.d.ts +128 -0
  42. package/dist_ts/radius/classes.vlan.manager.js +279 -0
  43. package/dist_ts/radius/index.d.ts +13 -0
  44. package/dist_ts/radius/index.js +14 -0
  45. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +82 -0
  46. package/dist_ts/remoteingress/classes.remoteingress-manager.js +227 -0
  47. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
  48. package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
  49. package/dist_ts/remoteingress/index.d.ts +2 -0
  50. package/dist_ts/remoteingress/index.js +3 -0
  51. package/dist_ts/security/classes.securitylogger.d.ts +144 -0
  52. package/dist_ts_web/00_commitinfo_data.js +1 -1
  53. package/package.json +2 -2
  54. package/ts/00_commitinfo_data.ts +1 -1
  55. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,227 @@
1
+ import * as plugins from '../plugins.js';
2
+ const STORAGE_PREFIX = '/remote-ingress/';
3
+ /**
4
+ * Flatten a port range (number | number[] | Array<{from, to}>) to a sorted unique number array.
5
+ */
6
+ function extractPorts(portRange) {
7
+ const ports = new Set();
8
+ if (typeof portRange === 'number') {
9
+ ports.add(portRange);
10
+ }
11
+ else if (Array.isArray(portRange)) {
12
+ for (const entry of portRange) {
13
+ if (typeof entry === 'number') {
14
+ ports.add(entry);
15
+ }
16
+ else if (typeof entry === 'object' && 'from' in entry && 'to' in entry) {
17
+ for (let p = entry.from; p <= entry.to; p++) {
18
+ ports.add(p);
19
+ }
20
+ }
21
+ }
22
+ }
23
+ return [...ports].sort((a, b) => a - b);
24
+ }
25
+ /**
26
+ * Manages CRUD for remote ingress edge registrations.
27
+ * Persists edge configs via StorageManager and provides
28
+ * the allowed edges list for the Rust hub.
29
+ */
30
+ export class RemoteIngressManager {
31
+ storageManager;
32
+ edges = new Map();
33
+ routes = [];
34
+ constructor(storageManager) {
35
+ this.storageManager = storageManager;
36
+ }
37
+ /**
38
+ * Load all edge registrations from storage into memory.
39
+ */
40
+ async initialize() {
41
+ const keys = await this.storageManager.list(STORAGE_PREFIX);
42
+ for (const key of keys) {
43
+ const edge = await this.storageManager.getJSON(key);
44
+ if (edge) {
45
+ // Migration: old edges without autoDerivePorts default to true
46
+ if (edge.autoDerivePorts === undefined) {
47
+ edge.autoDerivePorts = true;
48
+ await this.storageManager.setJSON(key, edge);
49
+ }
50
+ this.edges.set(edge.id, edge);
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Store the current route configs for port derivation.
56
+ */
57
+ setRoutes(routes) {
58
+ this.routes = routes;
59
+ }
60
+ /**
61
+ * Derive listen ports for an edge from routes tagged with remoteIngress.enabled.
62
+ * When a route specifies edgeFilter, only edges whose id or tags match get that route's ports.
63
+ * When edgeFilter is absent, the route applies to all edges.
64
+ */
65
+ derivePortsForEdge(edgeId, edgeTags) {
66
+ const ports = new Set();
67
+ for (const route of this.routes) {
68
+ if (!route.remoteIngress?.enabled)
69
+ continue;
70
+ // Apply edge filter if present
71
+ const filter = route.remoteIngress.edgeFilter;
72
+ if (filter && filter.length > 0) {
73
+ const idMatch = filter.includes(edgeId);
74
+ const tagMatch = edgeTags?.some((tag) => filter.includes(tag)) ?? false;
75
+ if (!idMatch && !tagMatch)
76
+ continue;
77
+ }
78
+ // Extract ports from the route match
79
+ if (route.match?.ports) {
80
+ for (const p of extractPorts(route.match.ports)) {
81
+ ports.add(p);
82
+ }
83
+ }
84
+ }
85
+ return [...ports].sort((a, b) => a - b);
86
+ }
87
+ /**
88
+ * Get the effective listen ports for an edge.
89
+ * Manual ports are always included. Auto-derived ports are added (union) when autoDerivePorts is true.
90
+ */
91
+ getEffectiveListenPorts(edge) {
92
+ const manualPorts = edge.listenPorts || [];
93
+ const shouldDerive = edge.autoDerivePorts !== false;
94
+ if (!shouldDerive)
95
+ return [...manualPorts].sort((a, b) => a - b);
96
+ const derivedPorts = this.derivePortsForEdge(edge.id, edge.tags);
97
+ return [...new Set([...manualPorts, ...derivedPorts])].sort((a, b) => a - b);
98
+ }
99
+ /**
100
+ * Get manual and derived port breakdown for an edge (used in API responses).
101
+ * Derived ports exclude any ports already present in the manual list.
102
+ */
103
+ getPortBreakdown(edge) {
104
+ const manual = edge.listenPorts || [];
105
+ const shouldDerive = edge.autoDerivePorts !== false;
106
+ if (!shouldDerive)
107
+ return { manual, derived: [] };
108
+ const manualSet = new Set(manual);
109
+ const allDerived = this.derivePortsForEdge(edge.id, edge.tags);
110
+ const derived = allDerived.filter((p) => !manualSet.has(p));
111
+ return { manual, derived };
112
+ }
113
+ /**
114
+ * Create a new edge registration.
115
+ */
116
+ async createEdge(name, listenPorts = [], tags, autoDerivePorts = true) {
117
+ const id = plugins.uuid.v4();
118
+ const secret = plugins.crypto.randomBytes(32).toString('hex');
119
+ const now = Date.now();
120
+ const edge = {
121
+ id,
122
+ name,
123
+ secret,
124
+ listenPorts,
125
+ enabled: true,
126
+ autoDerivePorts,
127
+ tags: tags || [],
128
+ createdAt: now,
129
+ updatedAt: now,
130
+ };
131
+ await this.storageManager.setJSON(`${STORAGE_PREFIX}${id}`, edge);
132
+ this.edges.set(id, edge);
133
+ return edge;
134
+ }
135
+ /**
136
+ * Get an edge by ID.
137
+ */
138
+ getEdge(id) {
139
+ return this.edges.get(id);
140
+ }
141
+ /**
142
+ * Get all edge registrations.
143
+ */
144
+ getAllEdges() {
145
+ return Array.from(this.edges.values());
146
+ }
147
+ /**
148
+ * Update an edge registration.
149
+ */
150
+ async updateEdge(id, updates) {
151
+ const edge = this.edges.get(id);
152
+ if (!edge) {
153
+ return null;
154
+ }
155
+ if (updates.name !== undefined)
156
+ edge.name = updates.name;
157
+ if (updates.listenPorts !== undefined)
158
+ edge.listenPorts = updates.listenPorts;
159
+ if (updates.autoDerivePorts !== undefined)
160
+ edge.autoDerivePorts = updates.autoDerivePorts;
161
+ if (updates.enabled !== undefined)
162
+ edge.enabled = updates.enabled;
163
+ if (updates.tags !== undefined)
164
+ edge.tags = updates.tags;
165
+ edge.updatedAt = Date.now();
166
+ await this.storageManager.setJSON(`${STORAGE_PREFIX}${id}`, edge);
167
+ this.edges.set(id, edge);
168
+ return edge;
169
+ }
170
+ /**
171
+ * Delete an edge registration.
172
+ */
173
+ async deleteEdge(id) {
174
+ if (!this.edges.has(id)) {
175
+ return false;
176
+ }
177
+ await this.storageManager.delete(`${STORAGE_PREFIX}${id}`);
178
+ this.edges.delete(id);
179
+ return true;
180
+ }
181
+ /**
182
+ * Regenerate the secret for an edge.
183
+ */
184
+ async regenerateSecret(id) {
185
+ const edge = this.edges.get(id);
186
+ if (!edge) {
187
+ return null;
188
+ }
189
+ edge.secret = plugins.crypto.randomBytes(32).toString('hex');
190
+ edge.updatedAt = Date.now();
191
+ await this.storageManager.setJSON(`${STORAGE_PREFIX}${id}`, edge);
192
+ this.edges.set(id, edge);
193
+ return edge.secret;
194
+ }
195
+ /**
196
+ * Verify an edge's secret using constant-time comparison.
197
+ */
198
+ verifySecret(id, secret) {
199
+ const edge = this.edges.get(id);
200
+ if (!edge) {
201
+ return false;
202
+ }
203
+ const expected = Buffer.from(edge.secret);
204
+ const provided = Buffer.from(secret);
205
+ if (expected.length !== provided.length) {
206
+ return false;
207
+ }
208
+ return plugins.crypto.timingSafeEqual(expected, provided);
209
+ }
210
+ /**
211
+ * Get the list of allowed edges (enabled only) for the Rust hub.
212
+ */
213
+ getAllowedEdges() {
214
+ const result = [];
215
+ for (const edge of this.edges.values()) {
216
+ if (edge.enabled) {
217
+ result.push({
218
+ id: edge.id,
219
+ secret: edge.secret,
220
+ listenPorts: this.getEffectiveListenPorts(edge),
221
+ });
222
+ }
223
+ }
224
+ return result;
225
+ }
226
+ }
227
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yZW1vdGVpbmdyZXNzLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9yZW1vdGVpbmdyZXNzL2NsYXNzZXMucmVtb3RlaW5ncmVzcy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBSXpDLE1BQU0sY0FBYyxHQUFHLGtCQUFrQixDQUFDO0FBRTFDOztHQUVHO0FBQ0gsU0FBUyxZQUFZLENBQUMsU0FBa0U7SUFDdEYsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUNoQyxJQUFJLE9BQU8sU0FBUyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ2xDLEtBQUssQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkIsQ0FBQztTQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ3BDLEtBQUssTUFBTSxLQUFLLElBQUksU0FBUyxFQUFFLENBQUM7WUFDOUIsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDOUIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNuQixDQUFDO2lCQUFNLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLE1BQU0sSUFBSSxLQUFLLElBQUksSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUN6RSxLQUFLLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztvQkFDNUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDZixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQzFDLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLG9CQUFvQjtJQUN2QixjQUFjLENBQWlCO0lBQy9CLEtBQUssR0FBZ0MsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUMvQyxNQUFNLEdBQTJCLEVBQUUsQ0FBQztJQUU1QyxZQUFZLGNBQThCO1FBQ3hDLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVO1FBQ3JCLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDNUQsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFpQixHQUFHLENBQUMsQ0FBQztZQUNwRSxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNULCtEQUErRDtnQkFDL0QsSUFBSyxJQUFZLENBQUMsZUFBZSxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUNoRCxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQztvQkFDNUIsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQy9DLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNoQyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVMsQ0FBQyxNQUE4QjtRQUM3QyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLGtCQUFrQixDQUFDLE1BQWMsRUFBRSxRQUFtQjtRQUMzRCxNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBRWhDLEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hDLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLE9BQU87Z0JBQUUsU0FBUztZQUU1QywrQkFBK0I7WUFDL0IsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUM7WUFDOUMsSUFBSSxNQUFNLElBQUksTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDaEMsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDeEMsTUFBTSxRQUFRLEdBQUcsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQztnQkFDeEUsSUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFDLFFBQVE7b0JBQUUsU0FBUztZQUN0QyxDQUFDO1lBRUQscUNBQXFDO1lBQ3JDLElBQUksS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQztnQkFDdkIsS0FBSyxNQUFNLENBQUMsSUFBSSxZQUFZLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUNoRCxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNmLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksdUJBQXVCLENBQUMsSUFBb0I7UUFDakQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFdBQVcsSUFBSSxFQUFFLENBQUM7UUFDM0MsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGVBQWUsS0FBSyxLQUFLLENBQUM7UUFDcEQsSUFBSSxDQUFDLFlBQVk7WUFBRSxPQUFPLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDakUsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2pFLE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxXQUFXLEVBQUUsR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFFRDs7O09BR0c7SUFDSSxnQkFBZ0IsQ0FBQyxJQUFvQjtRQUMxQyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztRQUN0QyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsZUFBZSxLQUFLLEtBQUssQ0FBQztRQUNwRCxJQUFJLENBQUMsWUFBWTtZQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ2xELE1BQU0sU0FBUyxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2xDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMvRCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM1RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQ3JCLElBQVksRUFDWixjQUF3QixFQUFFLEVBQzFCLElBQWUsRUFDZixrQkFBMkIsSUFBSTtRQUUvQixNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzdCLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5RCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFdkIsTUFBTSxJQUFJLEdBQW1CO1lBQzNCLEVBQUU7WUFDRixJQUFJO1lBQ0osTUFBTTtZQUNOLFdBQVc7WUFDWCxPQUFPLEVBQUUsSUFBSTtZQUNiLGVBQWU7WUFDZixJQUFJLEVBQUUsSUFBSSxJQUFJLEVBQUU7WUFDaEIsU0FBUyxFQUFFLEdBQUc7WUFDZCxTQUFTLEVBQUUsR0FBRztTQUNmLENBQUM7UUFFRixNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLEdBQUcsY0FBYyxHQUFHLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ2xFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUN6QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNJLE9BQU8sQ0FBQyxFQUFVO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksV0FBVztRQUNoQixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQ3JCLEVBQVUsRUFDVixPQU1DO1FBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1YsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFNBQVM7WUFBRSxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFDekQsSUFBSSxPQUFPLENBQUMsV0FBVyxLQUFLLFNBQVM7WUFBRSxJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUM7UUFDOUUsSUFBSSxPQUFPLENBQUMsZUFBZSxLQUFLLFNBQVM7WUFBRSxJQUFJLENBQUMsZUFBZSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUM7UUFDMUYsSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLFNBQVM7WUFBRSxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFDbEUsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFNBQVM7WUFBRSxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFDekQsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFNUIsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxHQUFHLGNBQWMsR0FBRyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDekIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsVUFBVSxDQUFDLEVBQVU7UUFDaEMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDeEIsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBQ0QsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxHQUFHLGNBQWMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3RCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLGdCQUFnQixDQUFDLEVBQVU7UUFDdEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1YsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0QsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFNUIsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxHQUFHLGNBQWMsR0FBRyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDekIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7T0FFRztJQUNJLFlBQVksQ0FBQyxFQUFVLEVBQUUsTUFBYztRQUM1QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDVixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMxQyxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JDLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDeEMsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVEOztPQUVHO0lBQ0ksZUFBZTtRQUNwQixNQUFNLE1BQU0sR0FBaUUsRUFBRSxDQUFDO1FBQ2hGLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3ZDLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNqQixNQUFNLENBQUMsSUFBSSxDQUFDO29CQUNWLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDWCxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07b0JBQ25CLFdBQVcsRUFBRSxJQUFJLENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDO2lCQUNoRCxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7Q0FDRiJ9
@@ -0,0 +1,59 @@
1
+ import type { IRemoteIngressStatus } from '../../dist_ts_interfaces/data/remoteingress.js';
2
+ import type { RemoteIngressManager } from './classes.remoteingress-manager.js';
3
+ export interface ITunnelManagerConfig {
4
+ tunnelPort?: number;
5
+ targetHost?: string;
6
+ tls?: {
7
+ certPem?: string;
8
+ keyPem?: string;
9
+ };
10
+ }
11
+ /**
12
+ * Manages the RemoteIngressHub instance and tracks connected edge statuses.
13
+ */
14
+ export declare class TunnelManager {
15
+ private hub;
16
+ private manager;
17
+ private config;
18
+ private edgeStatuses;
19
+ private reconcileInterval;
20
+ constructor(manager: RemoteIngressManager, config?: ITunnelManagerConfig);
21
+ /**
22
+ * Start the tunnel hub and load allowed edges.
23
+ */
24
+ start(): Promise<void>;
25
+ /**
26
+ * Stop the tunnel hub.
27
+ */
28
+ stop(): Promise<void>;
29
+ /**
30
+ * Reconcile TS-side edge statuses with the authoritative Rust hub status.
31
+ * Overwrites event-derived activeTunnels with the real activeStreams count.
32
+ */
33
+ private reconcile;
34
+ /**
35
+ * Sync allowed edges from the manager to the hub.
36
+ * Call this after creating/deleting/updating edges.
37
+ */
38
+ syncAllowedEdges(): Promise<void>;
39
+ /**
40
+ * Get runtime statuses for all known edges.
41
+ */
42
+ getEdgeStatuses(): IRemoteIngressStatus[];
43
+ /**
44
+ * Get status for a specific edge.
45
+ */
46
+ getEdgeStatus(edgeId: string): IRemoteIngressStatus | undefined;
47
+ /**
48
+ * Get the count of connected edges.
49
+ */
50
+ getConnectedCount(): number;
51
+ /**
52
+ * Get the public IPs of all connected edges.
53
+ */
54
+ getConnectedEdgeIps(): string[];
55
+ /**
56
+ * Get the total number of active tunnels across all edges.
57
+ */
58
+ getTotalActiveTunnels(): number;
59
+ }
@@ -0,0 +1,165 @@
1
+ import * as plugins from '../plugins.js';
2
+ /**
3
+ * Manages the RemoteIngressHub instance and tracks connected edge statuses.
4
+ */
5
+ export class TunnelManager {
6
+ hub;
7
+ manager;
8
+ config;
9
+ edgeStatuses = new Map();
10
+ reconcileInterval = null;
11
+ constructor(manager, config = {}) {
12
+ this.manager = manager;
13
+ this.config = config;
14
+ this.hub = new plugins.remoteingress.RemoteIngressHub();
15
+ // Listen for edge connect/disconnect events
16
+ this.hub.on('edgeConnected', (data) => {
17
+ this.edgeStatuses.set(data.edgeId, {
18
+ edgeId: data.edgeId,
19
+ connected: true,
20
+ publicIp: data.peerAddr || null,
21
+ activeTunnels: 0,
22
+ lastHeartbeat: Date.now(),
23
+ connectedAt: Date.now(),
24
+ });
25
+ });
26
+ this.hub.on('edgeDisconnected', (data) => {
27
+ this.edgeStatuses.delete(data.edgeId);
28
+ });
29
+ this.hub.on('streamOpened', (data) => {
30
+ const existing = this.edgeStatuses.get(data.edgeId);
31
+ if (existing) {
32
+ existing.activeTunnels++;
33
+ existing.lastHeartbeat = Date.now();
34
+ }
35
+ });
36
+ this.hub.on('streamClosed', (data) => {
37
+ const existing = this.edgeStatuses.get(data.edgeId);
38
+ if (existing && existing.activeTunnels > 0) {
39
+ existing.activeTunnels--;
40
+ }
41
+ });
42
+ }
43
+ /**
44
+ * Start the tunnel hub and load allowed edges.
45
+ */
46
+ async start() {
47
+ await this.hub.start({
48
+ tunnelPort: this.config.tunnelPort ?? 8443,
49
+ targetHost: this.config.targetHost ?? '127.0.0.1',
50
+ tls: this.config.tls,
51
+ });
52
+ // Send allowed edges to the hub
53
+ await this.syncAllowedEdges();
54
+ // Periodically reconcile with authoritative Rust hub status
55
+ this.reconcileInterval = setInterval(() => {
56
+ this.reconcile().catch(() => { });
57
+ }, 15_000);
58
+ }
59
+ /**
60
+ * Stop the tunnel hub.
61
+ */
62
+ async stop() {
63
+ if (this.reconcileInterval) {
64
+ clearInterval(this.reconcileInterval);
65
+ this.reconcileInterval = null;
66
+ }
67
+ // Remove event listeners before stopping to prevent leaks
68
+ this.hub.removeAllListeners();
69
+ await this.hub.stop();
70
+ this.edgeStatuses.clear();
71
+ }
72
+ /**
73
+ * Reconcile TS-side edge statuses with the authoritative Rust hub status.
74
+ * Overwrites event-derived activeTunnels with the real activeStreams count.
75
+ */
76
+ async reconcile() {
77
+ const hubStatus = await this.hub.getStatus();
78
+ if (!hubStatus || !hubStatus.connectedEdges)
79
+ return;
80
+ const rustEdgeIds = new Set();
81
+ for (const rustEdge of hubStatus.connectedEdges) {
82
+ rustEdgeIds.add(rustEdge.edgeId);
83
+ const existing = this.edgeStatuses.get(rustEdge.edgeId);
84
+ if (existing) {
85
+ existing.activeTunnels = rustEdge.activeStreams;
86
+ existing.lastHeartbeat = Date.now();
87
+ // Update peer address if available from Rust hub
88
+ if (rustEdge.peerAddr) {
89
+ existing.publicIp = rustEdge.peerAddr;
90
+ }
91
+ }
92
+ else {
93
+ // Missed edgeConnected event — add entry
94
+ this.edgeStatuses.set(rustEdge.edgeId, {
95
+ edgeId: rustEdge.edgeId,
96
+ connected: true,
97
+ publicIp: rustEdge.peerAddr || null,
98
+ activeTunnels: rustEdge.activeStreams,
99
+ lastHeartbeat: Date.now(),
100
+ connectedAt: rustEdge.connectedAt * 1000,
101
+ });
102
+ }
103
+ }
104
+ // Remove entries for edges no longer connected in Rust (missed edgeDisconnected)
105
+ for (const edgeId of this.edgeStatuses.keys()) {
106
+ if (!rustEdgeIds.has(edgeId)) {
107
+ this.edgeStatuses.delete(edgeId);
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Sync allowed edges from the manager to the hub.
113
+ * Call this after creating/deleting/updating edges.
114
+ */
115
+ async syncAllowedEdges() {
116
+ const edges = this.manager.getAllowedEdges();
117
+ await this.hub.updateAllowedEdges(edges);
118
+ }
119
+ /**
120
+ * Get runtime statuses for all known edges.
121
+ */
122
+ getEdgeStatuses() {
123
+ return Array.from(this.edgeStatuses.values());
124
+ }
125
+ /**
126
+ * Get status for a specific edge.
127
+ */
128
+ getEdgeStatus(edgeId) {
129
+ return this.edgeStatuses.get(edgeId);
130
+ }
131
+ /**
132
+ * Get the count of connected edges.
133
+ */
134
+ getConnectedCount() {
135
+ let count = 0;
136
+ for (const status of this.edgeStatuses.values()) {
137
+ if (status.connected)
138
+ count++;
139
+ }
140
+ return count;
141
+ }
142
+ /**
143
+ * Get the public IPs of all connected edges.
144
+ */
145
+ getConnectedEdgeIps() {
146
+ const ips = [];
147
+ for (const status of this.edgeStatuses.values()) {
148
+ if (status.connected && status.publicIp) {
149
+ ips.push(status.publicIp);
150
+ }
151
+ }
152
+ return ips;
153
+ }
154
+ /**
155
+ * Get the total number of active tunnels across all edges.
156
+ */
157
+ getTotalActiveTunnels() {
158
+ let total = 0;
159
+ for (const status of this.edgeStatuses.values()) {
160
+ total += status.activeTunnels;
161
+ }
162
+ return total;
163
+ }
164
+ }
165
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50dW5uZWwtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3JlbW90ZWluZ3Jlc3MvY2xhc3Nlcy50dW5uZWwtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQWF6Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxhQUFhO0lBQ2hCLEdBQUcsQ0FBOEQ7SUFDakUsT0FBTyxDQUF1QjtJQUM5QixNQUFNLENBQXVCO0lBQzdCLFlBQVksR0FBc0MsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUM1RCxpQkFBaUIsR0FBMEMsSUFBSSxDQUFDO0lBRXhFLFlBQVksT0FBNkIsRUFBRSxTQUErQixFQUFFO1FBQzFFLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxPQUFPLENBQUMsYUFBYSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEQsNENBQTRDO1FBQzVDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLGVBQWUsRUFBRSxDQUFDLElBQTBDLEVBQUUsRUFBRTtZQUMxRSxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO2dCQUNqQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07Z0JBQ25CLFNBQVMsRUFBRSxJQUFJO2dCQUNmLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUk7Z0JBQy9CLGFBQWEsRUFBRSxDQUFDO2dCQUNoQixhQUFhLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtnQkFDekIsV0FBVyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7YUFDeEIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsR0FBRyxDQUFDLEVB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
@@ -0,0 +1,2 @@
1
+ export * from './classes.remoteingress-manager.js';
2
+ export * from './classes.tunnel-manager.js';
@@ -0,0 +1,3 @@
1
+ export * from './classes.remoteingress-manager.js';
2
+ export * from './classes.tunnel-manager.js';
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9yZW1vdGVpbmdyZXNzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0NBQW9DLENBQUM7QUFDbkQsY0FBYyw2QkFBNkIsQ0FBQyJ9
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Log level for security events
3
+ */
4
+ export declare enum SecurityLogLevel {
5
+ INFO = "info",
6
+ WARN = "warn",
7
+ ERROR = "error",
8
+ CRITICAL = "critical"
9
+ }
10
+ /**
11
+ * Security event types for categorization
12
+ */
13
+ export declare enum SecurityEventType {
14
+ AUTHENTICATION = "authentication",
15
+ ACCESS_CONTROL = "access_control",
16
+ EMAIL_VALIDATION = "email_validation",
17
+ EMAIL_PROCESSING = "email_processing",
18
+ EMAIL_FORWARDING = "email_forwarding",
19
+ EMAIL_DELIVERY = "email_delivery",
20
+ DKIM = "dkim",
21
+ SPF = "spf",
22
+ DMARC = "dmarc",
23
+ RATE_LIMIT = "rate_limit",
24
+ RATE_LIMITING = "rate_limiting",
25
+ SPAM = "spam",
26
+ MALWARE = "malware",
27
+ CONNECTION = "connection",
28
+ DATA_EXPOSURE = "data_exposure",
29
+ CONFIGURATION = "configuration",
30
+ IP_REPUTATION = "ip_reputation",
31
+ REJECTED_CONNECTION = "rejected_connection"
32
+ }
33
+ /**
34
+ * Security event interface
35
+ */
36
+ export interface ISecurityEvent {
37
+ timestamp: number;
38
+ level: SecurityLogLevel;
39
+ type: SecurityEventType;
40
+ message: string;
41
+ details?: any;
42
+ ipAddress?: string;
43
+ userId?: string;
44
+ sessionId?: string;
45
+ emailId?: string;
46
+ domain?: string;
47
+ action?: string;
48
+ result?: string;
49
+ success?: boolean;
50
+ }
51
+ /**
52
+ * Security logger for enhanced security monitoring
53
+ */
54
+ export declare class SecurityLogger {
55
+ private static instance;
56
+ private securityEvents;
57
+ private maxEventHistory;
58
+ private enableNotifications;
59
+ private constructor();
60
+ /**
61
+ * Get singleton instance
62
+ */
63
+ static getInstance(options?: {
64
+ maxEventHistory?: number;
65
+ enableNotifications?: boolean;
66
+ }): SecurityLogger;
67
+ /**
68
+ * Reset the singleton instance (for shutdown/testing)
69
+ */
70
+ static resetInstance(): void;
71
+ /**
72
+ * Log a security event
73
+ * @param event The security event to log
74
+ */
75
+ logEvent(event: Omit<ISecurityEvent, 'timestamp'>): void;
76
+ /**
77
+ * Get recent security events
78
+ * @param limit Maximum number of events to return
79
+ * @param filter Filter for specific event types
80
+ * @returns Recent security events
81
+ */
82
+ getRecentEvents(limit?: number, filter?: {
83
+ level?: SecurityLogLevel;
84
+ type?: SecurityEventType;
85
+ fromTimestamp?: number;
86
+ toTimestamp?: number;
87
+ }): ISecurityEvent[];
88
+ /**
89
+ * Get events by security level
90
+ * @param level The security level to filter by
91
+ * @param limit Maximum number of events to return
92
+ * @returns Security events matching the level
93
+ */
94
+ getEventsByLevel(level: SecurityLogLevel, limit?: number): ISecurityEvent[];
95
+ /**
96
+ * Get events by security type
97
+ * @param type The event type to filter by
98
+ * @param limit Maximum number of events to return
99
+ * @returns Security events matching the type
100
+ */
101
+ getEventsByType(type: SecurityEventType, limit?: number): ISecurityEvent[];
102
+ /**
103
+ * Get security events for a specific IP address
104
+ * @param ipAddress The IP address to filter by
105
+ * @param limit Maximum number of events to return
106
+ * @returns Security events for the IP address
107
+ */
108
+ getEventsByIP(ipAddress: string, limit?: number): ISecurityEvent[];
109
+ /**
110
+ * Get security events for a specific domain
111
+ * @param domain The domain to filter by
112
+ * @param limit Maximum number of events to return
113
+ * @returns Security events for the domain
114
+ */
115
+ getEventsByDomain(domain: string, limit?: number): ISecurityEvent[];
116
+ /**
117
+ * Send a notification for critical security events
118
+ * @param event The security event to notify about
119
+ * @private
120
+ */
121
+ private sendNotification;
122
+ /**
123
+ * Clear event history
124
+ */
125
+ clearEvents(): void;
126
+ /**
127
+ * Get statistical summary of security events
128
+ * @param timeWindow Optional time window in milliseconds
129
+ * @returns Summary of security events
130
+ */
131
+ getEventsSummary(timeWindow?: number): {
132
+ total: number;
133
+ byLevel: Record<SecurityLogLevel, number>;
134
+ byType: Record<SecurityEventType, number>;
135
+ topIPs: Array<{
136
+ ip: string;
137
+ count: number;
138
+ }>;
139
+ topDomains: Array<{
140
+ domain: string;
141
+ count: number;
142
+ }>;
143
+ };
144
+ }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '11.0.27',
6
+ version: '11.0.29',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsc0JBQXNCO0lBQzVCLE9BQU8sRUFBRSxTQUFTO0lBQ2xCLFdBQVcsRUFBRSwwRUFBMEU7Q0FDeEYsQ0FBQSJ9
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@serve.zone/dcrouter",
3
3
  "private": false,
4
- "version": "11.0.27",
4
+ "version": "11.0.29",
5
5
  "description": "A multifaceted routing service handling mail and SMS delivery functions.",
6
6
  "type": "module",
7
7
  "exports": {
@@ -19,7 +19,7 @@
19
19
  "watch": "tswatch"
20
20
  },
21
21
  "devDependencies": {
22
- "@git.zone/tsbuild": "^4.1.16",
22
+ "@git.zone/tsbuild": "^4.1.18",
23
23
  "@git.zone/tsbundle": "^2.9.0",
24
24
  "@git.zone/tsrun": "^2.0.1",
25
25
  "@git.zone/tstest": "^3.2.0",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '11.0.27',
6
+ version: '11.0.29',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '11.0.27',
6
+ version: '11.0.29',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }