@serve.zone/dcrouter 18.9.3 → 18.9.4

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 (42) hide show
  1. package/deno.json +1 -1
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.dcrouter.js +5 -4
  4. package/dist_ts/db/documents/classes.authentication-event.doc.d.ts +0 -1
  5. package/dist_ts/db/documents/classes.authentication-event.doc.js +176 -259
  6. package/dist_ts/db/documents/classes.email-traffic-bucket.doc.js +110 -188
  7. package/dist_ts/dns/manager.dns-authority.d.ts +5 -0
  8. package/dist_ts/dns/manager.dns-authority.js +97 -53
  9. package/dist_ts/dns/manager.dns.js +23 -5
  10. package/dist_ts/email/classes.email-domain.manager.js +14 -3
  11. package/dist_ts/email/classes.email-settings.manager.js +26 -6
  12. package/dist_ts/email/classes.mail-dns-sync.js +22 -2
  13. package/dist_ts/monitoring/classes.metricscache.d.ts +28 -19
  14. package/dist_ts/monitoring/classes.metricscache.js +133 -62
  15. package/dist_ts/monitoring/classes.metricsmanager.js +7 -5
  16. package/dist_ts/plugins.d.ts +2 -1
  17. package/dist_ts/plugins.js +3 -2
  18. package/dist_ts/remoteingress/classes.remoteingress-manager.js +46 -9
  19. package/dist_ts/security/classes.authentication-event-manager.d.ts +5 -1
  20. package/dist_ts/security/classes.authentication-event-manager.js +32 -22
  21. package/dist_ts/vpn/classes.vpn-manager.js +34 -2
  22. package/dist_ts_migrations/index.d.ts +4 -1
  23. package/dist_ts_migrations/index.js +18 -3
  24. package/dist_ts_web/00_commitinfo_data.js +1 -1
  25. package/package.json +7 -6
  26. package/readme.hints.md +72 -0
  27. package/ts/00_commitinfo_data.ts +1 -1
  28. package/ts/classes.dcrouter.ts +4 -3
  29. package/ts/db/documents/classes.authentication-event.doc.ts +64 -87
  30. package/ts/db/documents/classes.email-traffic-bucket.doc.ts +10 -9
  31. package/ts/dns/manager.dns-authority.ts +92 -54
  32. package/ts/dns/manager.dns.ts +20 -4
  33. package/ts/email/classes.email-domain.manager.ts +12 -2
  34. package/ts/email/classes.email-settings.manager.ts +23 -5
  35. package/ts/email/classes.mail-dns-sync.ts +23 -1
  36. package/ts/monitoring/classes.metricscache.ts +133 -79
  37. package/ts/monitoring/classes.metricsmanager.ts +6 -4
  38. package/ts/plugins.ts +2 -0
  39. package/ts/remoteingress/classes.remoteingress-manager.ts +42 -8
  40. package/ts/security/classes.authentication-event-manager.ts +31 -20
  41. package/ts/vpn/classes.vpn-manager.ts +32 -1
  42. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -1,34 +1,43 @@
1
+ import * as plugins from '../plugins.js';
1
2
  export interface ICacheEntry<T> {
2
3
  data: T;
3
4
  timestamp: number;
4
5
  ttl: number;
5
6
  }
