@metamask-previews/phishing-controller 17.4.0-preview-4f4c98e → 17.4.0-preview-eb263b0ee
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/CHANGELOG.md +0 -2
- package/dist/CacheManager.cjs +177 -0
- package/dist/CacheManager.cjs.map +1 -0
- package/dist/{CacheManager.d.ts → CacheManager.d.cts} +1 -1
- package/dist/CacheManager.d.cts.map +1 -0
- package/dist/CacheManager.d.mts +104 -0
- package/dist/CacheManager.d.mts.map +1 -0
- package/dist/{CacheManager.js → CacheManager.mjs} +2 -2
- package/dist/CacheManager.mjs.map +1 -0
- package/dist/PathTrie.cjs +169 -0
- package/dist/PathTrie.cjs.map +1 -0
- package/dist/{PathTrie.d.ts → PathTrie.d.cts} +1 -1
- package/dist/PathTrie.d.cts.map +1 -0
- package/dist/PathTrie.d.mts +46 -0
- package/dist/PathTrie.d.mts.map +1 -0
- package/dist/{PathTrie.js → PathTrie.mjs} +2 -2
- package/dist/PathTrie.mjs.map +1 -0
- package/dist/PhishingController-method-action-types.cjs +7 -0
- package/dist/PhishingController-method-action-types.cjs.map +1 -0
- package/dist/{PhishingController-method-action-types.d.ts → PhishingController-method-action-types.d.cts} +2 -2
- package/dist/PhishingController-method-action-types.d.cts.map +1 -0
- package/dist/PhishingController-method-action-types.d.mts +123 -0
- package/dist/PhishingController-method-action-types.d.mts.map +1 -0
- package/dist/{PhishingController-method-action-types.js → PhishingController-method-action-types.mjs} +1 -1
- package/dist/PhishingController-method-action-types.mjs.map +1 -0
- package/dist/PhishingController.cjs +1222 -0
- package/dist/PhishingController.cjs.map +1 -0
- package/dist/{PhishingController.d.ts → PhishingController.d.cts} +10 -10
- package/dist/PhishingController.d.cts.map +1 -0
- package/dist/PhishingController.d.mts +425 -0
- package/dist/PhishingController.d.mts.map +1 -0
- package/dist/{PhishingController.js → PhishingController.mjs} +12 -11
- package/dist/PhishingController.mjs.map +1 -0
- package/dist/PhishingDetector.cjs +277 -0
- package/dist/PhishingDetector.cjs.map +1 -0
- package/dist/{PhishingDetector.d.ts → PhishingDetector.d.cts} +4 -4
- package/dist/PhishingDetector.d.cts.map +1 -0
- package/dist/PhishingDetector.d.mts +73 -0
- package/dist/PhishingDetector.d.mts.map +1 -0
- package/dist/{PhishingDetector.js → PhishingDetector.mjs} +15 -21
- package/dist/PhishingDetector.mjs.map +1 -0
- package/dist/address-poisoning.cjs +71 -0
- package/dist/address-poisoning.cjs.map +1 -0
- package/dist/{address-poisoning.d.ts → address-poisoning.d.cts} +2 -2
- package/dist/address-poisoning.d.cts.map +1 -0
- package/dist/address-poisoning.d.mts +3 -0
- package/dist/address-poisoning.d.mts.map +1 -0
- package/dist/{address-poisoning.js → address-poisoning.mjs} +2 -2
- package/dist/address-poisoning.mjs.map +1 -0
- package/dist/index.cjs +36 -0
- package/dist/index.cjs.map +1 -0
- package/dist/{index.d.ts → index.d.cts} +12 -12
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -0
- package/dist/tests/utils.cjs +102 -0
- package/dist/tests/utils.cjs.map +1 -0
- package/dist/tests/{utils.d.ts → utils.d.cts} +3 -3
- package/dist/tests/utils.d.cts.map +1 -0
- package/dist/tests/utils.d.mts +70 -0
- package/dist/tests/utils.d.mts.map +1 -0
- package/dist/tests/{utils.js → utils.mjs} +2 -2
- package/dist/tests/utils.mjs.map +1 -0
- package/dist/types.cjs +267 -0
- package/dist/types.cjs.map +1 -0
- package/dist/{types.d.ts → types.d.cts} +62 -62
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +338 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/{types.js → types.mjs} +1 -1
- package/dist/types.mjs.map +1 -0
- package/dist/utils.cjs +522 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/{utils.d.ts → utils.d.cts} +72 -74
- package/dist/utils.d.cts.map +1 -0
- package/dist/utils.d.mts +302 -0
- package/dist/utils.d.mts.map +1 -0
- package/dist/{utils.js → utils.mjs} +16 -16
- package/dist/utils.mjs.map +1 -0
- package/package.json +16 -12
- package/dist/CacheManager.d.ts.map +0 -1
- package/dist/CacheManager.js.map +0 -1
- package/dist/PathTrie.d.ts.map +0 -1
- package/dist/PathTrie.js.map +0 -1
- package/dist/PhishingController-method-action-types.d.ts.map +0 -1
- package/dist/PhishingController-method-action-types.js.map +0 -1
- package/dist/PhishingController.d.ts.map +0 -1
- package/dist/PhishingController.js.map +0 -1
- package/dist/PhishingDetector.d.ts.map +0 -1
- package/dist/PhishingDetector.js.map +0 -1
- package/dist/address-poisoning.d.ts.map +0 -1
- package/dist/address-poisoning.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -7
- package/dist/index.js.map +0 -1
- package/dist/tests/utils.d.ts.map +0 -1
- package/dist/tests/utils.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,8 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
|
-
- **BREAKING:** Bump minimum Node.js version to 22 ([#9168](https://github.com/MetaMask/core/pull/9168))
|
|
13
|
-
- Optimize C2 domain blocklist lookups by switching internal storage from `Array` to `Set`, reducing per-lookup complexity from O(n) to O(1) ([#6388](https://github.com/MetaMask/core/pull/6388))
|
|
14
12
|
- Bump `@metamask/transaction-controller` from `^69.5.2` to `^69.6.1` ([#9960](https://github.com/MetaMask/core/pull/9960), [#9969](https://github.com/MetaMask/core/pull/9969))
|
|
15
13
|
|
|
16
14
|
## [17.4.0]
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _CacheManager_instances, _CacheManager_cacheTTL, _CacheManager_maxCacheSize, _CacheManager_cache, _CacheManager_updateState, _CacheManager_persistCache, _CacheManager_evictEntries;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.CacheManager = void 0;
|
|
16
|
+
const utils_js_1 = require("./utils.cjs");
|
|
17
|
+
/**
|
|
18
|
+
* Generic cache manager with TTL and size limit support
|
|
19
|
+
*
|
|
20
|
+
* @template T - The type of data to cache
|
|
21
|
+
*/
|
|
22
|
+
class CacheManager {
|
|
23
|
+
/**
|
|
24
|
+
* Constructor for CacheManager
|
|
25
|
+
*
|
|
26
|
+
* @param options - Cache configuration options
|
|
27
|
+
* @param options.cacheTTL - Time to live in seconds for cached entries
|
|
28
|
+
* @param options.maxCacheSize - Maximum number of entries in the cache
|
|
29
|
+
* @param options.initialCache - Initial cache state
|
|
30
|
+
* @param options.updateState - Function to update the state when cache changes
|
|
31
|
+
*/
|
|
32
|
+
constructor({ cacheTTL = 300, // 5 minutes default
|
|
33
|
+
maxCacheSize = 100, initialCache = {}, updateState, }) {
|
|
34
|
+
_CacheManager_instances.add(this);
|
|
35
|
+
_CacheManager_cacheTTL.set(this, void 0);
|
|
36
|
+
_CacheManager_maxCacheSize.set(this, void 0);
|
|
37
|
+
_CacheManager_cache.set(this, void 0);
|
|
38
|
+
_CacheManager_updateState.set(this, void 0);
|
|
39
|
+
__classPrivateFieldSet(this, _CacheManager_cacheTTL, cacheTTL, "f");
|
|
40
|
+
__classPrivateFieldSet(this, _CacheManager_maxCacheSize, maxCacheSize, "f");
|
|
41
|
+
__classPrivateFieldSet(this, _CacheManager_cache, new Map(Object.entries(initialCache)), "f");
|
|
42
|
+
__classPrivateFieldSet(this, _CacheManager_updateState, updateState, "f");
|
|
43
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_evictEntries).call(this);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Set the time-to-live for cached entries
|
|
47
|
+
*
|
|
48
|
+
* @param ttl - The TTL in seconds
|
|
49
|
+
*/
|
|
50
|
+
setTTL(ttl) {
|
|
51
|
+
__classPrivateFieldSet(this, _CacheManager_cacheTTL, ttl, "f");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the current TTL setting
|
|
55
|
+
*
|
|
56
|
+
* @returns The TTL in seconds
|
|
57
|
+
*/
|
|
58
|
+
getTTL() {
|
|
59
|
+
return __classPrivateFieldGet(this, _CacheManager_cacheTTL, "f");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Set the maximum cache size
|
|
63
|
+
*
|
|
64
|
+
* @param maxSize - The maximum cache size
|
|
65
|
+
*/
|
|
66
|
+
setMaxSize(maxSize) {
|
|
67
|
+
__classPrivateFieldSet(this, _CacheManager_maxCacheSize, maxSize, "f");
|
|
68
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_evictEntries).call(this);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the current maximum cache size
|
|
72
|
+
*
|
|
73
|
+
* @returns The maximum cache size
|
|
74
|
+
*/
|
|
75
|
+
getMaxSize() {
|
|
76
|
+
return __classPrivateFieldGet(this, _CacheManager_maxCacheSize, "f");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the current cache size
|
|
80
|
+
*
|
|
81
|
+
* @returns The current number of entries in the cache
|
|
82
|
+
*/
|
|
83
|
+
getSize() {
|
|
84
|
+
return __classPrivateFieldGet(this, _CacheManager_cache, "f").size;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Clear the cache
|
|
88
|
+
*/
|
|
89
|
+
clear() {
|
|
90
|
+
__classPrivateFieldGet(this, _CacheManager_cache, "f").clear();
|
|
91
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_persistCache).call(this);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get a cached result if it exists and is not expired
|
|
95
|
+
*
|
|
96
|
+
* @param key - The cache key
|
|
97
|
+
* @returns The cached data or undefined if not found or expired
|
|
98
|
+
*/
|
|
99
|
+
get(key) {
|
|
100
|
+
const cacheEntry = __classPrivateFieldGet(this, _CacheManager_cache, "f").get(key);
|
|
101
|
+
if (!cacheEntry) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
// Check if the entry is expired
|
|
105
|
+
const now = (0, utils_js_1.fetchTimeNow)();
|
|
106
|
+
if (now - cacheEntry.timestamp > __classPrivateFieldGet(this, _CacheManager_cacheTTL, "f")) {
|
|
107
|
+
// Entry expired, remove it from cache
|
|
108
|
+
__classPrivateFieldGet(this, _CacheManager_cache, "f").delete(key);
|
|
109
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_persistCache).call(this);
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
return cacheEntry.data;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Add an entry to the cache, evicting oldest entries if necessary
|
|
116
|
+
*
|
|
117
|
+
* @param key - The cache key
|
|
118
|
+
* @param data - The data to cache
|
|
119
|
+
*/
|
|
120
|
+
set(key, data) {
|
|
121
|
+
__classPrivateFieldGet(this, _CacheManager_cache, "f").set(key, {
|
|
122
|
+
data,
|
|
123
|
+
timestamp: (0, utils_js_1.fetchTimeNow)(),
|
|
124
|
+
});
|
|
125
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_evictEntries).call(this);
|
|
126
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_persistCache).call(this);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Delete a specific entry from the cache
|
|
130
|
+
*
|
|
131
|
+
* @param key - The cache key
|
|
132
|
+
* @returns True if an entry was deleted
|
|
133
|
+
*/
|
|
134
|
+
delete(key) {
|
|
135
|
+
const result = __classPrivateFieldGet(this, _CacheManager_cache, "f").delete(key);
|
|
136
|
+
if (result) {
|
|
137
|
+
__classPrivateFieldGet(this, _CacheManager_instances, "m", _CacheManager_persistCache).call(this);
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get all keys in the cache
|
|
143
|
+
*
|
|
144
|
+
* @returns Array of cache keys
|
|
145
|
+
*/
|
|
146
|
+
keys() {
|
|
147
|
+
return Array.from(__classPrivateFieldGet(this, _CacheManager_cache, "f").keys());
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get all entries in the cache (including expired ones)
|
|
151
|
+
* Useful for debugging or persistence
|
|
152
|
+
*
|
|
153
|
+
* @returns Record of all cache entries
|
|
154
|
+
*/
|
|
155
|
+
getAllEntries() {
|
|
156
|
+
return Object.fromEntries(__classPrivateFieldGet(this, _CacheManager_cache, "f"));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.CacheManager = CacheManager;
|
|
160
|
+
_CacheManager_cacheTTL = new WeakMap(), _CacheManager_maxCacheSize = new WeakMap(), _CacheManager_cache = new WeakMap(), _CacheManager_updateState = new WeakMap(), _CacheManager_instances = new WeakSet(), _CacheManager_persistCache = function _CacheManager_persistCache() {
|
|
161
|
+
__classPrivateFieldGet(this, _CacheManager_updateState, "f").call(this, Object.fromEntries(__classPrivateFieldGet(this, _CacheManager_cache, "f")));
|
|
162
|
+
}, _CacheManager_evictEntries = function _CacheManager_evictEntries() {
|
|
163
|
+
if (__classPrivateFieldGet(this, _CacheManager_cache, "f").size <= __classPrivateFieldGet(this, _CacheManager_maxCacheSize, "f")) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const entriesToRemove = __classPrivateFieldGet(this, _CacheManager_cache, "f").size - __classPrivateFieldGet(this, _CacheManager_maxCacheSize, "f");
|
|
167
|
+
let count = 0;
|
|
168
|
+
// Delete the oldest entries (Map maintains insertion order)
|
|
169
|
+
for (const key of __classPrivateFieldGet(this, _CacheManager_cache, "f").keys()) {
|
|
170
|
+
if (count >= entriesToRemove) {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
__classPrivateFieldGet(this, _CacheManager_cache, "f").delete(key);
|
|
174
|
+
count += 1;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=CacheManager.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.cjs","sourceRoot":"","sources":["../src/CacheManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { fetchTimeNow } from './utils.js';\n\n/**\n * Generic cache entry type that wraps the data with a timestamp\n */\nexport type CacheEntry<T> = {\n data: T;\n timestamp: number;\n};\n\n/**\n * Configuration options for CacheManager\n */\nexport type CacheManagerOptions<T> = {\n cacheTTL?: number;\n maxCacheSize?: number;\n initialCache?: Record<string, CacheEntry<T>>;\n updateState: (cache: Record<string, CacheEntry<T>>) => void;\n};\n\n/**\n * Generic cache manager with TTL and size limit support\n *\n * @template T - The type of data to cache\n */\nexport class CacheManager<T> {\n #cacheTTL: number;\n\n #maxCacheSize: number;\n\n readonly #cache: Map<string, CacheEntry<T>>;\n\n readonly #updateState: (cache: Record<string, CacheEntry<T>>) => void;\n\n /**\n * Constructor for CacheManager\n *\n * @param options - Cache configuration options\n * @param options.cacheTTL - Time to live in seconds for cached entries\n * @param options.maxCacheSize - Maximum number of entries in the cache\n * @param options.initialCache - Initial cache state\n * @param options.updateState - Function to update the state when cache changes\n */\n constructor({\n cacheTTL = 300, // 5 minutes default\n maxCacheSize = 100,\n initialCache = {},\n updateState,\n }: CacheManagerOptions<T>) {\n this.#cacheTTL = cacheTTL;\n this.#maxCacheSize = maxCacheSize;\n this.#cache = new Map(Object.entries(initialCache));\n this.#updateState = updateState;\n this.#evictEntries();\n }\n\n /**\n * Set the time-to-live for cached entries\n *\n * @param ttl - The TTL in seconds\n */\n setTTL(ttl: number): void {\n this.#cacheTTL = ttl;\n }\n\n /**\n * Get the current TTL setting\n *\n * @returns The TTL in seconds\n */\n getTTL(): number {\n return this.#cacheTTL;\n }\n\n /**\n * Set the maximum cache size\n *\n * @param maxSize - The maximum cache size\n */\n setMaxSize(maxSize: number): void {\n this.#maxCacheSize = maxSize;\n this.#evictEntries();\n }\n\n /**\n * Get the current maximum cache size\n *\n * @returns The maximum cache size\n */\n getMaxSize(): number {\n return this.#maxCacheSize;\n }\n\n /**\n * Get the current cache size\n *\n * @returns The current number of entries in the cache\n */\n getSize(): number {\n return this.#cache.size;\n }\n\n /**\n * Clear the cache\n */\n clear(): void {\n this.#cache.clear();\n this.#persistCache();\n }\n\n /**\n * Get a cached result if it exists and is not expired\n *\n * @param key - The cache key\n * @returns The cached data or undefined if not found or expired\n */\n get(key: string): T | undefined {\n const cacheEntry = this.#cache.get(key);\n if (!cacheEntry) {\n return undefined;\n }\n\n // Check if the entry is expired\n const now = fetchTimeNow();\n if (now - cacheEntry.timestamp > this.#cacheTTL) {\n // Entry expired, remove it from cache\n this.#cache.delete(key);\n this.#persistCache();\n return undefined;\n }\n\n return cacheEntry.data;\n }\n\n /**\n * Add an entry to the cache, evicting oldest entries if necessary\n *\n * @param key - The cache key\n * @param data - The data to cache\n */\n set(key: string, data: T): void {\n this.#cache.set(key, {\n data,\n timestamp: fetchTimeNow(),\n });\n\n this.#evictEntries();\n this.#persistCache();\n }\n\n /**\n * Delete a specific entry from the cache\n *\n * @param key - The cache key\n * @returns True if an entry was deleted\n */\n delete(key: string): boolean {\n const result = this.#cache.delete(key);\n if (result) {\n this.#persistCache();\n }\n return result;\n }\n\n /**\n * Get all keys in the cache\n *\n * @returns Array of cache keys\n */\n keys(): string[] {\n return Array.from(this.#cache.keys());\n }\n\n /**\n * Get all entries in the cache (including expired ones)\n * Useful for debugging or persistence\n *\n * @returns Record of all cache entries\n */\n getAllEntries(): Record<string, CacheEntry<T>> {\n return Object.fromEntries(this.#cache);\n }\n\n /**\n * Persist the current cache state\n */\n #persistCache(): void {\n this.#updateState(Object.fromEntries(this.#cache));\n }\n\n /**\n * Evict oldest entries if cache exceeds max size\n */\n #evictEntries(): void {\n if (this.#cache.size <= this.#maxCacheSize) {\n return;\n }\n\n const entriesToRemove = this.#cache.size - this.#maxCacheSize;\n let count = 0;\n // Delete the oldest entries (Map maintains insertion order)\n for (const key of this.#cache.keys()) {\n if (count >= entriesToRemove) {\n break;\n }\n this.#cache.delete(key);\n count += 1;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.d.cts","sourceRoot":"","sources":["../src/CacheManager.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAC1B,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF;;;;GAIG;AACH,qBAAa,YAAY,CAAC,CAAC;;IASzB;;;;;;;;OAQG;gBACS,EACV,QAAc,EAAE,oBAAoB;IACpC,YAAkB,EAClB,YAAiB,EACjB,WAAW,GACZ,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAQzB;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB;;;;OAIG;IACH,MAAM,IAAI,MAAM;IAIhB;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKjC;;;;OAIG;IACH,UAAU,IAAI,MAAM;IAIpB;;;;OAIG;IACH,OAAO,IAAI,MAAM;IAIjB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAkB/B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAU/B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQ5B;;;;OAIG;IACH,IAAI,IAAI,MAAM,EAAE;IAIhB;;;;;OAKG;IACH,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CA8B/C"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic cache entry type that wraps the data with a timestamp
|
|
3
|
+
*/
|
|
4
|
+
export type CacheEntry<T> = {
|
|
5
|
+
data: T;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Configuration options for CacheManager
|
|
10
|
+
*/
|
|
11
|
+
export type CacheManagerOptions<T> = {
|
|
12
|
+
cacheTTL?: number;
|
|
13
|
+
maxCacheSize?: number;
|
|
14
|
+
initialCache?: Record<string, CacheEntry<T>>;
|
|
15
|
+
updateState: (cache: Record<string, CacheEntry<T>>) => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Generic cache manager with TTL and size limit support
|
|
19
|
+
*
|
|
20
|
+
* @template T - The type of data to cache
|
|
21
|
+
*/
|
|
22
|
+
export declare class CacheManager<T> {
|
|
23
|
+
#private;
|
|
24
|
+
/**
|
|
25
|
+
* Constructor for CacheManager
|
|
26
|
+
*
|
|
27
|
+
* @param options - Cache configuration options
|
|
28
|
+
* @param options.cacheTTL - Time to live in seconds for cached entries
|
|
29
|
+
* @param options.maxCacheSize - Maximum number of entries in the cache
|
|
30
|
+
* @param options.initialCache - Initial cache state
|
|
31
|
+
* @param options.updateState - Function to update the state when cache changes
|
|
32
|
+
*/
|
|
33
|
+
constructor({ cacheTTL, // 5 minutes default
|
|
34
|
+
maxCacheSize, initialCache, updateState, }: CacheManagerOptions<T>);
|
|
35
|
+
/**
|
|
36
|
+
* Set the time-to-live for cached entries
|
|
37
|
+
*
|
|
38
|
+
* @param ttl - The TTL in seconds
|
|
39
|
+
*/
|
|
40
|
+
setTTL(ttl: number): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get the current TTL setting
|
|
43
|
+
*
|
|
44
|
+
* @returns The TTL in seconds
|
|
45
|
+
*/
|
|
46
|
+
getTTL(): number;
|
|
47
|
+
/**
|
|
48
|
+
* Set the maximum cache size
|
|
49
|
+
*
|
|
50
|
+
* @param maxSize - The maximum cache size
|
|
51
|
+
*/
|
|
52
|
+
setMaxSize(maxSize: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Get the current maximum cache size
|
|
55
|
+
*
|
|
56
|
+
* @returns The maximum cache size
|
|
57
|
+
*/
|
|
58
|
+
getMaxSize(): number;
|
|
59
|
+
/**
|
|
60
|
+
* Get the current cache size
|
|
61
|
+
*
|
|
62
|
+
* @returns The current number of entries in the cache
|
|
63
|
+
*/
|
|
64
|
+
getSize(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Clear the cache
|
|
67
|
+
*/
|
|
68
|
+
clear(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Get a cached result if it exists and is not expired
|
|
71
|
+
*
|
|
72
|
+
* @param key - The cache key
|
|
73
|
+
* @returns The cached data or undefined if not found or expired
|
|
74
|
+
*/
|
|
75
|
+
get(key: string): T | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Add an entry to the cache, evicting oldest entries if necessary
|
|
78
|
+
*
|
|
79
|
+
* @param key - The cache key
|
|
80
|
+
* @param data - The data to cache
|
|
81
|
+
*/
|
|
82
|
+
set(key: string, data: T): void;
|
|
83
|
+
/**
|
|
84
|
+
* Delete a specific entry from the cache
|
|
85
|
+
*
|
|
86
|
+
* @param key - The cache key
|
|
87
|
+
* @returns True if an entry was deleted
|
|
88
|
+
*/
|
|
89
|
+
delete(key: string): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Get all keys in the cache
|
|
92
|
+
*
|
|
93
|
+
* @returns Array of cache keys
|
|
94
|
+
*/
|
|
95
|
+
keys(): string[];
|
|
96
|
+
/**
|
|
97
|
+
* Get all entries in the cache (including expired ones)
|
|
98
|
+
* Useful for debugging or persistence
|
|
99
|
+
*
|
|
100
|
+
* @returns Record of all cache entries
|
|
101
|
+
*/
|
|
102
|
+
getAllEntries(): Record<string, CacheEntry<T>>;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=CacheManager.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.d.mts","sourceRoot":"","sources":["../src/CacheManager.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAC1B,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF;;;;GAIG;AACH,qBAAa,YAAY,CAAC,CAAC;;IASzB;;;;;;;;OAQG;gBACS,EACV,QAAc,EAAE,oBAAoB;IACpC,YAAkB,EAClB,YAAiB,EACjB,WAAW,GACZ,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAQzB;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB;;;;OAIG;IACH,MAAM,IAAI,MAAM;IAIhB;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKjC;;;;OAIG;IACH,UAAU,IAAI,MAAM;IAIpB;;;;OAIG;IACH,OAAO,IAAI,MAAM;IAIjB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAkB/B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAU/B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQ5B;;;;OAIG;IACH,IAAI,IAAI,MAAM,EAAE;IAIhB;;;;;OAKG;IACH,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CA8B/C"}
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
12
|
var _CacheManager_instances, _CacheManager_cacheTTL, _CacheManager_maxCacheSize, _CacheManager_cache, _CacheManager_updateState, _CacheManager_persistCache, _CacheManager_evictEntries;
|
|
13
|
-
import { fetchTimeNow } from
|
|
13
|
+
import { fetchTimeNow } from "./utils.mjs";
|
|
14
14
|
/**
|
|
15
15
|
* Generic cache manager with TTL and size limit support
|
|
16
16
|
*
|
|
@@ -170,4 +170,4 @@ _CacheManager_cacheTTL = new WeakMap(), _CacheManager_maxCacheSize = new WeakMap
|
|
|
170
170
|
count += 1;
|
|
171
171
|
}
|
|
172
172
|
};
|
|
173
|
-
//# sourceMappingURL=CacheManager.
|
|
173
|
+
//# sourceMappingURL=CacheManager.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.mjs","sourceRoot":"","sources":["../src/CacheManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { fetchTimeNow } from './utils.js';\n\n/**\n * Generic cache entry type that wraps the data with a timestamp\n */\nexport type CacheEntry<T> = {\n data: T;\n timestamp: number;\n};\n\n/**\n * Configuration options for CacheManager\n */\nexport type CacheManagerOptions<T> = {\n cacheTTL?: number;\n maxCacheSize?: number;\n initialCache?: Record<string, CacheEntry<T>>;\n updateState: (cache: Record<string, CacheEntry<T>>) => void;\n};\n\n/**\n * Generic cache manager with TTL and size limit support\n *\n * @template T - The type of data to cache\n */\nexport class CacheManager<T> {\n #cacheTTL: number;\n\n #maxCacheSize: number;\n\n readonly #cache: Map<string, CacheEntry<T>>;\n\n readonly #updateState: (cache: Record<string, CacheEntry<T>>) => void;\n\n /**\n * Constructor for CacheManager\n *\n * @param options - Cache configuration options\n * @param options.cacheTTL - Time to live in seconds for cached entries\n * @param options.maxCacheSize - Maximum number of entries in the cache\n * @param options.initialCache - Initial cache state\n * @param options.updateState - Function to update the state when cache changes\n */\n constructor({\n cacheTTL = 300, // 5 minutes default\n maxCacheSize = 100,\n initialCache = {},\n updateState,\n }: CacheManagerOptions<T>) {\n this.#cacheTTL = cacheTTL;\n this.#maxCacheSize = maxCacheSize;\n this.#cache = new Map(Object.entries(initialCache));\n this.#updateState = updateState;\n this.#evictEntries();\n }\n\n /**\n * Set the time-to-live for cached entries\n *\n * @param ttl - The TTL in seconds\n */\n setTTL(ttl: number): void {\n this.#cacheTTL = ttl;\n }\n\n /**\n * Get the current TTL setting\n *\n * @returns The TTL in seconds\n */\n getTTL(): number {\n return this.#cacheTTL;\n }\n\n /**\n * Set the maximum cache size\n *\n * @param maxSize - The maximum cache size\n */\n setMaxSize(maxSize: number): void {\n this.#maxCacheSize = maxSize;\n this.#evictEntries();\n }\n\n /**\n * Get the current maximum cache size\n *\n * @returns The maximum cache size\n */\n getMaxSize(): number {\n return this.#maxCacheSize;\n }\n\n /**\n * Get the current cache size\n *\n * @returns The current number of entries in the cache\n */\n getSize(): number {\n return this.#cache.size;\n }\n\n /**\n * Clear the cache\n */\n clear(): void {\n this.#cache.clear();\n this.#persistCache();\n }\n\n /**\n * Get a cached result if it exists and is not expired\n *\n * @param key - The cache key\n * @returns The cached data or undefined if not found or expired\n */\n get(key: string): T | undefined {\n const cacheEntry = this.#cache.get(key);\n if (!cacheEntry) {\n return undefined;\n }\n\n // Check if the entry is expired\n const now = fetchTimeNow();\n if (now - cacheEntry.timestamp > this.#cacheTTL) {\n // Entry expired, remove it from cache\n this.#cache.delete(key);\n this.#persistCache();\n return undefined;\n }\n\n return cacheEntry.data;\n }\n\n /**\n * Add an entry to the cache, evicting oldest entries if necessary\n *\n * @param key - The cache key\n * @param data - The data to cache\n */\n set(key: string, data: T): void {\n this.#cache.set(key, {\n data,\n timestamp: fetchTimeNow(),\n });\n\n this.#evictEntries();\n this.#persistCache();\n }\n\n /**\n * Delete a specific entry from the cache\n *\n * @param key - The cache key\n * @returns True if an entry was deleted\n */\n delete(key: string): boolean {\n const result = this.#cache.delete(key);\n if (result) {\n this.#persistCache();\n }\n return result;\n }\n\n /**\n * Get all keys in the cache\n *\n * @returns Array of cache keys\n */\n keys(): string[] {\n return Array.from(this.#cache.keys());\n }\n\n /**\n * Get all entries in the cache (including expired ones)\n * Useful for debugging or persistence\n *\n * @returns Record of all cache entries\n */\n getAllEntries(): Record<string, CacheEntry<T>> {\n return Object.fromEntries(this.#cache);\n }\n\n /**\n * Persist the current cache state\n */\n #persistCache(): void {\n this.#updateState(Object.fromEntries(this.#cache));\n }\n\n /**\n * Evict oldest entries if cache exceeds max size\n */\n #evictEntries(): void {\n if (this.#cache.size <= this.#maxCacheSize) {\n return;\n }\n\n const entriesToRemove = this.#cache.size - this.#maxCacheSize;\n let count = 0;\n // Delete the oldest entries (Map maintains insertion order)\n for (const key of this.#cache.keys()) {\n if (count >= entriesToRemove) {\n break;\n }\n this.#cache.delete(key);\n count += 1;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deepCopyPathTrie = exports.convertListToTrie = exports.matchedPathPrefix = exports.deleteFromTrie = exports.insertToTrie = exports.isTerminal = void 0;
|
|
4
|
+
const utils_js_1 = require("./utils.cjs");
|
|
5
|
+
const isTerminal = (node) => {
|
|
6
|
+
if (!node || typeof node !== 'object') {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
return Object.keys(node).length === 0;
|
|
10
|
+
};
|
|
11
|
+
exports.isTerminal = isTerminal;
|
|
12
|
+
/**
|
|
13
|
+
* Insert a URL into the trie.
|
|
14
|
+
*
|
|
15
|
+
* @param url - The URL to insert into the trie.
|
|
16
|
+
* @param pathTrie - The trie to insert the URL into.
|
|
17
|
+
*/
|
|
18
|
+
const insertToTrie = (url, pathTrie) => {
|
|
19
|
+
const { hostname, pathComponents } = (0, utils_js_1.getHostnameAndPathComponents)(url);
|
|
20
|
+
if (pathComponents.length === 0 || !hostname) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const lowerHostname = hostname.toLowerCase();
|
|
24
|
+
if (!pathTrie[lowerHostname]) {
|
|
25
|
+
pathTrie[lowerHostname] = {};
|
|
26
|
+
}
|
|
27
|
+
let curr = pathTrie[lowerHostname];
|
|
28
|
+
for (let i = 0; i < pathComponents.length; i++) {
|
|
29
|
+
const pathComponent = pathComponents[i];
|
|
30
|
+
const isLast = i === pathComponents.length - 1;
|
|
31
|
+
const exists = curr[pathComponent] !== undefined;
|
|
32
|
+
if (exists) {
|
|
33
|
+
if (!isLast && (0, exports.isTerminal)(curr[pathComponent])) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (isLast) {
|
|
37
|
+
// Prune descendants if the current path component is not terminal
|
|
38
|
+
if (!(0, exports.isTerminal)(curr[pathComponent])) {
|
|
39
|
+
curr[pathComponent] = {};
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
curr = curr[pathComponent];
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (isLast) {
|
|
47
|
+
curr[pathComponent] = {};
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const next = {};
|
|
51
|
+
curr[pathComponent] = next;
|
|
52
|
+
curr = next;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.insertToTrie = insertToTrie;
|
|
56
|
+
/**
|
|
57
|
+
* Delete a URL from the trie.
|
|
58
|
+
*
|
|
59
|
+
* @param url - The URL to delete from the trie.
|
|
60
|
+
* @param pathTrie - The trie to delete the URL from.
|
|
61
|
+
*/
|
|
62
|
+
const deleteFromTrie = (url, pathTrie) => {
|
|
63
|
+
const { hostname, pathComponents } = (0, utils_js_1.getHostnameAndPathComponents)(url);
|
|
64
|
+
const lowerHostname = hostname.toLowerCase();
|
|
65
|
+
if (pathComponents.length === 0 || !pathTrie[lowerHostname]) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const pathToNode = [
|
|
69
|
+
{ node: pathTrie, key: lowerHostname },
|
|
70
|
+
];
|
|
71
|
+
let curr = pathTrie[lowerHostname];
|
|
72
|
+
for (const pathComponent of pathComponents) {
|
|
73
|
+
if (!curr[pathComponent]) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
pathToNode.push({ node: curr, key: pathComponent });
|
|
77
|
+
curr = curr[pathComponent];
|
|
78
|
+
}
|
|
79
|
+
const lastEntry = pathToNode[pathToNode.length - 1];
|
|
80
|
+
delete lastEntry.node[lastEntry.key];
|
|
81
|
+
for (let i = pathToNode.length - 2; i >= 0; i--) {
|
|
82
|
+
const { node, key } = pathToNode[i];
|
|
83
|
+
if ((0, exports.isTerminal)(node[key])) {
|
|
84
|
+
delete node[key];
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
exports.deleteFromTrie = deleteFromTrie;
|
|
92
|
+
/**
|
|
93
|
+
* Get the concatenated hostname and path components all the way down to the
|
|
94
|
+
* terminal node in the trie that is prefixed in the passed URL. It will only
|
|
95
|
+
* return a string if the terminal node in the trie is contained in the passed
|
|
96
|
+
* URL.
|
|
97
|
+
*
|
|
98
|
+
* @param url - The URL to check.
|
|
99
|
+
* @param pathTrie - The trie to check the URL in.
|
|
100
|
+
* @returns The matched path prefix, or null if no match is found.
|
|
101
|
+
*/
|
|
102
|
+
const matchedPathPrefix = (url, pathTrie) => {
|
|
103
|
+
const { hostname, pathComponents } = (0, utils_js_1.getHostnameAndPathComponents)(url);
|
|
104
|
+
const lowerHostname = hostname.toLowerCase();
|
|
105
|
+
if (pathComponents.length === 0 || !hostname || !pathTrie[lowerHostname]) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
let matchedPath = `${hostname}/`;
|
|
109
|
+
let curr = pathTrie[lowerHostname];
|
|
110
|
+
for (const pathComponent of pathComponents) {
|
|
111
|
+
if (!curr[pathComponent]) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
curr = curr[pathComponent];
|
|
115
|
+
// If we've reached a terminal node, then we can return the matched path.
|
|
116
|
+
if ((0, exports.isTerminal)(curr)) {
|
|
117
|
+
matchedPath += pathComponent;
|
|
118
|
+
return matchedPath;
|
|
119
|
+
}
|
|
120
|
+
matchedPath += `${pathComponent}/`;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
};
|
|
124
|
+
exports.matchedPathPrefix = matchedPathPrefix;
|
|
125
|
+
/**
|
|
126
|
+
* Converts a list ofpaths into a PathTrie structure. This assumes that the
|
|
127
|
+
* entries are only hostname+pathname format.
|
|
128
|
+
*
|
|
129
|
+
* @param paths - Array of hostname+pathname
|
|
130
|
+
* @returns PathTrie structure for efficient path checking
|
|
131
|
+
*/
|
|
132
|
+
const convertListToTrie = (paths = []) => {
|
|
133
|
+
const pathTrie = {};
|
|
134
|
+
if (!paths || !Array.isArray(paths)) {
|
|
135
|
+
return pathTrie;
|
|
136
|
+
}
|
|
137
|
+
for (const path of paths) {
|
|
138
|
+
(0, exports.insertToTrie)(path, pathTrie);
|
|
139
|
+
}
|
|
140
|
+
return pathTrie;
|
|
141
|
+
};
|
|
142
|
+
exports.convertListToTrie = convertListToTrie;
|
|
143
|
+
/**
|
|
144
|
+
* Creates a deep copy of a PathNode structure.
|
|
145
|
+
*
|
|
146
|
+
* @param original - The original PathNode to copy.
|
|
147
|
+
* @returns A deep copy of the PathNode.
|
|
148
|
+
*/
|
|
149
|
+
const deepCopyPathNode = (original) => {
|
|
150
|
+
const copy = {};
|
|
151
|
+
for (const [key, childNode] of Object.entries(original)) {
|
|
152
|
+
copy[key] = deepCopyPathNode(childNode);
|
|
153
|
+
}
|
|
154
|
+
return copy;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Creates a deep copy of a PathTrie structure.
|
|
158
|
+
*
|
|
159
|
+
* @param original - The original PathTrie to copy.
|
|
160
|
+
* @returns A deep copy of the PathTrie.
|
|
161
|
+
*/
|
|
162
|
+
const deepCopyPathTrie = (original) => {
|
|
163
|
+
if (!original) {
|
|
164
|
+
return {};
|
|
165
|
+
}
|
|
166
|
+
return deepCopyPathNode(original);
|
|
167
|
+
};
|
|
168
|
+
exports.deepCopyPathTrie = deepCopyPathTrie;
|
|
169
|
+
//# sourceMappingURL=PathTrie.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PathTrie.cjs","sourceRoot":"","sources":["../src/PathTrie.ts"],"names":[],"mappings":"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","sourcesContent":["import { getHostnameAndPathComponents } from './utils.js';\n\nexport type PathNode = {\n [key: string]: PathNode;\n};\n\nexport type PathTrie = Record<string, PathNode>;\n\nexport const isTerminal = (node: PathNode | undefined): boolean => {\n if (!node || typeof node !== 'object') {\n return false;\n }\n return Object.keys(node).length === 0;\n};\n\n/**\n * Insert a URL into the trie.\n *\n * @param url - The URL to insert into the trie.\n * @param pathTrie - The trie to insert the URL into.\n */\nexport const insertToTrie = (url: string, pathTrie: PathTrie) => {\n const { hostname, pathComponents } = getHostnameAndPathComponents(url);\n\n if (pathComponents.length === 0 || !hostname) {\n return;\n }\n\n const lowerHostname = hostname.toLowerCase();\n if (!pathTrie[lowerHostname]) {\n pathTrie[lowerHostname] = {} as PathNode;\n }\n\n let curr: PathNode = pathTrie[lowerHostname];\n for (let i = 0; i < pathComponents.length; i++) {\n const pathComponent = pathComponents[i];\n const isLast = i === pathComponents.length - 1;\n const exists = curr[pathComponent] !== undefined;\n\n if (exists) {\n if (!isLast && isTerminal(curr[pathComponent])) {\n return;\n }\n\n if (isLast) {\n // Prune descendants if the current path component is not terminal\n if (!isTerminal(curr[pathComponent])) {\n curr[pathComponent] = {};\n }\n return;\n }\n curr = curr[pathComponent];\n continue;\n }\n\n if (isLast) {\n curr[pathComponent] = {};\n return;\n }\n const next: PathNode = {};\n curr[pathComponent] = next;\n curr = next;\n }\n};\n\n/**\n * Delete a URL from the trie.\n *\n * @param url - The URL to delete from the trie.\n * @param pathTrie - The trie to delete the URL from.\n */\nexport const deleteFromTrie = (url: string, pathTrie: PathTrie) => {\n const { hostname, pathComponents } = getHostnameAndPathComponents(url);\n\n const lowerHostname = hostname.toLowerCase();\n if (pathComponents.length === 0 || !pathTrie[lowerHostname]) {\n return;\n }\n\n const pathToNode: { node: PathNode; key: string }[] = [\n { node: pathTrie, key: lowerHostname },\n ];\n let curr: PathNode = pathTrie[lowerHostname];\n for (const pathComponent of pathComponents) {\n if (!curr[pathComponent]) {\n return;\n }\n\n pathToNode.push({ node: curr, key: pathComponent });\n curr = curr[pathComponent];\n }\n\n const lastEntry = pathToNode[pathToNode.length - 1];\n delete lastEntry.node[lastEntry.key];\n for (let i = pathToNode.length - 2; i >= 0; i--) {\n const { node, key } = pathToNode[i];\n if (isTerminal(node[key])) {\n delete node[key];\n } else {\n break;\n }\n }\n};\n\n/**\n * Get the concatenated hostname and path components all the way down to the\n * terminal node in the trie that is prefixed in the passed URL. It will only\n * return a string if the terminal node in the trie is contained in the passed\n * URL.\n *\n * @param url - The URL to check.\n * @param pathTrie - The trie to check the URL in.\n * @returns The matched path prefix, or null if no match is found.\n */\nexport const matchedPathPrefix = (\n url: string,\n pathTrie: PathTrie,\n): string | null => {\n const { hostname, pathComponents } = getHostnameAndPathComponents(url);\n\n const lowerHostname = hostname.toLowerCase();\n if (pathComponents.length === 0 || !hostname || !pathTrie[lowerHostname]) {\n return null;\n }\n\n let matchedPath = `${hostname}/`;\n let curr: PathNode = pathTrie[lowerHostname];\n for (const pathComponent of pathComponents) {\n if (!curr[pathComponent]) {\n return null;\n }\n curr = curr[pathComponent];\n // If we've reached a terminal node, then we can return the matched path.\n if (isTerminal(curr)) {\n matchedPath += pathComponent;\n return matchedPath;\n }\n matchedPath += `${pathComponent}/`;\n }\n return null;\n};\n\n/**\n * Converts a list ofpaths into a PathTrie structure. This assumes that the\n * entries are only hostname+pathname format.\n *\n * @param paths - Array of hostname+pathname\n * @returns PathTrie structure for efficient path checking\n */\nexport const convertListToTrie = (paths: string[] = []): PathTrie => {\n const pathTrie: PathTrie = {};\n if (!paths || !Array.isArray(paths)) {\n return pathTrie;\n }\n for (const path of paths) {\n insertToTrie(path, pathTrie);\n }\n return pathTrie;\n};\n\n/**\n * Creates a deep copy of a PathNode structure.\n *\n * @param original - The original PathNode to copy.\n * @returns A deep copy of the PathNode.\n */\nconst deepCopyPathNode = (original: PathNode): PathNode => {\n const copy: PathNode = {};\n\n for (const [key, childNode] of Object.entries(original)) {\n copy[key] = deepCopyPathNode(childNode);\n }\n\n return copy;\n};\n\n/**\n * Creates a deep copy of a PathTrie structure.\n *\n * @param original - The original PathTrie to copy.\n * @returns A deep copy of the PathTrie.\n */\nexport const deepCopyPathTrie = (\n original: PathTrie | undefined | null,\n): PathTrie => {\n if (!original) {\n return {};\n }\n return deepCopyPathNode(original) as PathTrie;\n};\n"]}
|
|
@@ -43,4 +43,4 @@ export declare const convertListToTrie: (paths?: string[]) => PathTrie;
|
|
|
43
43
|
* @returns A deep copy of the PathTrie.
|
|
44
44
|
*/
|
|
45
45
|
export declare const deepCopyPathTrie: (original: PathTrie | undefined | null) => PathTrie;
|
|
46
|
-
//# sourceMappingURL=PathTrie.d.
|
|
46
|
+
//# sourceMappingURL=PathTrie.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PathTrie.d.cts","sourceRoot":"","sources":["../src/PathTrie.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,UAAU,SAAU,QAAQ,GAAG,SAAS,KAAG,OAKvD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,YAAY,QAAQ,SA0C3D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAS,MAAM,YAAY,QAAQ,SA+B7D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,QACvB,MAAM,YACD,QAAQ,KACjB,MAAM,GAAG,IAuBX,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,WAAW,MAAM,EAAE,KAAQ,QASxD,CAAC;AAkBF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aACjB,QAAQ,GAAG,SAAS,GAAG,IAAI,KACpC,QAKF,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type PathNode = {
|
|
2
|
+
[key: string]: PathNode;
|
|
3
|
+
};
|
|
4
|
+
export type PathTrie = Record<string, PathNode>;
|
|
5
|
+
export declare const isTerminal: (node: PathNode | undefined) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Insert a URL into the trie.
|
|
8
|
+
*
|
|
9
|
+
* @param url - The URL to insert into the trie.
|
|
10
|
+
* @param pathTrie - The trie to insert the URL into.
|
|
11
|
+
*/
|
|
12
|
+
export declare const insertToTrie: (url: string, pathTrie: PathTrie) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Delete a URL from the trie.
|
|
15
|
+
*
|
|
16
|
+
* @param url - The URL to delete from the trie.
|
|
17
|
+
* @param pathTrie - The trie to delete the URL from.
|
|
18
|
+
*/
|
|
19
|
+
export declare const deleteFromTrie: (url: string, pathTrie: PathTrie) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Get the concatenated hostname and path components all the way down to the
|
|
22
|
+
* terminal node in the trie that is prefixed in the passed URL. It will only
|
|
23
|
+
* return a string if the terminal node in the trie is contained in the passed
|
|
24
|
+
* URL.
|
|
25
|
+
*
|
|
26
|
+
* @param url - The URL to check.
|
|
27
|
+
* @param pathTrie - The trie to check the URL in.
|
|
28
|
+
* @returns The matched path prefix, or null if no match is found.
|
|
29
|
+
*/
|
|
30
|
+
export declare const matchedPathPrefix: (url: string, pathTrie: PathTrie) => string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Converts a list ofpaths into a PathTrie structure. This assumes that the
|
|
33
|
+
* entries are only hostname+pathname format.
|
|
34
|
+
*
|
|
35
|
+
* @param paths - Array of hostname+pathname
|
|
36
|
+
* @returns PathTrie structure for efficient path checking
|
|
37
|
+
*/
|
|
38
|
+
export declare const convertListToTrie: (paths?: string[]) => PathTrie;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a deep copy of a PathTrie structure.
|
|
41
|
+
*
|
|
42
|
+
* @param original - The original PathTrie to copy.
|
|
43
|
+
* @returns A deep copy of the PathTrie.
|
|
44
|
+
*/
|
|
45
|
+
export declare const deepCopyPathTrie: (original: PathTrie | undefined | null) => PathTrie;
|
|
46
|
+
//# sourceMappingURL=PathTrie.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PathTrie.d.mts","sourceRoot":"","sources":["../src/PathTrie.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,UAAU,SAAU,QAAQ,GAAG,SAAS,KAAG,OAKvD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,YAAY,QAAQ,SA0C3D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAS,MAAM,YAAY,QAAQ,SA+B7D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,QACvB,MAAM,YACD,QAAQ,KACjB,MAAM,GAAG,IAuBX,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,WAAW,MAAM,EAAE,KAAQ,QASxD,CAAC;AAkBF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aACjB,QAAQ,GAAG,SAAS,GAAG,IAAI,KACpC,QAKF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getHostnameAndPathComponents } from
|
|
1
|
+
import { getHostnameAndPathComponents } from "./utils.mjs";
|
|
2
2
|
export const isTerminal = (node) => {
|
|
3
3
|
if (!node || typeof node !== 'object') {
|
|
4
4
|
return false;
|
|
@@ -157,4 +157,4 @@ export const deepCopyPathTrie = (original) => {
|
|
|
157
157
|
}
|
|
158
158
|
return deepCopyPathNode(original);
|
|
159
159
|
};
|
|
160
|
-
//# sourceMappingURL=PathTrie.
|
|
160
|
+
//# sourceMappingURL=PathTrie.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PathTrie.mjs","sourceRoot":"","sources":["../src/PathTrie.ts"],"names":[],"mappings":"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","sourcesContent":["import { getHostnameAndPathComponents } from './utils.js';\n\nexport type PathNode = {\n [key: string]: PathNode;\n};\n\nexport type PathTrie = Record<string, PathNode>;\n\nexport const isTerminal = (node: PathNode | undefined): boolean => {\n if (!node || typeof node !== 'object') {\n return false;\n }\n return Object.keys(node).length === 0;\n};\n\n/**\n * Insert a URL into the trie.\n *\n * @param url - The URL to insert into the trie.\n * @param pathTrie - The trie to insert the URL into.\n */\nexport const insertToTrie = (url: string, pathTrie: PathTrie) => {\n const { hostname, pathComponents } = getHostnameAndPathComponents(url);\n\n if (pathComponents.length === 0 || !hostname) {\n return;\n }\n\n const lowerHostname = hostname.toLowerCase();\n if (!pathTrie[lowerHostname]) {\n pathTrie[lowerHostname] = {} as PathNode;\n }\n\n let curr: PathNode = pathTrie[lowerHostname];\n for (let i = 0; i < pathComponents.length; i++) {\n const pathComponent = pathComponents[i];\n const isLast = i === pathComponents.length - 1;\n const exists = curr[pathComponent] !== undefined;\n\n if (exists) {\n if (!isLast && isTerminal(curr[pathComponent])) {\n return;\n }\n\n if (isLast) {\n // Prune descendants if the current path component is not terminal\n if (!isTerminal(curr[pathComponent])) {\n curr[pathComponent] = {};\n }\n return;\n }\n curr = curr[pathComponent];\n continue;\n }\n\n if (isLast) {\n curr[pathComponent] = {};\n return;\n }\n const next: PathNode = {};\n curr[pathComponent] = next;\n curr = next;\n }\n};\n\n/**\n * Delete a URL from the trie.\n *\n * @param url - The URL to delete from the trie.\n * @param pathTrie - The trie to delete the URL from.\n */\nexport const deleteFromTrie = (url: string, pathTrie: PathTrie) => {\n const { hostname, pathComponents } = getHostnameAndPathComponents(url);\n\n const lowerHostname = hostname.toLowerCase();\n if (pathComponents.length === 0 || !pathTrie[lowerHostname]) {\n return;\n }\n\n const pathToNode: { node: PathNode; key: string }[] = [\n { node: pathTrie, key: lowerHostname },\n ];\n let curr: PathNode = pathTrie[lowerHostname];\n for (const pathComponent of pathComponents) {\n if (!curr[pathComponent]) {\n return;\n }\n\n pathToNode.push({ node: curr, key: pathComponent });\n curr = curr[pathComponent];\n }\n\n const lastEntry = pathToNode[pathToNode.length - 1];\n delete lastEntry.node[lastEntry.key];\n for (let i = pathToNode.length - 2; i >= 0; i--) {\n const { node, key } = pathToNode[i];\n if (isTerminal(node[key])) {\n delete node[key];\n } else {\n break;\n }\n }\n};\n\n/**\n * Get the concatenated hostname and path components all the way down to the\n * terminal node in the trie that is prefixed in the passed URL. It will only\n * return a string if the terminal node in the trie is contained in the passed\n * URL.\n *\n * @param url - The URL to check.\n * @param pathTrie - The trie to check the URL in.\n * @returns The matched path prefix, or null if no match is found.\n */\nexport const matchedPathPrefix = (\n url: string,\n pathTrie: PathTrie,\n): string | null => {\n const { hostname, pathComponents } = getHostnameAndPathComponents(url);\n\n const lowerHostname = hostname.toLowerCase();\n if (pathComponents.length === 0 || !hostname || !pathTrie[lowerHostname]) {\n return null;\n }\n\n let matchedPath = `${hostname}/`;\n let curr: PathNode = pathTrie[lowerHostname];\n for (const pathComponent of pathComponents) {\n if (!curr[pathComponent]) {\n return null;\n }\n curr = curr[pathComponent];\n // If we've reached a terminal node, then we can return the matched path.\n if (isTerminal(curr)) {\n matchedPath += pathComponent;\n return matchedPath;\n }\n matchedPath += `${pathComponent}/`;\n }\n return null;\n};\n\n/**\n * Converts a list ofpaths into a PathTrie structure. This assumes that the\n * entries are only hostname+pathname format.\n *\n * @param paths - Array of hostname+pathname\n * @returns PathTrie structure for efficient path checking\n */\nexport const convertListToTrie = (paths: string[] = []): PathTrie => {\n const pathTrie: PathTrie = {};\n if (!paths || !Array.isArray(paths)) {\n return pathTrie;\n }\n for (const path of paths) {\n insertToTrie(path, pathTrie);\n }\n return pathTrie;\n};\n\n/**\n * Creates a deep copy of a PathNode structure.\n *\n * @param original - The original PathNode to copy.\n * @returns A deep copy of the PathNode.\n */\nconst deepCopyPathNode = (original: PathNode): PathNode => {\n const copy: PathNode = {};\n\n for (const [key, childNode] of Object.entries(original)) {\n copy[key] = deepCopyPathNode(childNode);\n }\n\n return copy;\n};\n\n/**\n * Creates a deep copy of a PathTrie structure.\n *\n * @param original - The original PathTrie to copy.\n * @returns A deep copy of the PathTrie.\n */\nexport const deepCopyPathTrie = (\n original: PathTrie | undefined | null,\n): PathTrie => {\n if (!original) {\n return {};\n }\n return deepCopyPathNode(original) as PathTrie;\n};\n"]}
|