@hedystia/db 2.0.5 → 2.0.7
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/cache/index.mjs +12 -0
- package/dist/cache/index.mjs.map +1 -0
- package/dist/cache/manager.mjs +156 -153
- package/dist/cache/manager.mjs.map +1 -1
- package/dist/cache/memory-store.mjs +113 -111
- package/dist/cache/memory-store.mjs.map +1 -1
- package/dist/cli/commands/migrate.cjs +78 -0
- package/dist/cli/commands/migrate.cjs.map +1 -0
- package/dist/cli/commands/migrate.mjs +83 -0
- package/dist/cli/commands/migrate.mjs.map +1 -0
- package/dist/cli.cjs +36 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +37 -0
- package/dist/cli.mjs.map +1 -1
- package/dist/core/database.cjs +72 -29
- package/dist/core/database.cjs.map +1 -1
- package/dist/core/database.d.cts +65 -0
- package/dist/core/database.d.mts +65 -0
- package/dist/core/database.mjs +88 -34
- package/dist/core/database.mjs.map +1 -1
- package/dist/core/repository.mjs +414 -410
- package/dist/core/repository.mjs.map +1 -1
- package/dist/drivers/driver.mjs +9 -7
- package/dist/drivers/driver.mjs.map +1 -1
- package/dist/drivers/file.mjs +315 -312
- package/dist/drivers/file.mjs.map +1 -1
- package/dist/drivers/index.mjs +15 -6
- package/dist/drivers/index.mjs.map +1 -1
- package/dist/drivers/mysql.mjs +261 -256
- package/dist/drivers/mysql.mjs.map +1 -1
- package/dist/drivers/sql-compiler.mjs +4 -1
- package/dist/drivers/sql-compiler.mjs.map +1 -1
- package/dist/drivers/sqlite.cjs +12 -1
- package/dist/drivers/sqlite.cjs.map +1 -1
- package/dist/drivers/sqlite.mjs +258 -242
- package/dist/drivers/sqlite.mjs.map +1 -1
- package/dist/errors.mjs +48 -64
- package/dist/errors.mjs.map +1 -1
- package/dist/index.mjs +21 -9
- package/dist/index.mjs.map +1 -1
- package/dist/schema/column.mjs +155 -157
- package/dist/schema/column.mjs.map +1 -1
- package/dist/schema/columns/index.mjs +103 -171
- package/dist/schema/columns/index.mjs.map +1 -1
- package/dist/schema/index.mjs +15 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/schema/registry.mjs +122 -119
- package/dist/schema/registry.mjs.map +1 -1
- package/dist/schema/table.mjs +4 -1
- package/dist/schema/table.mjs.map +1 -1
- package/dist/sync/synchronizer.mjs +2 -1
- package/dist/sync/synchronizer.mjs.map +1 -1
- package/dist/types.d.cts +67 -6
- package/dist/types.d.mts +67 -6
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { __esmMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import "./memory-store.mjs";
|
|
3
|
+
import { init_manager } from "./manager.mjs";
|
|
4
|
+
//#region src/cache/index.ts
|
|
5
|
+
var init_cache = __esmMin((() => {
|
|
6
|
+
init_manager();
|
|
7
|
+
}));
|
|
8
|
+
//#endregion
|
|
9
|
+
init_cache();
|
|
10
|
+
export { init_cache };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/index.ts"],"sourcesContent":["export { CacheManager } from \"./manager\";\nexport { MemoryStore } from \"./memory-store\";\n"],"mappings":";;;;;eAAyC"}
|
package/dist/cache/manager.mjs
CHANGED
|
@@ -1,163 +1,166 @@
|
|
|
1
|
+
import { __esmMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
1
2
|
import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL, init_constants } from "../constants.mjs";
|
|
2
3
|
import { stableStringify } from "../utils/stable-stringify.mjs";
|
|
3
4
|
import { init_utils } from "../utils/index.mjs";
|
|
4
|
-
import { MemoryStore } from "./memory-store.mjs";
|
|
5
|
+
import { MemoryStore, init_memory_store } from "./memory-store.mjs";
|
|
5
6
|
//#region src/cache/manager.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
7
|
+
var CacheManager;
|
|
8
|
+
var init_manager = __esmMin((() => {
|
|
9
|
+
init_constants();
|
|
10
|
+
init_utils();
|
|
11
|
+
init_memory_store();
|
|
12
|
+
CacheManager = class {
|
|
13
|
+
store;
|
|
14
|
+
baseTtl;
|
|
15
|
+
maxTtl;
|
|
16
|
+
enabled;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
if (typeof config === "boolean") {
|
|
19
|
+
this.enabled = config;
|
|
20
|
+
this.baseTtl = DEFAULT_CACHE_TTL;
|
|
21
|
+
this.maxTtl = DEFAULT_CACHE_MAX_TTL;
|
|
22
|
+
this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);
|
|
23
|
+
} else if (config) {
|
|
24
|
+
this.enabled = config.enabled;
|
|
25
|
+
this.baseTtl = config.ttl ?? 6e4;
|
|
26
|
+
this.maxTtl = config.maxTtl ?? 3e5;
|
|
27
|
+
this.store = new MemoryStore(config.maxEntries ?? 1e4);
|
|
28
|
+
} else {
|
|
29
|
+
this.enabled = false;
|
|
30
|
+
this.baseTtl = DEFAULT_CACHE_TTL;
|
|
31
|
+
this.maxTtl = DEFAULT_CACHE_MAX_TTL;
|
|
32
|
+
this.store = new MemoryStore();
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Get a cached query result or execute the query and cache the result
|
|
37
|
+
* @param {string} table - Table name
|
|
38
|
+
* @param {string} method - Method name (find, findFirst, etc.)
|
|
39
|
+
* @param {unknown} options - Query options
|
|
40
|
+
* @param {() => Promise<T>} executor - Function that executes the query
|
|
41
|
+
* @returns {Promise<T>} The query result
|
|
42
|
+
*/
|
|
43
|
+
async getOrSet(table, method, options, executor) {
|
|
44
|
+
if (!this.enabled) return executor();
|
|
45
|
+
const key = this.buildKey(table, method, options);
|
|
46
|
+
const cached = this.store.get(key);
|
|
47
|
+
if (cached !== void 0) {
|
|
48
|
+
this.store.extendTtl(key, this.baseTtl, this.maxTtl);
|
|
49
|
+
return cached;
|
|
50
|
+
}
|
|
51
|
+
const result = await executor();
|
|
52
|
+
this.store.set(key, result, this.baseTtl);
|
|
53
|
+
return result;
|
|
49
54
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
setEntity(table, id, data) {
|
|
61
|
-
if (!this.enabled) return;
|
|
62
|
-
const key = `entity:${table}:${id}`;
|
|
63
|
-
this.store.set(key, data, this.baseTtl);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Get a cached entity by primary key
|
|
67
|
-
* @param {string} table - Table name
|
|
68
|
-
* @param {string | number} id - Primary key value
|
|
69
|
-
* @returns {unknown | undefined} Cached entity or undefined
|
|
70
|
-
*/
|
|
71
|
-
getEntity(table, id) {
|
|
72
|
-
if (!this.enabled) return;
|
|
73
|
-
const key = `entity:${table}:${id}`;
|
|
74
|
-
const result = this.store.get(key);
|
|
75
|
-
if (result !== void 0) this.store.extendTtl(key, this.baseTtl, this.maxTtl);
|
|
76
|
-
return result;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Invalidate all cache entries for a table
|
|
80
|
-
* @param {string} table - Table name
|
|
81
|
-
*/
|
|
82
|
-
invalidateTable(table) {
|
|
83
|
-
if (!this.enabled) return;
|
|
84
|
-
this.store.invalidateByPrefix(`query:${table}:`);
|
|
85
|
-
this.store.invalidateByPrefix(`entity:${table}:`);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Invalidate a specific entity cache entry
|
|
89
|
-
* @param {string} table - Table name
|
|
90
|
-
* @param {string | number} id - Primary key value
|
|
91
|
-
*/
|
|
92
|
-
invalidateEntity(table, id) {
|
|
93
|
-
if (!this.enabled) return;
|
|
94
|
-
this.store.delete(`entity:${table}:${id}`);
|
|
95
|
-
this.store.invalidateByPrefix(`query:${table}:`);
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Update an entity in cache if it exists
|
|
99
|
-
* @param {string} table - Table name
|
|
100
|
-
* @param {string | number} id - Primary key value
|
|
101
|
-
* @param {Record<string, unknown>} data - Updated data
|
|
102
|
-
*/
|
|
103
|
-
updateEntity(table, id, data) {
|
|
104
|
-
if (!this.enabled) return;
|
|
105
|
-
const key = `entity:${table}:${id}`;
|
|
106
|
-
const existing = this.store.get(key);
|
|
107
|
-
if (existing && typeof existing === "object") this.store.set(key, {
|
|
108
|
-
...existing,
|
|
109
|
-
...data
|
|
110
|
-
}, this.baseTtl);
|
|
111
|
-
this.store.invalidateByPrefix(`query:${table}:`);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Clear the entire cache
|
|
115
|
-
*/
|
|
116
|
-
clear() {
|
|
117
|
-
this.store.clear();
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Get the number of cached entries
|
|
121
|
-
* @returns {number} Cache size
|
|
122
|
-
*/
|
|
123
|
-
get size() {
|
|
124
|
-
return this.store.size;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Check if caching is enabled
|
|
128
|
-
* @returns {boolean} Whether caching is enabled
|
|
129
|
-
*/
|
|
130
|
-
get isEnabled() {
|
|
131
|
-
return this.enabled;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Get a cached query result or execute the query with per-table cache config override
|
|
135
|
-
* @param {string} table - Table name
|
|
136
|
-
* @param {string} method - Method name (find, findFirst, etc.)
|
|
137
|
-
* @param {unknown} options - Query options
|
|
138
|
-
* @param {() => Promise<T>} executor - Function that executes the query
|
|
139
|
-
* @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config
|
|
140
|
-
* @returns {Promise<T>} The query result
|
|
141
|
-
*/
|
|
142
|
-
async getOrSetWithTableConfig(table, method, options, executor, tableConfig) {
|
|
143
|
-
if (!(tableConfig ? tableConfig.enabled : this.enabled)) return executor();
|
|
144
|
-
const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;
|
|
145
|
-
const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;
|
|
146
|
-
const key = this.buildKey(table, method, options);
|
|
147
|
-
const cached = this.store.get(key);
|
|
148
|
-
if (cached !== void 0) {
|
|
149
|
-
this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);
|
|
150
|
-
return cached;
|
|
55
|
+
/**
|
|
56
|
+
* Set an entity in the cache by primary key
|
|
57
|
+
* @param {string} table - Table name
|
|
58
|
+
* @param {string | number} id - Primary key value
|
|
59
|
+
* @param {unknown} data - Entity data
|
|
60
|
+
*/
|
|
61
|
+
setEntity(table, id, data) {
|
|
62
|
+
if (!this.enabled) return;
|
|
63
|
+
const key = `entity:${table}:${id}`;
|
|
64
|
+
this.store.set(key, data, this.baseTtl);
|
|
151
65
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Get a cached entity by primary key
|
|
68
|
+
* @param {string} table - Table name
|
|
69
|
+
* @param {string | number} id - Primary key value
|
|
70
|
+
* @returns {unknown | undefined} Cached entity or undefined
|
|
71
|
+
*/
|
|
72
|
+
getEntity(table, id) {
|
|
73
|
+
if (!this.enabled) return;
|
|
74
|
+
const key = `entity:${table}:${id}`;
|
|
75
|
+
const result = this.store.get(key);
|
|
76
|
+
if (result !== void 0) this.store.extendTtl(key, this.baseTtl, this.maxTtl);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Invalidate all cache entries for a table
|
|
81
|
+
* @param {string} table - Table name
|
|
82
|
+
*/
|
|
83
|
+
invalidateTable(table) {
|
|
84
|
+
if (!this.enabled) return;
|
|
85
|
+
this.store.invalidateByPrefix(`query:${table}:`);
|
|
86
|
+
this.store.invalidateByPrefix(`entity:${table}:`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Invalidate a specific entity cache entry
|
|
90
|
+
* @param {string} table - Table name
|
|
91
|
+
* @param {string | number} id - Primary key value
|
|
92
|
+
*/
|
|
93
|
+
invalidateEntity(table, id) {
|
|
94
|
+
if (!this.enabled) return;
|
|
95
|
+
this.store.delete(`entity:${table}:${id}`);
|
|
96
|
+
this.store.invalidateByPrefix(`query:${table}:`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Update an entity in cache if it exists
|
|
100
|
+
* @param {string} table - Table name
|
|
101
|
+
* @param {string | number} id - Primary key value
|
|
102
|
+
* @param {Record<string, unknown>} data - Updated data
|
|
103
|
+
*/
|
|
104
|
+
updateEntity(table, id, data) {
|
|
105
|
+
if (!this.enabled) return;
|
|
106
|
+
const key = `entity:${table}:${id}`;
|
|
107
|
+
const existing = this.store.get(key);
|
|
108
|
+
if (existing && typeof existing === "object") this.store.set(key, {
|
|
109
|
+
...existing,
|
|
110
|
+
...data
|
|
111
|
+
}, this.baseTtl);
|
|
112
|
+
this.store.invalidateByPrefix(`query:${table}:`);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Clear the entire cache
|
|
116
|
+
*/
|
|
117
|
+
clear() {
|
|
118
|
+
this.store.clear();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get the number of cached entries
|
|
122
|
+
* @returns {number} Cache size
|
|
123
|
+
*/
|
|
124
|
+
get size() {
|
|
125
|
+
return this.store.size;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Check if caching is enabled
|
|
129
|
+
* @returns {boolean} Whether caching is enabled
|
|
130
|
+
*/
|
|
131
|
+
get isEnabled() {
|
|
132
|
+
return this.enabled;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Get a cached query result or execute the query with per-table cache config override
|
|
136
|
+
* @param {string} table - Table name
|
|
137
|
+
* @param {string} method - Method name (find, findFirst, etc.)
|
|
138
|
+
* @param {unknown} options - Query options
|
|
139
|
+
* @param {() => Promise<T>} executor - Function that executes the query
|
|
140
|
+
* @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config
|
|
141
|
+
* @returns {Promise<T>} The query result
|
|
142
|
+
*/
|
|
143
|
+
async getOrSetWithTableConfig(table, method, options, executor, tableConfig) {
|
|
144
|
+
if (!(tableConfig ? tableConfig.enabled : this.enabled)) return executor();
|
|
145
|
+
const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;
|
|
146
|
+
const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;
|
|
147
|
+
const key = this.buildKey(table, method, options);
|
|
148
|
+
const cached = this.store.get(key);
|
|
149
|
+
if (cached !== void 0) {
|
|
150
|
+
this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);
|
|
151
|
+
return cached;
|
|
152
|
+
}
|
|
153
|
+
const result = await executor();
|
|
154
|
+
this.store.set(key, result, effectiveTtl);
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
buildKey(table, method, options) {
|
|
158
|
+
return `query:${table}:${method}:${stableStringify(options)}`;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}));
|
|
160
162
|
//#endregion
|
|
161
|
-
|
|
163
|
+
init_manager();
|
|
164
|
+
export { CacheManager, init_manager };
|
|
162
165
|
|
|
163
166
|
//# sourceMappingURL=manager.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.mjs","names":[],"sources":["../../src/cache/manager.ts"],"sourcesContent":["import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL } from \"../constants\";\nimport type { CacheConfig } from \"../types\";\nimport { stableStringify } from \"../utils\";\nimport { MemoryStore } from \"./memory-store\";\n\n/**\n * Cache manager that wraps query execution with caching behavior\n */\nexport class CacheManager {\n private store: MemoryStore;\n private baseTtl: number;\n private maxTtl: number;\n private enabled: boolean;\n\n constructor(config?: boolean | CacheConfig) {\n if (typeof config === \"boolean\") {\n this.enabled = config;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);\n } else if (config) {\n this.enabled = config.enabled;\n this.baseTtl = config.ttl ?? DEFAULT_CACHE_TTL;\n this.maxTtl = config.maxTtl ?? DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(config.maxEntries ?? DEFAULT_CACHE_MAX_ENTRIES);\n } else {\n this.enabled = false;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore();\n }\n }\n\n /**\n * Get a cached query result or execute the query and cache the result\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @returns {Promise<T>} The query result\n */\n async getOrSet<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n ): Promise<T> {\n if (!this.enabled) {\n return executor();\n }\n\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, this.baseTtl);\n return result;\n }\n\n /**\n * Set an entity in the cache by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {unknown} data - Entity data\n */\n setEntity(table: string, id: string | number, data: unknown): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n this.store.set(key, data, this.baseTtl);\n }\n\n /**\n * Get a cached entity by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @returns {unknown | undefined} Cached entity or undefined\n */\n getEntity(table: string, id: string | number): unknown | undefined {\n if (!this.enabled) {\n return undefined;\n }\n const key = `entity:${table}:${id}`;\n const result = this.store.get(key);\n if (result !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n }\n return result;\n }\n\n /**\n * Invalidate all cache entries for a table\n * @param {string} table - Table name\n */\n invalidateTable(table: string): void {\n if (!this.enabled) {\n return;\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n this.store.invalidateByPrefix(`entity:${table}:`);\n }\n\n /**\n * Invalidate a specific entity cache entry\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n */\n invalidateEntity(table: string, id: string | number): void {\n if (!this.enabled) {\n return;\n }\n this.store.delete(`entity:${table}:${id}`);\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Update an entity in cache if it exists\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {Record<string, unknown>} data - Updated data\n */\n updateEntity(table: string, id: string | number, data: Record<string, unknown>): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n const existing = this.store.get(key);\n if (existing && typeof existing === \"object\") {\n this.store.set(key, { ...existing, ...data }, this.baseTtl);\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Clear the entire cache\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Cache size\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Check if caching is enabled\n * @returns {boolean} Whether caching is enabled\n */\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Get a cached query result or execute the query with per-table cache config override\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config\n * @returns {Promise<T>} The query result\n */\n async getOrSetWithTableConfig<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n tableConfig?: { enabled: boolean; ttl?: number; maxTtl?: number },\n ): Promise<T> {\n const effectiveEnabled = tableConfig ? tableConfig.enabled : this.enabled;\n if (!effectiveEnabled) {\n return executor();\n }\n\n const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;\n const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, effectiveTtl);\n return result;\n }\n\n private buildKey(table: string, method: string, options: unknown): string {\n return `query:${table}:${method}:${stableStringify(options)}`;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"manager.mjs","names":[],"sources":["../../src/cache/manager.ts"],"sourcesContent":["import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL } from \"../constants\";\nimport type { CacheConfig } from \"../types\";\nimport { stableStringify } from \"../utils\";\nimport { MemoryStore } from \"./memory-store\";\n\n/**\n * Cache manager that wraps query execution with caching behavior\n */\nexport class CacheManager {\n private store: MemoryStore;\n private baseTtl: number;\n private maxTtl: number;\n private enabled: boolean;\n\n constructor(config?: boolean | CacheConfig) {\n if (typeof config === \"boolean\") {\n this.enabled = config;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);\n } else if (config) {\n this.enabled = config.enabled;\n this.baseTtl = config.ttl ?? DEFAULT_CACHE_TTL;\n this.maxTtl = config.maxTtl ?? DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(config.maxEntries ?? DEFAULT_CACHE_MAX_ENTRIES);\n } else {\n this.enabled = false;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore();\n }\n }\n\n /**\n * Get a cached query result or execute the query and cache the result\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @returns {Promise<T>} The query result\n */\n async getOrSet<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n ): Promise<T> {\n if (!this.enabled) {\n return executor();\n }\n\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, this.baseTtl);\n return result;\n }\n\n /**\n * Set an entity in the cache by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {unknown} data - Entity data\n */\n setEntity(table: string, id: string | number, data: unknown): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n this.store.set(key, data, this.baseTtl);\n }\n\n /**\n * Get a cached entity by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @returns {unknown | undefined} Cached entity or undefined\n */\n getEntity(table: string, id: string | number): unknown | undefined {\n if (!this.enabled) {\n return undefined;\n }\n const key = `entity:${table}:${id}`;\n const result = this.store.get(key);\n if (result !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n }\n return result;\n }\n\n /**\n * Invalidate all cache entries for a table\n * @param {string} table - Table name\n */\n invalidateTable(table: string): void {\n if (!this.enabled) {\n return;\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n this.store.invalidateByPrefix(`entity:${table}:`);\n }\n\n /**\n * Invalidate a specific entity cache entry\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n */\n invalidateEntity(table: string, id: string | number): void {\n if (!this.enabled) {\n return;\n }\n this.store.delete(`entity:${table}:${id}`);\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Update an entity in cache if it exists\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {Record<string, unknown>} data - Updated data\n */\n updateEntity(table: string, id: string | number, data: Record<string, unknown>): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n const existing = this.store.get(key);\n if (existing && typeof existing === \"object\") {\n this.store.set(key, { ...existing, ...data }, this.baseTtl);\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Clear the entire cache\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Cache size\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Check if caching is enabled\n * @returns {boolean} Whether caching is enabled\n */\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Get a cached query result or execute the query with per-table cache config override\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config\n * @returns {Promise<T>} The query result\n */\n async getOrSetWithTableConfig<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n tableConfig?: { enabled: boolean; ttl?: number; maxTtl?: number },\n ): Promise<T> {\n const effectiveEnabled = tableConfig ? tableConfig.enabled : this.enabled;\n if (!effectiveEnabled) {\n return executor();\n }\n\n const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;\n const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, effectiveTtl);\n return result;\n }\n\n private buildKey(table: string, method: string, options: unknown): string {\n return `query:${table}:${method}:${stableStringify(options)}`;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,122 +1,124 @@
|
|
|
1
|
+
import { __esmMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
1
2
|
//#region src/cache/memory-store.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
this.maxEntries = maxEntries;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Get a value from cache
|
|
13
|
-
* @param {string} key - Cache key
|
|
14
|
-
* @returns {unknown | undefined} Cached value or undefined
|
|
15
|
-
*/
|
|
16
|
-
get(key) {
|
|
17
|
-
const entry = this.store.get(key);
|
|
18
|
-
if (!entry) return;
|
|
19
|
-
if (Date.now() > entry.expiresAt) {
|
|
20
|
-
this.store.delete(key);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
entry.hitCount++;
|
|
24
|
-
entry.lastAccess = Date.now();
|
|
25
|
-
return entry.value;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Set a value in cache with TTL
|
|
29
|
-
* @param {string} key - Cache key
|
|
30
|
-
* @param {unknown} value - Value to cache
|
|
31
|
-
* @param {number} ttl - Time to live in milliseconds
|
|
32
|
-
*/
|
|
33
|
-
set(key, value, ttl) {
|
|
34
|
-
if (this.store.size >= this.maxEntries) this.evict();
|
|
35
|
-
this.store.set(key, {
|
|
36
|
-
value,
|
|
37
|
-
expiresAt: Date.now() + ttl,
|
|
38
|
-
hitCount: 1,
|
|
39
|
-
lastAccess: Date.now()
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Check if a key exists in cache and is not expired
|
|
44
|
-
* @param {string} key - Cache key
|
|
45
|
-
* @returns {boolean} Whether the key exists
|
|
46
|
-
*/
|
|
47
|
-
has(key) {
|
|
48
|
-
const entry = this.store.get(key);
|
|
49
|
-
if (!entry) return false;
|
|
50
|
-
if (Date.now() > entry.expiresAt) {
|
|
51
|
-
this.store.delete(key);
|
|
52
|
-
return false;
|
|
3
|
+
var MemoryStore;
|
|
4
|
+
var init_memory_store = __esmMin((() => {
|
|
5
|
+
MemoryStore = class {
|
|
6
|
+
store = /* @__PURE__ */ new Map();
|
|
7
|
+
maxEntries;
|
|
8
|
+
constructor(maxEntries = 1e4) {
|
|
9
|
+
this.maxEntries = maxEntries;
|
|
53
10
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Invalidate all cache entries matching a prefix
|
|
65
|
-
* @param {string} prefix - Key prefix
|
|
66
|
-
*/
|
|
67
|
-
invalidateByPrefix(prefix) {
|
|
68
|
-
for (const key of this.store.keys()) if (key.startsWith(prefix)) this.store.delete(key);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Clear all cached entries
|
|
72
|
-
*/
|
|
73
|
-
clear() {
|
|
74
|
-
this.store.clear();
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Get the number of cached entries
|
|
78
|
-
* @returns {number} Number of entries
|
|
79
|
-
*/
|
|
80
|
-
get size() {
|
|
81
|
-
return this.store.size;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Get hit count for a cache key
|
|
85
|
-
* @param {string} key - Cache key
|
|
86
|
-
* @returns {number} Number of hits
|
|
87
|
-
*/
|
|
88
|
-
getHitCount(key) {
|
|
89
|
-
return this.store.get(key)?.hitCount ?? 0;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Extend the TTL of a cache entry based on hit count
|
|
93
|
-
* @param {string} key - Cache key
|
|
94
|
-
* @param {number} baseTtl - Base TTL in milliseconds
|
|
95
|
-
* @param {number} maxTtl - Maximum TTL in milliseconds
|
|
96
|
-
*/
|
|
97
|
-
extendTtl(key, baseTtl, maxTtl) {
|
|
98
|
-
const entry = this.store.get(key);
|
|
99
|
-
if (!entry) return;
|
|
100
|
-
const adaptiveTtl = Math.min(maxTtl, baseTtl * (1 + Math.log2(entry.hitCount + 1)));
|
|
101
|
-
entry.expiresAt = Date.now() + adaptiveTtl;
|
|
102
|
-
}
|
|
103
|
-
evict() {
|
|
104
|
-
let oldestKey = null;
|
|
105
|
-
let oldestAccess = Number.POSITIVE_INFINITY;
|
|
106
|
-
for (const [key, entry] of this.store) {
|
|
11
|
+
/**
|
|
12
|
+
* Get a value from cache
|
|
13
|
+
* @param {string} key - Cache key
|
|
14
|
+
* @returns {unknown | undefined} Cached value or undefined
|
|
15
|
+
*/
|
|
16
|
+
get(key) {
|
|
17
|
+
const entry = this.store.get(key);
|
|
18
|
+
if (!entry) return;
|
|
107
19
|
if (Date.now() > entry.expiresAt) {
|
|
108
20
|
this.store.delete(key);
|
|
109
21
|
return;
|
|
110
22
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
23
|
+
entry.hitCount++;
|
|
24
|
+
entry.lastAccess = Date.now();
|
|
25
|
+
return entry.value;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Set a value in cache with TTL
|
|
29
|
+
* @param {string} key - Cache key
|
|
30
|
+
* @param {unknown} value - Value to cache
|
|
31
|
+
* @param {number} ttl - Time to live in milliseconds
|
|
32
|
+
*/
|
|
33
|
+
set(key, value, ttl) {
|
|
34
|
+
if (this.store.size >= this.maxEntries) this.evict();
|
|
35
|
+
this.store.set(key, {
|
|
36
|
+
value,
|
|
37
|
+
expiresAt: Date.now() + ttl,
|
|
38
|
+
hitCount: 1,
|
|
39
|
+
lastAccess: Date.now()
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a key exists in cache and is not expired
|
|
44
|
+
* @param {string} key - Cache key
|
|
45
|
+
* @returns {boolean} Whether the key exists
|
|
46
|
+
*/
|
|
47
|
+
has(key) {
|
|
48
|
+
const entry = this.store.get(key);
|
|
49
|
+
if (!entry) return false;
|
|
50
|
+
if (Date.now() > entry.expiresAt) {
|
|
51
|
+
this.store.delete(key);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Delete a key from cache
|
|
58
|
+
* @param {string} key - Cache key
|
|
59
|
+
*/
|
|
60
|
+
delete(key) {
|
|
61
|
+
this.store.delete(key);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Invalidate all cache entries matching a prefix
|
|
65
|
+
* @param {string} prefix - Key prefix
|
|
66
|
+
*/
|
|
67
|
+
invalidateByPrefix(prefix) {
|
|
68
|
+
for (const key of this.store.keys()) if (key.startsWith(prefix)) this.store.delete(key);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clear all cached entries
|
|
72
|
+
*/
|
|
73
|
+
clear() {
|
|
74
|
+
this.store.clear();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the number of cached entries
|
|
78
|
+
* @returns {number} Number of entries
|
|
79
|
+
*/
|
|
80
|
+
get size() {
|
|
81
|
+
return this.store.size;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get hit count for a cache key
|
|
85
|
+
* @param {string} key - Cache key
|
|
86
|
+
* @returns {number} Number of hits
|
|
87
|
+
*/
|
|
88
|
+
getHitCount(key) {
|
|
89
|
+
return this.store.get(key)?.hitCount ?? 0;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Extend the TTL of a cache entry based on hit count
|
|
93
|
+
* @param {string} key - Cache key
|
|
94
|
+
* @param {number} baseTtl - Base TTL in milliseconds
|
|
95
|
+
* @param {number} maxTtl - Maximum TTL in milliseconds
|
|
96
|
+
*/
|
|
97
|
+
extendTtl(key, baseTtl, maxTtl) {
|
|
98
|
+
const entry = this.store.get(key);
|
|
99
|
+
if (!entry) return;
|
|
100
|
+
const adaptiveTtl = Math.min(maxTtl, baseTtl * (1 + Math.log2(entry.hitCount + 1)));
|
|
101
|
+
entry.expiresAt = Date.now() + adaptiveTtl;
|
|
102
|
+
}
|
|
103
|
+
evict() {
|
|
104
|
+
let oldestKey = null;
|
|
105
|
+
let oldestAccess = Number.POSITIVE_INFINITY;
|
|
106
|
+
for (const [key, entry] of this.store) {
|
|
107
|
+
if (Date.now() > entry.expiresAt) {
|
|
108
|
+
this.store.delete(key);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (entry.lastAccess < oldestAccess) {
|
|
112
|
+
oldestAccess = entry.lastAccess;
|
|
113
|
+
oldestKey = key;
|
|
114
|
+
}
|
|
114
115
|
}
|
|
116
|
+
if (oldestKey) this.store.delete(oldestKey);
|
|
115
117
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
};
|
|
118
|
+
};
|
|
119
|
+
}));
|
|
119
120
|
//#endregion
|
|
120
|
-
|
|
121
|
+
init_memory_store();
|
|
122
|
+
export { MemoryStore, init_memory_store };
|
|
121
123
|
|
|
122
124
|
//# sourceMappingURL=memory-store.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.mjs","names":[],"sources":["../../src/cache/memory-store.ts"],"sourcesContent":["interface CacheEntry {\n value: unknown;\n expiresAt: number;\n hitCount: number;\n lastAccess: number;\n}\n\n/**\n * In-memory cache store with TTL and hit-count tracking\n */\nexport class MemoryStore {\n private store = new Map<string, CacheEntry>();\n private maxEntries: number;\n\n constructor(maxEntries = 10_000) {\n this.maxEntries = maxEntries;\n }\n\n /**\n * Get a value from cache\n * @param {string} key - Cache key\n * @returns {unknown | undefined} Cached value or undefined\n */\n get(key: string): unknown | undefined {\n const entry = this.store.get(key);\n if (!entry) {\n return undefined;\n }\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n entry.hitCount++;\n entry.lastAccess = Date.now();\n return entry.value;\n }\n\n /**\n * Set a value in cache with TTL\n * @param {string} key - Cache key\n * @param {unknown} value - Value to cache\n * @param {number} ttl - Time to live in milliseconds\n */\n set(key: string, value: unknown, ttl: number): void {\n if (this.store.size >= this.maxEntries) {\n this.evict();\n }\n this.store.set(key, {\n value,\n expiresAt: Date.now() + ttl,\n hitCount: 1,\n lastAccess: Date.now(),\n });\n }\n\n /**\n * Check if a key exists in cache and is not expired\n * @param {string} key - Cache key\n * @returns {boolean} Whether the key exists\n */\n has(key: string): boolean {\n const entry = this.store.get(key);\n if (!entry) {\n return false;\n }\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return false;\n }\n return true;\n }\n\n /**\n * Delete a key from cache\n * @param {string} key - Cache key\n */\n delete(key: string): void {\n this.store.delete(key);\n }\n\n /**\n * Invalidate all cache entries matching a prefix\n * @param {string} prefix - Key prefix\n */\n invalidateByPrefix(prefix: string): void {\n for (const key of this.store.keys()) {\n if (key.startsWith(prefix)) {\n this.store.delete(key);\n }\n }\n }\n\n /**\n * Clear all cached entries\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Number of entries\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Get hit count for a cache key\n * @param {string} key - Cache key\n * @returns {number} Number of hits\n */\n getHitCount(key: string): number {\n return this.store.get(key)?.hitCount ?? 0;\n }\n\n /**\n * Extend the TTL of a cache entry based on hit count\n * @param {string} key - Cache key\n * @param {number} baseTtl - Base TTL in milliseconds\n * @param {number} maxTtl - Maximum TTL in milliseconds\n */\n extendTtl(key: string, baseTtl: number, maxTtl: number): void {\n const entry = this.store.get(key);\n if (!entry) {\n return;\n }\n const adaptiveTtl = Math.min(maxTtl, baseTtl * (1 + Math.log2(entry.hitCount + 1)));\n entry.expiresAt = Date.now() + adaptiveTtl;\n }\n\n private evict(): void {\n let oldestKey: string | null = null;\n let oldestAccess = Number.POSITIVE_INFINITY;\n for (const [key, entry] of this.store) {\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return;\n }\n if (entry.lastAccess < oldestAccess) {\n oldestAccess = entry.lastAccess;\n oldestKey = key;\n }\n }\n if (oldestKey) {\n this.store.delete(oldestKey);\n }\n }\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"memory-store.mjs","names":[],"sources":["../../src/cache/memory-store.ts"],"sourcesContent":["interface CacheEntry {\n value: unknown;\n expiresAt: number;\n hitCount: number;\n lastAccess: number;\n}\n\n/**\n * In-memory cache store with TTL and hit-count tracking\n */\nexport class MemoryStore {\n private store = new Map<string, CacheEntry>();\n private maxEntries: number;\n\n constructor(maxEntries = 10_000) {\n this.maxEntries = maxEntries;\n }\n\n /**\n * Get a value from cache\n * @param {string} key - Cache key\n * @returns {unknown | undefined} Cached value or undefined\n */\n get(key: string): unknown | undefined {\n const entry = this.store.get(key);\n if (!entry) {\n return undefined;\n }\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n entry.hitCount++;\n entry.lastAccess = Date.now();\n return entry.value;\n }\n\n /**\n * Set a value in cache with TTL\n * @param {string} key - Cache key\n * @param {unknown} value - Value to cache\n * @param {number} ttl - Time to live in milliseconds\n */\n set(key: string, value: unknown, ttl: number): void {\n if (this.store.size >= this.maxEntries) {\n this.evict();\n }\n this.store.set(key, {\n value,\n expiresAt: Date.now() + ttl,\n hitCount: 1,\n lastAccess: Date.now(),\n });\n }\n\n /**\n * Check if a key exists in cache and is not expired\n * @param {string} key - Cache key\n * @returns {boolean} Whether the key exists\n */\n has(key: string): boolean {\n const entry = this.store.get(key);\n if (!entry) {\n return false;\n }\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return false;\n }\n return true;\n }\n\n /**\n * Delete a key from cache\n * @param {string} key - Cache key\n */\n delete(key: string): void {\n this.store.delete(key);\n }\n\n /**\n * Invalidate all cache entries matching a prefix\n * @param {string} prefix - Key prefix\n */\n invalidateByPrefix(prefix: string): void {\n for (const key of this.store.keys()) {\n if (key.startsWith(prefix)) {\n this.store.delete(key);\n }\n }\n }\n\n /**\n * Clear all cached entries\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Number of entries\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Get hit count for a cache key\n * @param {string} key - Cache key\n * @returns {number} Number of hits\n */\n getHitCount(key: string): number {\n return this.store.get(key)?.hitCount ?? 0;\n }\n\n /**\n * Extend the TTL of a cache entry based on hit count\n * @param {string} key - Cache key\n * @param {number} baseTtl - Base TTL in milliseconds\n * @param {number} maxTtl - Maximum TTL in milliseconds\n */\n extendTtl(key: string, baseTtl: number, maxTtl: number): void {\n const entry = this.store.get(key);\n if (!entry) {\n return;\n }\n const adaptiveTtl = Math.min(maxTtl, baseTtl * (1 + Math.log2(entry.hitCount + 1)));\n entry.expiresAt = Date.now() + adaptiveTtl;\n }\n\n private evict(): void {\n let oldestKey: string | null = null;\n let oldestAccess = Number.POSITIVE_INFINITY;\n for (const [key, entry] of this.store) {\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return;\n }\n if (entry.lastAccess < oldestAccess) {\n oldestAccess = entry.lastAccess;\n oldestKey = key;\n }\n }\n if (oldestKey) {\n this.store.delete(oldestKey);\n }\n }\n}\n"],"mappings":";;;;AAUa,eAAb,MAAyB;EACvB,wBAAgB,IAAI,KAAyB;EAC7C;EAEA,YAAY,aAAa,KAAQ;AAC/B,QAAK,aAAa;;;;;;;EAQpB,IAAI,KAAkC;GACpC,MAAM,QAAQ,KAAK,MAAM,IAAI,IAAI;AACjC,OAAI,CAAC,MACH;AAEF,OAAI,KAAK,KAAK,GAAG,MAAM,WAAW;AAChC,SAAK,MAAM,OAAO,IAAI;AACtB;;AAEF,SAAM;AACN,SAAM,aAAa,KAAK,KAAK;AAC7B,UAAO,MAAM;;;;;;;;EASf,IAAI,KAAa,OAAgB,KAAmB;AAClD,OAAI,KAAK,MAAM,QAAQ,KAAK,WAC1B,MAAK,OAAO;AAEd,QAAK,MAAM,IAAI,KAAK;IAClB;IACA,WAAW,KAAK,KAAK,GAAG;IACxB,UAAU;IACV,YAAY,KAAK,KAAK;IACvB,CAAC;;;;;;;EAQJ,IAAI,KAAsB;GACxB,MAAM,QAAQ,KAAK,MAAM,IAAI,IAAI;AACjC,OAAI,CAAC,MACH,QAAO;AAET,OAAI,KAAK,KAAK,GAAG,MAAM,WAAW;AAChC,SAAK,MAAM,OAAO,IAAI;AACtB,WAAO;;AAET,UAAO;;;;;;EAOT,OAAO,KAAmB;AACxB,QAAK,MAAM,OAAO,IAAI;;;;;;EAOxB,mBAAmB,QAAsB;AACvC,QAAK,MAAM,OAAO,KAAK,MAAM,MAAM,CACjC,KAAI,IAAI,WAAW,OAAO,CACxB,MAAK,MAAM,OAAO,IAAI;;;;;EAQ5B,QAAc;AACZ,QAAK,MAAM,OAAO;;;;;;EAOpB,IAAI,OAAe;AACjB,UAAO,KAAK,MAAM;;;;;;;EAQpB,YAAY,KAAqB;AAC/B,UAAO,KAAK,MAAM,IAAI,IAAI,EAAE,YAAY;;;;;;;;EAS1C,UAAU,KAAa,SAAiB,QAAsB;GAC5D,MAAM,QAAQ,KAAK,MAAM,IAAI,IAAI;AACjC,OAAI,CAAC,MACH;GAEF,MAAM,cAAc,KAAK,IAAI,QAAQ,WAAW,IAAI,KAAK,KAAK,MAAM,WAAW,EAAE,EAAE;AACnF,SAAM,YAAY,KAAK,KAAK,GAAG;;EAGjC,QAAsB;GACpB,IAAI,YAA2B;GAC/B,IAAI,eAAe,OAAO;AAC1B,QAAK,MAAM,CAAC,KAAK,UAAU,KAAK,OAAO;AACrC,QAAI,KAAK,KAAK,GAAG,MAAM,WAAW;AAChC,UAAK,MAAM,OAAO,IAAI;AACtB;;AAEF,QAAI,MAAM,aAAa,cAAc;AACnC,oBAAe,MAAM;AACrB,iBAAY;;;AAGhB,OAAI,UACF,MAAK,MAAM,OAAO,UAAU"}
|