7
+ export interface IMetricsCacheOptions {
8
+ maxAggregateEntries?: number;
9
+ maxSnapshotEntries?: number;
10
+ maxEstimatedBytes?: number;
11
+ maxInFlight?: number;
12
+ }
13
+ type TCacheCategory = 'aggregate' | 'snapshot';
14
+ /** Uses the existing TypedRequest error envelope; polling callers retain their last result. */
15
+ export declare class MetricsCapacityError extends plugins.typedrequest.TypedResponseError {
16
+ constructor();
17
+ }
6
18
  export declare class MetricsCache {
7
- private cache;
8
- private inFlight;
9
19
  private readonly defaultTTL;
10
- constructor(defaultTTL?: number);
11
- /**
12
- * Get cached data or compute and cache it
13
- */
14
- get<T>(key: string, computeFn: () => T | Promise<T>, ttl?: number): T | Promise<T>;
15
- /**
16
- * Invalidate a specific cache entry
17
- */
20
+ private readonly caches;
21
+ private readonly inFlight;
22
+ private readonly admitted;
23
+ private readonly maxInFlight;
24
+ private readonly maxEstimatedBytes;
25
+ private stopped;
26
+ private generation;
27
+ private activeComputations;
28
+ constructor(defaultTTL?: number, options?: IMetricsCacheOptions);
29
+ private createCache;
30
+ get<T>(key: string, computeFn: () => T | Promise<T>, ttl?: number, category?: TCacheCategory): T | Promise<T>;
18
31
  invalidate(key: string): void;
19
- /**
20
- * Clear all cache entries
21
- */
22
32
  clear(): void;
23
- /**
24
- * Get cache statistics
25
- */
33
+ start(): void;
34
+ stop(): Promise<void>;
26
35
  getStats(): {
27
36
  size: number;
28
37
  keys: string[];
38
+ inFlight: number;
39
+ estimatedBytes: number;
29
40
  };
30
- /**
31
- * Clean up expired entries
32
- */
33
41
  cleanup(): void;
34
42
  }
