@serve.zone/dcrouter 11.0.29 → 11.0.31
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_serve/bundle.js +1 -1
- package/dist_ts/monitoring/classes.metricscache.d.ts +32 -0
- package/dist_ts/monitoring/classes.metricscache.js +63 -0
- package/dist_ts/opsserver/handlers/logs.handler.d.ts +25 -0
- package/dist_ts/opsserver/handlers/logs.handler.js +256 -0
- package/dist_ts/security/classes.securitylogger.js +233 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
package/dist_serve/bundle.js
CHANGED
|
@@ -39328,4 +39328,4 @@ ibantools/jsnext/ibantools.js:
|
|
|
39328
39328
|
* @preferred
|
|
39329
39329
|
*)
|
|
39330
39330
|
*/
|
|
39331
|
-
//# sourceMappingURL=bundle-
|
|
39331
|
+
//# sourceMappingURL=bundle-1772722185785.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface ICacheEntry<T> {
|
|
2
|
+
data: T;
|
|
3
|
+
timestamp: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class MetricsCache {
|
|
6
|
+
private cache;
|
|
7
|
+
private readonly defaultTTL;
|
|
8
|
+
constructor(defaultTTL?: number);
|
|
9
|
+
/**
|
|
10
|
+
* Get cached data or compute and cache it
|
|
11
|
+
*/
|
|
12
|
+
get<T>(key: string, computeFn: () => T | Promise<T>, ttl?: number): T | Promise<T>;
|
|
13
|
+
/**
|
|
14
|
+
* Invalidate a specific cache entry
|
|
15
|
+
*/
|
|
16
|
+
invalidate(key: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Clear all cache entries
|
|
19
|
+
*/
|
|
20
|
+
clear(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get cache statistics
|
|
23
|
+
*/
|
|
24
|
+
getStats(): {
|
|
25
|
+
size: number;
|
|
26
|
+
keys: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Clean up expired entries
|
|
30
|
+
*/
|
|
31
|
+
cleanup(): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export class MetricsCache {
|
|
2
|
+
cache = new Map();
|
|
3
|
+
defaultTTL;
|
|
4
|
+
constructor(defaultTTL = 500) {
|
|
5
|
+
this.defaultTTL = defaultTTL;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Get cached data or compute and cache it
|
|
9
|
+
*/
|
|
10
|
+
get(key, computeFn, ttl) {
|
|
11
|
+
const cached = this.cache.get(key);
|
|
12
|
+
const now = Date.now();
|
|
13
|
+
const actualTTL = ttl ?? this.defaultTTL;
|
|
14
|
+
if (cached && (now - cached.timestamp) < actualTTL) {
|
|
15
|
+
return cached.data;
|
|
16
|
+
}
|
|
17
|
+
const result = computeFn();
|
|
18
|
+
// Handle both sync and async compute functions
|
|
19
|
+
if (result instanceof Promise) {
|
|
20
|
+
return result.then(data => {
|
|
21
|
+
this.cache.set(key, { data, timestamp: now });
|
|
22
|
+
return data;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.cache.set(key, { data: result, timestamp: now });
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Invalidate a specific cache entry
|
|
32
|
+
*/
|
|
33
|
+
invalidate(key) {
|
|
34
|
+
this.cache.delete(key);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Clear all cache entries
|
|
38
|
+
*/
|
|
39
|
+
clear() {
|
|
40
|
+
this.cache.clear();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get cache statistics
|
|
44
|
+
*/
|
|
45
|
+
getStats() {
|
|
46
|
+
return {
|
|
47
|
+
size: this.cache.size,
|
|
48
|
+
keys: Array.from(this.cache.keys())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clean up expired entries
|
|
53
|
+
*/
|
|
54
|
+
cleanup() {
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
57
|
+
if (now - entry.timestamp > this.defaultTTL) {
|
|
58
|
+
this.cache.delete(key);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tZXRyaWNzY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9tb25pdG9yaW5nL2NsYXNzZXMubWV0cmljc2NhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE1BQU0sT0FBTyxZQUFZO0lBQ2YsS0FBSyxHQUFHLElBQUksR0FBRyxFQUE0QixDQUFDO0lBQ25DLFVBQVUsQ0FBUztJQUVwQyxZQUFZLGFBQXFCLEdBQUc7UUFDbEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ksR0FBRyxDQUFJLEdBQVcsRUFBRSxTQUErQixFQUFFLEdBQVk7UUFDdEUsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sU0FBUyxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDO1FBRXpDLElBQUksTUFBTSxJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxTQUFTLEVBQUUsQ0FBQztZQUNuRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUM7UUFDckIsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDO1FBRTNCLCtDQUErQztRQUMvQyxJQUFJLE1BQU0sWUFBWSxPQUFPLEVBQUUsQ0FBQztZQUM5QixPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztnQkFDOUMsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUN0RCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksVUFBVSxDQUFDLEdBQVc7UUFDM0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSztRQUNWLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksUUFBUTtRQUNiLE9BQU87WUFDTCxJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJO1lBQ3JCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDcEMsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLE9BQU87UUFDWixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdkIsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNoRCxJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDNUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDekIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0NBQ0YifQ==
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OpsServer } from '../classes.opsserver.js';
|
|
2
|
+
export declare class LogsHandler {
|
|
3
|
+
private opsServerRef;
|
|
4
|
+
private activeStreamStops;
|
|
5
|
+
constructor(opsServerRef: OpsServer);
|
|
6
|
+
/**
|
|
7
|
+
* Clean up all active log streams and deactivate the push destination.
|
|
8
|
+
* Called when OpsServer stops.
|
|
9
|
+
*/
|
|
10
|
+
cleanup(): void;
|
|
11
|
+
private registerHandlers;
|
|
12
|
+
private static mapLogLevel;
|
|
13
|
+
private static deriveCategory;
|
|
14
|
+
private getRecentLogs;
|
|
15
|
+
/**
|
|
16
|
+
* Add a log destination to the base logger that pushes entries
|
|
17
|
+
* to all connected ops_dashboard TypedSocket clients.
|
|
18
|
+
*
|
|
19
|
+
* Uses a module-level singleton so the destination is added only once,
|
|
20
|
+
* even across OpsServer restart cycles. The destination reads
|
|
21
|
+
* `currentOpsServerRef` dynamically so it always uses the active server.
|
|
22
|
+
*/
|
|
23
|
+
private setupLogPushDestination;
|
|
24
|
+
private setupLogStream;
|
|
25
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
3
|
+
import { logBuffer, baseLogger } from '../../logger.js';
|
|
4
|
+
// Module-level singleton: the log push destination is added once and reuses
|
|
5
|
+
// the current OpsServer reference so it survives OpsServer restarts without
|
|
6
|
+
// accumulating duplicate destinations.
|
|
7
|
+
let logPushDestinationInstalled = false;
|
|
8
|
+
let currentOpsServerRef = null;
|
|
9
|
+
export class LogsHandler {
|
|
10
|
+
opsServerRef;
|
|
11
|
+
activeStreamStops = new Set();
|
|
12
|
+
constructor(opsServerRef) {
|
|
13
|
+
this.opsServerRef = opsServerRef;
|
|
14
|
+
this.registerHandlers();
|
|
15
|
+
this.setupLogPushDestination();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Clean up all active log streams and deactivate the push destination.
|
|
19
|
+
* Called when OpsServer stops.
|
|
20
|
+
*/
|
|
21
|
+
cleanup() {
|
|
22
|
+
// Stop all active follow-mode log streams
|
|
23
|
+
for (const stop of this.activeStreamStops) {
|
|
24
|
+
stop();
|
|
25
|
+
}
|
|
26
|
+
this.activeStreamStops.clear();
|
|
27
|
+
// Deactivate the push destination (it stays registered but becomes a no-op)
|
|
28
|
+
currentOpsServerRef = null;
|
|
29
|
+
}
|
|
30
|
+
registerHandlers() {
|
|
31
|
+
// All log endpoints register directly on viewRouter (valid identity required via middleware)
|
|
32
|
+
const router = this.opsServerRef.viewRouter;
|
|
33
|
+
// Get Recent Logs Handler
|
|
34
|
+
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getRecentLogs', async (dataArg, toolsArg) => {
|
|
35
|
+
const logs = await this.getRecentLogs(dataArg.level, dataArg.category, dataArg.limit || 100, dataArg.offset || 0, dataArg.search, dataArg.timeRange);
|
|
36
|
+
return {
|
|
37
|
+
logs,
|
|
38
|
+
total: logs.length,
|
|
39
|
+
hasMore: false,
|
|
40
|
+
};
|
|
41
|
+
}));
|
|
42
|
+
// Get Log Stream Handler
|
|
43
|
+
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getLogStream', async (dataArg, toolsArg) => {
|
|
44
|
+
// Create a virtual stream for log streaming
|
|
45
|
+
const virtualStream = new plugins.typedrequest.VirtualStream();
|
|
46
|
+
// Set up log streaming
|
|
47
|
+
const streamLogs = this.setupLogStream(virtualStream, dataArg.filters?.level, dataArg.filters?.category, dataArg.follow);
|
|
48
|
+
// Start streaming
|
|
49
|
+
streamLogs.start();
|
|
50
|
+
// Track the stop function so we can clean up on shutdown
|
|
51
|
+
this.activeStreamStops.add(streamLogs.stop);
|
|
52
|
+
return {
|
|
53
|
+
logStream: virtualStream,
|
|
54
|
+
};
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
static mapLogLevel(smartlogLevel) {
|
|
58
|
+
switch (smartlogLevel) {
|
|
59
|
+
case 'silly':
|
|
60
|
+
case 'debug':
|
|
61
|
+
return 'debug';
|
|
62
|
+
case 'warn':
|
|
63
|
+
return 'warn';
|
|
64
|
+
case 'error':
|
|
65
|
+
return 'error';
|
|
66
|
+
default:
|
|
67
|
+
return 'info';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
static deriveCategory(zone, message) {
|
|
71
|
+
const msg = (message || '').toLowerCase();
|
|
72
|
+
if (msg.includes('[security:') || msg.includes('security'))
|
|
73
|
+
return 'security';
|
|
74
|
+
if (zone === 'email' || msg.includes('email') || msg.includes('smtp') || msg.includes('mta'))
|
|
75
|
+
return 'email';
|
|
76
|
+
if (zone === 'dns' || msg.includes('dns'))
|
|
77
|
+
return 'dns';
|
|
78
|
+
if (msg.includes('smtp'))
|
|
79
|
+
return 'smtp';
|
|
80
|
+
return 'system';
|
|
81
|
+
}
|
|
82
|
+
async getRecentLogs(level, category, limit = 100, offset = 0, search, timeRange) {
|
|
83
|
+
// Compute a timestamp cutoff from timeRange
|
|
84
|
+
let since;
|
|
85
|
+
if (timeRange) {
|
|
86
|
+
const rangeMs = {
|
|
87
|
+
'1h': 3600000,
|
|
88
|
+
'6h': 21600000,
|
|
89
|
+
'24h': 86400000,
|
|
90
|
+
'7d': 604800000,
|
|
91
|
+
'30d': 2592000000,
|
|
92
|
+
};
|
|
93
|
+
since = Date.now() - (rangeMs[timeRange] || 86400000);
|
|
94
|
+
}
|
|
95
|
+
// Map the UI level to smartlog levels for filtering
|
|
96
|
+
const smartlogLevels = level
|
|
97
|
+
? level === 'debug'
|
|
98
|
+
? ['debug', 'silly']
|
|
99
|
+
: level === 'info'
|
|
100
|
+
? ['info', 'ok', 'success', 'note', 'lifecycle']
|
|
101
|
+
: [level]
|
|
102
|
+
: undefined;
|
|
103
|
+
// Fetch a larger batch from buffer, then apply category filter client-side
|
|
104
|
+
const rawEntries = logBuffer.getEntries({
|
|
105
|
+
level: smartlogLevels,
|
|
106
|
+
search,
|
|
107
|
+
since,
|
|
108
|
+
limit: limit * 3, // over-fetch to compensate for category filtering
|
|
109
|
+
offset: 0,
|
|
110
|
+
});
|
|
111
|
+
// Map ILogPackage → UI log format and apply category filter
|
|
112
|
+
const mapped = [];
|
|
113
|
+
for (const pkg of rawEntries) {
|
|
114
|
+
const uiLevel = LogsHandler.mapLogLevel(pkg.level);
|
|
115
|
+
const uiCategory = LogsHandler.deriveCategory(pkg.context?.zone, pkg.message);
|
|
116
|
+
if (category && uiCategory !== category)
|
|
117
|
+
continue;
|
|
118
|
+
mapped.push({
|
|
119
|
+
timestamp: pkg.timestamp,
|
|
120
|
+
level: uiLevel,
|
|
121
|
+
category: uiCategory,
|
|
122
|
+
message: pkg.message,
|
|
123
|
+
metadata: pkg.data,
|
|
124
|
+
});
|
|
125
|
+
if (mapped.length >= limit)
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
return mapped;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Add a log destination to the base logger that pushes entries
|
|
132
|
+
* to all connected ops_dashboard TypedSocket clients.
|
|
133
|
+
*
|
|
134
|
+
* Uses a module-level singleton so the destination is added only once,
|
|
135
|
+
* even across OpsServer restart cycles. The destination reads
|
|
136
|
+
* `currentOpsServerRef` dynamically so it always uses the active server.
|
|
137
|
+
*/
|
|
138
|
+
setupLogPushDestination() {
|
|
139
|
+
// Update the module-level reference so the existing destination uses the new server
|
|
140
|
+
currentOpsServerRef = this.opsServerRef;
|
|
141
|
+
if (logPushDestinationInstalled) {
|
|
142
|
+
return; // destination already registered — just updated the ref
|
|
143
|
+
}
|
|
144
|
+
logPushDestinationInstalled = true;
|
|
145
|
+
baseLogger.addLogDestination({
|
|
146
|
+
async handleLog(logPackage) {
|
|
147
|
+
const opsServer = currentOpsServerRef;
|
|
148
|
+
if (!opsServer)
|
|
149
|
+
return;
|
|
150
|
+
const typedsocket = opsServer.server?.typedserver?.typedsocket;
|
|
151
|
+
if (!typedsocket)
|
|
152
|
+
return;
|
|
153
|
+
let connections;
|
|
154
|
+
try {
|
|
155
|
+
connections = await typedsocket.findAllTargetConnectionsByTag('role', 'ops_dashboard');
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (connections.length === 0)
|
|
161
|
+
return;
|
|
162
|
+
const entry = {
|
|
163
|
+
timestamp: logPackage.timestamp || Date.now(),
|
|
164
|
+
level: LogsHandler.mapLogLevel(logPackage.level),
|
|
165
|
+
category: LogsHandler.deriveCategory(logPackage.context?.zone, logPackage.message),
|
|
166
|
+
message: logPackage.message,
|
|
167
|
+
metadata: logPackage.data,
|
|
168
|
+
};
|
|
169
|
+
for (const conn of connections) {
|
|
170
|
+
try {
|
|
171
|
+
const push = typedsocket.createTypedRequest('pushLogEntry', conn);
|
|
172
|
+
push.fire({ entry }).catch(() => { }); // fire-and-forget
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// connection may have closed
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
setupLogStream(virtualStream, levelFilter, categoryFilter, follow = true) {
|
|
182
|
+
let intervalId = null;
|
|
183
|
+
let stopped = false;
|
|
184
|
+
let logIndex = 0;
|
|
185
|
+
const stop = () => {
|
|
186
|
+
stopped = true;
|
|
187
|
+
if (intervalId) {
|
|
188
|
+
clearInterval(intervalId);
|
|
189
|
+
intervalId = null;
|
|
190
|
+
}
|
|
191
|
+
this.activeStreamStops.delete(stop);
|
|
192
|
+
};
|
|
193
|
+
const start = () => {
|
|
194
|
+
if (!follow) {
|
|
195
|
+
// Send existing logs and close
|
|
196
|
+
this.getRecentLogs(levelFilter?.[0], categoryFilter?.[0], 100, 0).then(logs => {
|
|
197
|
+
logs.forEach(log => {
|
|
198
|
+
const logData = JSON.stringify(log);
|
|
199
|
+
const encoder = new TextEncoder();
|
|
200
|
+
virtualStream.sendData(encoder.encode(logData));
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// For follow mode, simulate real-time log streaming
|
|
206
|
+
intervalId = setInterval(async () => {
|
|
207
|
+
if (stopped) {
|
|
208
|
+
// Guard: clear interval if stop() was called between ticks
|
|
209
|
+
clearInterval(intervalId);
|
|
210
|
+
intervalId = null;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const categories = ['smtp', 'dns', 'security', 'system', 'email'];
|
|
214
|
+
const levels = ['info', 'warn', 'error', 'debug'];
|
|
215
|
+
const mockCategory = categories[Math.floor(Math.random() * categories.length)];
|
|
216
|
+
const mockLevel = levels[Math.floor(Math.random() * levels.length)];
|
|
217
|
+
// Filter by requested criteria
|
|
218
|
+
if (levelFilter && !levelFilter.includes(mockLevel))
|
|
219
|
+
return;
|
|
220
|
+
if (categoryFilter && !categoryFilter.includes(mockCategory))
|
|
221
|
+
return;
|
|
222
|
+
const logEntry = {
|
|
223
|
+
timestamp: Date.now(),
|
|
224
|
+
level: mockLevel,
|
|
225
|
+
category: mockCategory,
|
|
226
|
+
message: `Real-time log ${logIndex++} from ${mockCategory}`,
|
|
227
|
+
metadata: {
|
|
228
|
+
requestId: plugins.uuid.v4(),
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
const logData = JSON.stringify(logEntry);
|
|
232
|
+
const encoder = new TextEncoder();
|
|
233
|
+
try {
|
|
234
|
+
// Use a timeout to detect hung streams (sendData can hang if the
|
|
235
|
+
// VirtualStream's keepAlive loop has ended)
|
|
236
|
+
let timeoutHandle;
|
|
237
|
+
await Promise.race([
|
|
238
|
+
virtualStream.sendData(encoder.encode(logData)).then((result) => {
|
|
239
|
+
clearTimeout(timeoutHandle);
|
|
240
|
+
return result;
|
|
241
|
+
}),
|
|
242
|
+
new Promise((_, reject) => {
|
|
243
|
+
timeoutHandle = setTimeout(() => reject(new Error('stream send timeout')), 10_000);
|
|
244
|
+
}),
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// Stream closed, errored, or timed out — clean up
|
|
249
|
+
stop();
|
|
250
|
+
}
|
|
251
|
+
}, 2000);
|
|
252
|
+
};
|
|
253
|
+
return { start, stop };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9ncy5oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvb3Bzc2VydmVyL2hhbmRsZXJzL2xvZ3MuaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sS0FBSyxVQUFVLE1BQU0saUNBQWlDLENBQUM7QUFDOUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV4RCw0RUFBNEU7QUFDNUUsNEVBQTRFO0FBQzVFLHVDQUF1QztBQUN2QyxJQUFJLDJCQUEyQixHQUFHLEtBQUssQ0FBQztBQUN4QyxJQUFJLG1CQUFtQixHQUFxQixJQUFJLENBQUM7QUFFakQsTUFBTSxPQUFPLFdBQVc7SUFHRjtJQUZaLGlCQUFpQixHQUFvQixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBRXZELFlBQW9CLFlBQXVCO1FBQXZCLGlCQUFZLEdBQVosWUFBWSxDQUFXO1FBQ3pDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7O09BR0c7SUFDSSxPQUFPO1FBQ1osMENBQTBDO1FBQzFDLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDMUMsSUFBSSxFQUFFLENBQUM7UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQy9CLDRFQUE0RTtRQUM1RSxtQkFBbUIsR0FBRyxJQUFJLENBQUM7SUFDN0IsQ0FBQztJQUVPLGdCQUFnQjtRQUN0Qiw2RkFBNkY7UUFDN0YsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUM7UUFFNUMsMEJBQTBCO1FBQzFCLE1BQU0sQ0FBQyxlQUFlLENBQ3BCLElBQUksT0FBTyxD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
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Log level for security events
|
|
5
|
+
*/
|
|
6
|
+
export var SecurityLogLevel;
|
|
7
|
+
(function (SecurityLogLevel) {
|
|
8
|
+
SecurityLogLevel["INFO"] = "info";
|
|
9
|
+
SecurityLogLevel["WARN"] = "warn";
|
|
10
|
+
SecurityLogLevel["ERROR"] = "error";
|
|
11
|
+
SecurityLogLevel["CRITICAL"] = "critical";
|
|
12
|
+
})(SecurityLogLevel || (SecurityLogLevel = {}));
|
|
13
|
+
/**
|
|
14
|
+
* Security event types for categorization
|
|
15
|
+
*/
|
|
16
|
+
export var SecurityEventType;
|
|
17
|
+
(function (SecurityEventType) {
|
|
18
|
+
SecurityEventType["AUTHENTICATION"] = "authentication";
|
|
19
|
+
SecurityEventType["ACCESS_CONTROL"] = "access_control";
|
|
20
|
+
SecurityEventType["EMAIL_VALIDATION"] = "email_validation";
|
|
21
|
+
SecurityEventType["EMAIL_PROCESSING"] = "email_processing";
|
|
22
|
+
SecurityEventType["EMAIL_FORWARDING"] = "email_forwarding";
|
|
23
|
+
SecurityEventType["EMAIL_DELIVERY"] = "email_delivery";
|
|
24
|
+
SecurityEventType["DKIM"] = "dkim";
|
|
25
|
+
SecurityEventType["SPF"] = "spf";
|
|
26
|
+
SecurityEventType["DMARC"] = "dmarc";
|
|
27
|
+
SecurityEventType["RATE_LIMIT"] = "rate_limit";
|
|
28
|
+
SecurityEventType["RATE_LIMITING"] = "rate_limiting";
|
|
29
|
+
SecurityEventType["SPAM"] = "spam";
|
|
30
|
+
SecurityEventType["MALWARE"] = "malware";
|
|
31
|
+
SecurityEventType["CONNECTION"] = "connection";
|
|
32
|
+
SecurityEventType["DATA_EXPOSURE"] = "data_exposure";
|
|
33
|
+
SecurityEventType["CONFIGURATION"] = "configuration";
|
|
34
|
+
SecurityEventType["IP_REPUTATION"] = "ip_reputation";
|
|
35
|
+
SecurityEventType["REJECTED_CONNECTION"] = "rejected_connection";
|
|
36
|
+
})(SecurityEventType || (SecurityEventType = {}));
|
|
37
|
+
/**
|
|
38
|
+
* Security logger for enhanced security monitoring
|
|
39
|
+
*/
|
|
40
|
+
export class SecurityLogger {
|
|
41
|
+
static instance;
|
|
42
|
+
securityEvents = [];
|
|
43
|
+
maxEventHistory;
|
|
44
|
+
enableNotifications;
|
|
45
|
+
constructor(options) {
|
|
46
|
+
this.maxEventHistory = options?.maxEventHistory || 1000;
|
|
47
|
+
this.enableNotifications = options?.enableNotifications || false;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get singleton instance
|
|
51
|
+
*/
|
|
52
|
+
static getInstance(options) {
|
|
53
|
+
if (!SecurityLogger.instance) {
|
|
54
|
+
SecurityLogger.instance = new SecurityLogger(options);
|
|
55
|
+
}
|
|
56
|
+
return SecurityLogger.instance;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reset the singleton instance (for shutdown/testing)
|
|
60
|
+
*/
|
|
61
|
+
static resetInstance() {
|
|
62
|
+
SecurityLogger.instance = undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Log a security event
|
|
66
|
+
* @param event The security event to log
|
|
67
|
+
*/
|
|
68
|
+
logEvent(event) {
|
|
69
|
+
const fullEvent = {
|
|
70
|
+
...event,
|
|
71
|
+
timestamp: Date.now()
|
|
72
|
+
};
|
|
73
|
+
// Store in memory buffer
|
|
74
|
+
this.securityEvents.push(fullEvent);
|
|
75
|
+
// Trim history if needed
|
|
76
|
+
if (this.securityEvents.length > this.maxEventHistory) {
|
|
77
|
+
this.securityEvents.shift();
|
|
78
|
+
}
|
|
79
|
+
// Log to regular logger with appropriate level
|
|
80
|
+
switch (event.level) {
|
|
81
|
+
case SecurityLogLevel.INFO:
|
|
82
|
+
logger.log('info', `[SECURITY:${event.type}] ${event.message}`, event.details);
|
|
83
|
+
break;
|
|
84
|
+
case SecurityLogLevel.WARN:
|
|
85
|
+
logger.log('warn', `[SECURITY:${event.type}] ${event.message}`, event.details);
|
|
86
|
+
break;
|
|
87
|
+
case SecurityLogLevel.ERROR:
|
|
88
|
+
case SecurityLogLevel.CRITICAL:
|
|
89
|
+
logger.log('error', `[SECURITY:${event.type}] ${event.message}`, event.details);
|
|
90
|
+
// Send notification for critical events if enabled
|
|
91
|
+
if (event.level === SecurityLogLevel.CRITICAL && this.enableNotifications) {
|
|
92
|
+
this.sendNotification(fullEvent);
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get recent security events
|
|
99
|
+
* @param limit Maximum number of events to return
|
|
100
|
+
* @param filter Filter for specific event types
|
|
101
|
+
* @returns Recent security events
|
|
102
|
+
*/
|
|
103
|
+
getRecentEvents(limit = 100, filter) {
|
|
104
|
+
let filteredEvents = this.securityEvents;
|
|
105
|
+
// Apply filters
|
|
106
|
+
if (filter) {
|
|
107
|
+
if (filter.level) {
|
|
108
|
+
filteredEvents = filteredEvents.filter(event => event.level === filter.level);
|
|
109
|
+
}
|
|
110
|
+
if (filter.type) {
|
|
111
|
+
filteredEvents = filteredEvents.filter(event => event.type === filter.type);
|
|
112
|
+
}
|
|
113
|
+
if (filter.fromTimestamp) {
|
|
114
|
+
filteredEvents = filteredEvents.filter(event => event.timestamp >= filter.fromTimestamp);
|
|
115
|
+
}
|
|
116
|
+
if (filter.toTimestamp) {
|
|
117
|
+
filteredEvents = filteredEvents.filter(event => event.timestamp <= filter.toTimestamp);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Return most recent events up to limit (slice first to avoid mutating source)
|
|
121
|
+
return filteredEvents
|
|
122
|
+
.slice()
|
|
123
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
124
|
+
.slice(0, limit);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get events by security level
|
|
128
|
+
* @param level The security level to filter by
|
|
129
|
+
* @param limit Maximum number of events to return
|
|
130
|
+
* @returns Security events matching the level
|
|
131
|
+
*/
|
|
132
|
+
getEventsByLevel(level, limit = 100) {
|
|
133
|
+
return this.getRecentEvents(limit, { level });
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get events by security type
|
|
137
|
+
* @param type The event type to filter by
|
|
138
|
+
* @param limit Maximum number of events to return
|
|
139
|
+
* @returns Security events matching the type
|
|
140
|
+
*/
|
|
141
|
+
getEventsByType(type, limit = 100) {
|
|
142
|
+
return this.getRecentEvents(limit, { type });
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get security events for a specific IP address
|
|
146
|
+
* @param ipAddress The IP address to filter by
|
|
147
|
+
* @param limit Maximum number of events to return
|
|
148
|
+
* @returns Security events for the IP address
|
|
149
|
+
*/
|
|
150
|
+
getEventsByIP(ipAddress, limit = 100) {
|
|
151
|
+
return this.securityEvents
|
|
152
|
+
.filter(event => event.ipAddress === ipAddress)
|
|
153
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
154
|
+
.slice(0, limit);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get security events for a specific domain
|
|
158
|
+
* @param domain The domain to filter by
|
|
159
|
+
* @param limit Maximum number of events to return
|
|
160
|
+
* @returns Security events for the domain
|
|
161
|
+
*/
|
|
162
|
+
getEventsByDomain(domain, limit = 100) {
|
|
163
|
+
return this.securityEvents
|
|
164
|
+
.filter(event => event.domain === domain)
|
|
165
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
166
|
+
.slice(0, limit);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Send a notification for critical security events
|
|
170
|
+
* @param event The security event to notify about
|
|
171
|
+
* @private
|
|
172
|
+
*/
|
|
173
|
+
sendNotification(event) {
|
|
174
|
+
// In a production environment, this would integrate with a notification service
|
|
175
|
+
// For now, we'll just log that we would send a notification
|
|
176
|
+
logger.log('error', `[SECURITY NOTIFICATION] ${event.message}`, {
|
|
177
|
+
...event,
|
|
178
|
+
notificationSent: true
|
|
179
|
+
});
|
|
180
|
+
// Future integration with alerting systems would go here
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Clear event history
|
|
184
|
+
*/
|
|
185
|
+
clearEvents() {
|
|
186
|
+
this.securityEvents = [];
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get statistical summary of security events
|
|
190
|
+
* @param timeWindow Optional time window in milliseconds
|
|
191
|
+
* @returns Summary of security events
|
|
192
|
+
*/
|
|
193
|
+
getEventsSummary(timeWindow) {
|
|
194
|
+
const cutoff = timeWindow ? Date.now() - timeWindow : 0;
|
|
195
|
+
// Initialize counters
|
|
196
|
+
const byLevel = {};
|
|
197
|
+
for (const level of Object.values(SecurityLogLevel)) {
|
|
198
|
+
byLevel[level] = 0;
|
|
199
|
+
}
|
|
200
|
+
const byType = {};
|
|
201
|
+
for (const type of Object.values(SecurityEventType)) {
|
|
202
|
+
byType[type] = 0;
|
|
203
|
+
}
|
|
204
|
+
const ipCounts = new Map();
|
|
205
|
+
const domainCounts = new Map();
|
|
206
|
+
// Single pass over all events
|
|
207
|
+
let total = 0;
|
|
208
|
+
for (const e of this.securityEvents) {
|
|
209
|
+
if (cutoff && e.timestamp < cutoff)
|
|
210
|
+
continue;
|
|
211
|
+
total++;
|
|
212
|
+
byLevel[e.level]++;
|
|
213
|
+
byType[e.type]++;
|
|
214
|
+
if (e.ipAddress) {
|
|
215
|
+
ipCounts.set(e.ipAddress, (ipCounts.get(e.ipAddress) || 0) + 1);
|
|
216
|
+
}
|
|
217
|
+
if (e.domain) {
|
|
218
|
+
domainCounts.set(e.domain, (domainCounts.get(e.domain) || 0) + 1);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Sort and limit top entries
|
|
222
|
+
const topIPs = Array.from(ipCounts.entries())
|
|
223
|
+
.map(([ip, count]) => ({ ip, count }))
|
|
224
|
+
.sort((a, b) => b.count - a.count)
|
|
225
|
+
.slice(0, 10);
|
|
226
|
+
const topDomains = Array.from(domainCounts.entries())
|
|
227
|
+
.map(([domain, count]) => ({ domain, count }))
|
|
228
|
+
.sort((a, b) => b.count - a.count)
|
|
229
|
+
.slice(0, 10);
|
|
230
|
+
return { total, byLevel, byType, topIPs, topDomains };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zZWN1cml0eWxvZ2dlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3NlY3VyaXR5L2NsYXNzZXMuc2VjdXJpdHlsb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV0Qzs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLGdCQUtYO0FBTEQsV0FBWSxnQkFBZ0I7SUFDMUIsaUNBQWEsQ0FBQTtJQUNiLGlDQUFhLENBQUE7SUFDYixtQ0FBZSxDQUFBO0lBQ2YseUNBQXFCLENBQUE7QUFDdkIsQ0FBQyxFQUxXLGdCQUFnQixLQUFoQixnQkFBZ0IsUUFLM0I7QUFFRDs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLGlCQW1CWDtBQW5CRCxXQUFZLGlCQUFpQjtJQUMzQixzREFBaUMsQ0FBQTtJQUNqQyxzREFBaUMsQ0FBQTtJQUNqQywwREFBcUMsQ0FBQTtJQUNyQywwREFBcUMsQ0FBQTtJQUNyQywwREFBcUMsQ0FBQTtJQUNyQyxzREFBaUMsQ0FBQTtJQUNqQyxrQ0FBYSxDQUFBO0lBQ2IsZ0NBQVcsQ0FBQTtJQUNYLG9DQUFlLENBQUE7SUFDZiw4Q0FBeUIsQ0FBQTtJQUN6QixvREFBK0IsQ0FBQTtJQUMvQixrQ0FBYSxDQUFBO0lBQ2Isd0NBQW1CLENBQUE7SUFDbkIsOENBQXlCLENBQUE7SUFDekIsb0RBQStCLENBQUE7SUFDL0Isb0RBQStCLENBQUE7SUFDL0Isb0RBQStCLENBQUE7SUFDL0IsZ0VBQTJDLENBQUE7QUFDN0MsQ0FBQyxFQW5CVyxpQkFBaUIsS0FBakIsaUJBQWlCLFFBbUI1QjtBQXFCRDs7R0FFRztBQUNILE1BQU0sT0FBTyxjQUFjO0lBQ2pCLE1BQU0sQ0FBQyxRQUFRLENBQWlCO0lBQ2hDLGNBQWMsR0FBcUIsRUFBRSxDQUFDO0lBQ3RDLGVBQWUsQ0FBUztJQUN4QixtQkFBbUIsQ0FBVTtJQUVyQyxZQUFvQixPQUduQjtRQUNDLElBQUksQ0FBQyxlQUFlLEdBQUcsT0FBTyxFQUFFLGVBQWUsSUFBSSxJQUFJLENBQUM7UUFDeEQsSUFBSSxDQUFDLG1CQUFtQixHQUFHLE9BQU8sRUFBRSxtQkFBbUIsSUFBSSxLQUFLLENBQUM7SUFDbkUsQ0FBQztJQUVEOztPQUVHO0lBQ0ksTUFBTSxDQUFDLFdBQVcsQ0FBQyxPQUd6QjtRQUNDLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDN0IsY0FBYyxDQUFDLFFBQVEsR0FBRyxJQUFJLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4RCxDQUFDO1FBQ0QsT0FBTyxjQUFjLENBQUMsUUFBUSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxhQUFhO1FBQ3pCLGNBQWMsQ0FBQyxRQUFRLEdBQUcsU0FBUyxDQUFDO0lBQ3RDLENBQUM7SUFFRDs7O09BR0c7SUFDSSxRQUFRLENBQUMsS0FBd0M7UUFDdEQsTUFBTSxTQUFTLEdBQW1CO1lBQ2hDLEdBQUcsS0FBSztZQUNSLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO1NBQ3RCLENBQUM7UUFFRix5QkFBeUI7UUFDekIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFcEMseUJBQXlCO1FBQ3pCLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3RELElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDOUIsQ0FBQztRQUVELCtDQUErQztRQUMvQyxRQUFRLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNwQixLQUFLLGdCQUFnQixDQUFDLElBQUk7Z0JBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLGFBQWEsS0FBSyxDQUFDLElBQUksS0FBSyxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUMvRSxNQUFNO1lBQ1IsS0FBSyxnQkFBZ0IsQ0FBQyxJQUFJO2dCQUN4QixNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxhQUFhLEtBQUssQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDL0UsTUFBTTtZQUNSLEtBQUssZ0JBQWdCLENBQUMsS0FBSyxDQUFDO1lBQzVCLEtBQUssZ0JBQWdCLENBQUMsUUFBUTtnQkFDNUIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsYUFBYSxLQUFLLENBQUMsSUFBSSxLQUFLLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBRWhGLG1EQUFtRDtnQkFDbkQsSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLGdCQUFnQixDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztvQkFDMUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNuQyxDQUFDO2dCQUNELE1BQU07UUFDVixDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksZUFBZSxDQUFDLFFBQWdCLEdBQUcsRUFBRSxNQUszQztRQUNDLElBQUksY0FBYyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUM7UUFFekMsZ0JBQWdCO1FBQ2hCLElBQUksTUFBTSxFQUFFLENBQUM7WUFDWCxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDakIsY0FBYyxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNoRixDQUFDO1lBRUQsSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ2hCLGNBQWMsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDOUUsQ0FBQztZQUVELElBQUksTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUN6QixjQUFjLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzNGLENBQUM7WUFFRCxJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDdkIsY0FBYyxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsU0FBUyxJQUFJLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUN6RixDQUFDO1FBQ0gsQ0FBQztRQUVELCtFQUErRTtRQUMvRSxPQUFPLGNBQWM7YUFDbEIsS0FBSyxFQUFFO2FBQ1AsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDO2FBQ3pDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDckIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksZ0JBQWdCLENBQUMsS0FBdUIsRUFBRSxRQUFnQixHQUFHO1FBQ2xFLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLGVBQWUsQ0FBQyxJQUF1QixFQUFFLFFBQWdCLEdBQUc7UUFDakUsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksYUFBYSxDQUFDLFNBQWlCLEVBQUUsUUFBZ0IsR0FBRztRQUN6RCxPQUFPLElBQUksQ0FBQyxjQUFjO2FBQ3ZCLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDO2FBQzlDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQzthQUN6QyxLQUFLLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLGlCQUFpQixDQUFDLE1BQWMsRUFBRSxRQUFnQixHQUFHO1FBQzFELE9BQU8sSUFBSSxDQUFDLGNBQWM7YUFDdkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sS0FBSyxNQUFNLENBQUM7YUFDeEMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDO2FBQ3pDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDckIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxnQkFBZ0IsQ0FBQyxLQUFxQjtRQUM1QyxnRkFBZ0Y7UUFDaEYsNERBQTREO1FBQzVELE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLDJCQUEyQixLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDOUQsR0FBRyxLQUFLO1lBQ1IsZ0JBQWdCLEVBQUUsSUFBSTtTQUN2QixDQUFDLENBQUM7UUFFSCx5REFBeUQ7SUFDM0QsQ0FBQztJQUVEOztPQUVHO0lBQ0ksV0FBVztRQUNoQixJQUFJLENBQUMsY0FBYyxHQUFHLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLGdCQUFnQixDQUFDLFVBQW1CO1FBT3pDLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXhELHNCQUFzQjtRQUN0QixNQUFNLE9BQU8sR0FBRyxFQUFzQyxDQUFDO1FBQ3ZELEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUM7WUFDcEQsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQixDQUFDO1FBQ0QsTUFBTSxNQUFNLEdBQUcsRUFBdUMsQ0FBQztRQUN2RCxLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO1lBQ3BELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkIsQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBQzNDLE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBRS9DLDhCQUE4QjtRQUM5QixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxLQUFLLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNwQyxJQUFJLE1BQU0sSUFBSSxDQUFDLENBQUMsU0FBUyxHQUFHLE1BQU07Z0JBQUUsU0FBUztZQUM3QyxLQUFLLEVBQUUsQ0FBQztZQUNSLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNuQixNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDakIsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ2hCLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ2xFLENBQUM7WUFDRCxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDYixZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0gsQ0FBQztRQUVELDZCQUE2QjtRQUM3QixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQzthQUMxQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO2FBQ3JDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQzthQUNqQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWhCLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxDQUFDO2FBQ2xELEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7YUFDN0MsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO2FBQ2pDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFaEIsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUN4RCxDQUFDO0NBQ0YifQ==
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/dcrouter',
|
|
6
|
-
version: '11.0.
|
|
6
|
+
version: '11.0.31',
|
|
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.
|
|
4
|
+
"version": "11.0.31",
|
|
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.
|
|
22
|
+
"@git.zone/tsbuild": "^4.1.20",
|
|
23
23
|
"@git.zone/tsbundle": "^2.9.0",
|
|
24
24
|
"@git.zone/tsrun": "^2.0.1",
|
|
25
25
|
"@git.zone/tstest": "^3.2.0",
|
package/ts/00_commitinfo_data.ts
CHANGED