43
+ export {};
@@ -1,85 +1,156 @@
1
+ import * as plugins from '../plugins.js';
2
+ /** Uses the existing TypedRequest error envelope; polling callers retain their last result. */
3
+ export class MetricsCapacityError extends plugins.typedrequest.TypedResponseError {
4
+ constructor() {
5
+ super('Metrics are busy; retry after 500 ms', { code: 'METRICS_CAPACITY', retryAfterMs: 500 });
6
+ }
7
+ }
8
+ /** Conservative retained-payload estimate, including Maps and shared object graphs. */
9
+ function estimateBytes(value, budget, seen = new Set()) {
10
+ if (budget <= 0)
11
+ return 1;
12
+ if (typeof value === 'string')
13
+ return 24 + value.length * 2;
14
+ if (typeof value !== 'object' || value === null)
15
+ return 16;
16
+ if (seen.has(value))
17
+ return 8;
18
+ seen.add(value);
19
+ if (ArrayBuffer.isView(value))
20
+ return 64 + value.byteLength;
21
+ if (value instanceof ArrayBuffer)
22
+ return 64 + value.byteLength;
23
+ let size = 64;
24
+ if (value instanceof Map) {
25
+ for (const [key, entry] of value) {
26
+ size += 32 + estimateBytes(key, budget - size, seen) + estimateBytes(entry, budget - size, seen);
27
+ if (size > budget)
28
+ break;
29
+ }
30
+ }
31
+ else if (value instanceof Set) {
32
+ for (const entry of value) {
33
+ size += 16 + estimateBytes(entry, budget - size, seen);
34
+ if (size > budget)
35
+ break;
36
+ }
37
+ }
38
+ else {
39
+ for (const key of Object.keys(value)) {
40
+ size += 24 + key.length * 2 + estimateBytes(value[key], budget - size, seen);
41
+ if (size > budget)
42
+ break;
43
+ }
44
+ }
45
+ return size;
46
+ }
1
47
  export class MetricsCache {
2
- cache = new Map();
3
- inFlight = new Map();
4
48
  defaultTTL;
5
- constructor(defaultTTL = 500) {
49
+ caches;
50
+ inFlight = new Map();
51
+ admitted = new Set();
52
+ maxInFlight;
53
+ maxEstimatedBytes;
54
+ stopped = false;
55
+ generation = 0;
56
+ activeComputations = 0;
57
+ constructor(defaultTTL = 500, options = {}) {
6
58
  this.defaultTTL = defaultTTL;
59
+ this.maxInFlight = options.maxInFlight ?? 32;
60
+ this.maxEstimatedBytes = options.maxEstimatedBytes ?? 8 * 1024 * 1024;
61
+ this.caches = {
62
+ aggregate: this.createCache(options.maxAggregateEntries ?? 256),
63
+ snapshot: this.createCache(options.maxSnapshotEntries ?? 64),
64
+ };
65
+ }
66
+ createCache(max) {
67
+ return new plugins.lruCache.LRUCache({
68
+ max,
69
+ maxSize: this.maxEstimatedBytes,
70
+ // lru-cache owns bounded, unref'ed expiry timers, including idle keys.
71
+ ttlAutopurge: true,
72
+ ttlResolution: 0,
73
+ sizeCalculation: (entry, key) => 64 + key.length * 2 + estimateBytes(entry.data, this.maxEstimatedBytes),
74
+ });
7
75
  }
8
- /**
9
- * Get cached data or compute and cache it
10
- */
11
- get(key, computeFn, ttl) {
12
- const cached = this.cache.get(key);
13
- const now = Date.now();
14
- const actualTTL = ttl ?? this.defaultTTL;
15
- if (cached && (now - cached.timestamp) < cached.ttl) {
76
+ get(key, computeFn, ttl = this.defaultTTL, category = 'aggregate') {
77
+ if (this.stopped)
78
+ throw new Error('Metrics cache is stopped');
79
+ const cache = this.caches[category];
80
+ const cached = cache.get(key);
81
+ if (cached && Date.now() - cached.timestamp < cached.ttl)
16
82
  return cached.data;
17
- }
18
- if (cached) {
19
- this.cache.delete(key);
20
- }
21
- const pending = this.inFlight.get(key);
22
- if (pending) {
83
+ cache.delete(key);
84
+ const flightKey = JSON.stringify([category, key]);
85
+ const pending = this.inFlight.get(flightKey);
86
+ if (pending)
23
87
  return pending;
88
+ if (this.activeComputations >= this.maxInFlight)
89
+ throw new MetricsCapacityError();
90
+ const generation = this.generation;
91
+ this.activeComputations++;
92
+ let result;
93
+ try {
94
+ result = computeFn();
24
95
  }
25
- const result = computeFn();
26
- // Handle both sync and async compute functions
27
- if (result instanceof Promise) {
28
- let inFlightPromise;
29
- inFlightPromise = result.then((data) => {
30
- if (this.inFlight.get(key) === inFlightPromise) {
31
- this.inFlight.delete(key);
32
- this.cache.set(key, { data, timestamp: Date.now(), ttl: actualTTL });
33
- }
34
- return data;
35
- }, (error) => {
36
- if (this.inFlight.get(key) === inFlightPromise) {
37
- this.inFlight.delete(key);
38
- this.cache.delete(key);
39
- }
40
- throw error;
41
- });
42
- this.inFlight.set(key, inFlightPromise);
43
- return inFlightPromise;
96
+ catch (error) {
97
+ this.activeComputations--;
98
+ throw error;
44
99
  }
45
- else {
46
- this.cache.set(key, { data: result, timestamp: now, ttl: actualTTL });
100
+ const remember = (data) => {
101
+ if (!this.stopped && generation === this.generation && ttl > 0) {
102
+ cache.set(key, { data, timestamp: Date.now(), ttl }, { ttl });
103
+ }
104
+ };
105
+ if (!(result instanceof Promise)) {
106
+ this.activeComputations--;
107
+ remember(result);
47
108
  return result;
48
109
  }
110
+ const run = result.then((data) => {
111
+ if (this.inFlight.get(flightKey) === run)
112
+ remember(data);
113
+ return data;
114
+ }).finally(() => {
115
+ this.activeComputations--;
116
+ this.admitted.delete(run);
117
+ if (this.inFlight.get(flightKey) === run)
118
+ this.inFlight.delete(flightKey);
119
+ });
120
+ this.admitted.add(run);
121
+ this.inFlight.set(flightKey, run);
122
+ return run;
49
123
  }
50
- /**
51
- * Invalidate a specific cache entry
52
- */
53
124
  invalidate(key) {
54
- this.cache.delete(key);
55
- this.inFlight.delete(key);
125
+ for (const category of ['aggregate', 'snapshot']) {
126
+ this.caches[category].delete(key);
127
+ this.inFlight.delete(JSON.stringify([category, key]));
128
+ }
56
129
  }
57
- /**
58
- * Clear all cache entries
59
- */
60
130
  clear() {
61
- this.cache.clear();
131
+ this.generation++;
132
+ this.caches.aggregate.clear();
133
+ this.caches.snapshot.clear();
62
134
  this.inFlight.clear();
135
+ // Invalidated work retains its admission slot until it actually settles.
136
+ }
137
+ start() { this.stopped = false; }
138
+ async stop() {
139
+ this.stopped = true;
140
+ this.clear();
141
+ await Promise.allSettled(this.admitted);
63
142
  }
64
- /**
65
- * Get cache statistics
66
- */
67
143
  getStats() {
68
144
  return {
69
- size: this.cache.size,
70
- keys: Array.from(this.cache.keys())
145
+ size: this.caches.aggregate.size + this.caches.snapshot.size,
146
+ keys: [...this.caches.aggregate.keys(), ...this.caches.snapshot.keys()],
147
+ inFlight: this.activeComputations,
148
+ estimatedBytes: this.caches.aggregate.calculatedSize + this.caches.snapshot.calculatedSize,
71
149
  };
72
150
  }
73
- /**
74
- * Clean up expired entries
75
- */
76
151
  cleanup() {
77
- const now = Date.now();
78
- for (const [key, entry] of this.cache.entries()) {
79
- if (now - entry.timestamp > entry.ttl) {
80
- this.cache.delete(key);
81
- }
82
- }
152
+ this.caches.aggregate.purgeStale();
153
+ this.caches.snapshot.purgeStale();
83
154
  }
84
155
  }
85
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tZXRyaWNzY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9tb25pdG9yaW5nL2NsYXNzZXMubWV0cmljc2NhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU1BLE1BQU0sT0FBTyxZQUFZO0lBQ2YsS0FBSyxHQUFHLElBQUksR0FBRyxFQUE0QixDQUFDO0lBQzVDLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBd0IsQ0FBQztJQUNsQyxVQUFVLENBQVM7SUFFcEMsWUFBWSxhQUFxQixHQUFHO1FBQ2xDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7T0FFRztJQUNJLEdBQUcsQ0FBSSxHQUFXLEVBQUUsU0FBK0IsRUFBRSxHQUFZO1FBQ3RFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ25DLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN2QixNQUFNLFNBQVMsR0FBRyxHQUFHLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQztRQUV6QyxJQUFJLE1BQU0sSUFBSSxDQUFDLEdBQUcsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3BELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQztRQUNyQixDQUFDO1FBRUQsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pCLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQTJCLENBQUM7UUFDakUsSUFBSSxPQUFPLEVBQUUsQ0FBQztZQUNaLE9BQU8sT0FBTyxDQUFDO1FBQ2pCLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxTQUFT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
156
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tZXRyaWNzY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9tb25pdG9yaW5nL2NsYXNzZXMubWV0cmljc2NhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBaUJ6QywrRkFBK0Y7QUFDL0YsTUFBTSxPQUFPLG9CQUFxQixTQUFRLE9BQU8sQ0FBQyxZQUFZLENBQUMsa0JBQWtCO0lBQy9FO1FBQ0UsS0FBSyxDQUFDLHNDQUFzQyxFQUFFLEVBQUUsSUFBSSxFQUFFLGtCQUFrQixFQUFFLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ2pHLENBQUM7Q0FDRjtBQUVELHVGQUF1RjtBQUN2RixTQUFTLGFBQWEsQ0FBQyxLQUFjLEVBQUUsTUFBYyxFQUFFLE9BQU8sSUFBSSxHQUFHLEVBQVU7SUFDN0UsSUFBSSxNQUFNLElBQUksQ0FBQztRQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzFCLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtRQUFFLE9BQU8sRUFBRSxHQUFHLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQzVELElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJO1FBQUUsT0FBTyxFQUFFLENBQUM7SUFDM0QsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzlCLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEIsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sRUFBRSxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUM7SUFDNUQsSUFBSSxLQUFLLFlBQVksV0FBVztRQUFFLE9BQU8sRUFBRSxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUM7SUFDL0QsSUFBSSxJQUFJLEdBQUcsRUFB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