@webda/cache 4.0.0-beta.3
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/LICENSE +166 -0
- package/README.md +115 -0
- package/lib/cache.d.ts +299 -0
- package/lib/cache.js +604 -0
- package/lib/cache.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
GNU LESSER GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 29 June 2007
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
|
6
|
+
of this license document, but changing it is not allowed.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
This version of the GNU Lesser General Public License incorporates
|
|
10
|
+
the terms and conditions of version 3 of the GNU General Public
|
|
11
|
+
License, supplemented by the additional permissions listed below.
|
|
12
|
+
|
|
13
|
+
0. Additional Definitions.
|
|
14
|
+
|
|
15
|
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
16
|
+
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
17
|
+
General Public License.
|
|
18
|
+
|
|
19
|
+
"The Library" refers to a covered work governed by this License,
|
|
20
|
+
other than an Application or a Combined Work as defined below.
|
|
21
|
+
|
|
22
|
+
An "Application" is any work that makes use of an interface provided
|
|
23
|
+
by the Library, but which is not otherwise based on the Library.
|
|
24
|
+
Defining a subclass of a class defined by the Library is deemed a mode
|
|
25
|
+
of using an interface provided by the Library.
|
|
26
|
+
|
|
27
|
+
A "Combined Work" is a work produced by combining or linking an
|
|
28
|
+
Application with the Library. The particular version of the Library
|
|
29
|
+
with which the Combined Work was made is also called the "Linked
|
|
30
|
+
Version".
|
|
31
|
+
|
|
32
|
+
The "Minimal Corresponding Source" for a Combined Work means the
|
|
33
|
+
Corresponding Source for the Combined Work, excluding any source code
|
|
34
|
+
for portions of the Combined Work that, considered in isolation, are
|
|
35
|
+
based on the Application, and not on the Linked Version.
|
|
36
|
+
|
|
37
|
+
The "Corresponding Application Code" for a Combined Work means the
|
|
38
|
+
object code and/or source code for the Application, including any data
|
|
39
|
+
and utility programs needed for reproducing the Combined Work from the
|
|
40
|
+
Application, but excluding the System Libraries of the Combined Work.
|
|
41
|
+
|
|
42
|
+
1. Exception to Section 3 of the GNU GPL.
|
|
43
|
+
|
|
44
|
+
You may convey a covered work under sections 3 and 4 of this License
|
|
45
|
+
without being bound by section 3 of the GNU GPL.
|
|
46
|
+
|
|
47
|
+
2. Conveying Modified Versions.
|
|
48
|
+
|
|
49
|
+
If you modify a copy of the Library, and, in your modifications, a
|
|
50
|
+
facility refers to a function or data to be supplied by an Application
|
|
51
|
+
that uses the facility (other than as an argument passed when the
|
|
52
|
+
facility is invoked), then you may convey a copy of the modified
|
|
53
|
+
version:
|
|
54
|
+
|
|
55
|
+
a) under this License, provided that you make a good faith effort to
|
|
56
|
+
ensure that, in the event an Application does not supply the
|
|
57
|
+
function or data, the facility still operates, and performs
|
|
58
|
+
whatever part of its purpose remains meaningful, or
|
|
59
|
+
|
|
60
|
+
b) under the GNU GPL, with none of the additional permissions of
|
|
61
|
+
this License applicable to that copy.
|
|
62
|
+
|
|
63
|
+
3. Object Code Incorporating Material from Library Header Files.
|
|
64
|
+
|
|
65
|
+
The object code form of an Application may incorporate material from
|
|
66
|
+
a header file that is part of the Library. You may convey such object
|
|
67
|
+
code under terms of your choice, provided that, if the incorporated
|
|
68
|
+
material is not limited to numerical parameters, data structure
|
|
69
|
+
layouts and accessors, or small macros, inline functions and templates
|
|
70
|
+
(ten or fewer lines in length), you do both of the following:
|
|
71
|
+
|
|
72
|
+
a) Give prominent notice with each copy of the object code that the
|
|
73
|
+
Library is used in it and that the Library and its use are
|
|
74
|
+
covered by this License.
|
|
75
|
+
|
|
76
|
+
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
77
|
+
document.
|
|
78
|
+
|
|
79
|
+
4. Combined Works.
|
|
80
|
+
|
|
81
|
+
You may convey a Combined Work under terms of your choice that,
|
|
82
|
+
taken together, effectively do not restrict modification of the
|
|
83
|
+
portions of the Library contained in the Combined Work and reverse
|
|
84
|
+
engineering for debugging such modifications, if you also do each of
|
|
85
|
+
the following:
|
|
86
|
+
|
|
87
|
+
a) Give prominent notice with each copy of the Combined Work that
|
|
88
|
+
the Library is used in it and that the Library and its use are
|
|
89
|
+
covered by this License.
|
|
90
|
+
|
|
91
|
+
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
92
|
+
document.
|
|
93
|
+
|
|
94
|
+
c) For a Combined Work that displays copyright notices during
|
|
95
|
+
execution, include the copyright notice for the Library among
|
|
96
|
+
these notices, as well as a reference directing the user to the
|
|
97
|
+
copies of the GNU GPL and this license document.
|
|
98
|
+
|
|
99
|
+
d) Do one of the following:
|
|
100
|
+
|
|
101
|
+
0) Convey the Minimal Corresponding Source under the terms of this
|
|
102
|
+
License, and the Corresponding Application Code in a form
|
|
103
|
+
suitable for, and under terms that permit, the user to
|
|
104
|
+
recombine or relink the Application with a modified version of
|
|
105
|
+
the Linked Version to produce a modified Combined Work, in the
|
|
106
|
+
manner specified by section 6 of the GNU GPL for conveying
|
|
107
|
+
Corresponding Source.
|
|
108
|
+
|
|
109
|
+
1) Use a suitable shared library mechanism for linking with the
|
|
110
|
+
Library. A suitable mechanism is one that (a) uses at run time
|
|
111
|
+
a copy of the Library already present on the user's computer
|
|
112
|
+
system, and (b) will operate properly with a modified version
|
|
113
|
+
of the Library that is interface-compatible with the Linked
|
|
114
|
+
Version.
|
|
115
|
+
|
|
116
|
+
e) Provide Installation Information, but only if you would otherwise
|
|
117
|
+
be required to provide such information under section 6 of the
|
|
118
|
+
GNU GPL, and only to the extent that such information is
|
|
119
|
+
necessary to install and execute a modified version of the
|
|
120
|
+
Combined Work produced by recombining or relinking the
|
|
121
|
+
Application with a modified version of the Linked Version. (If
|
|
122
|
+
you use option 4d0, the Installation Information must accompany
|
|
123
|
+
the Minimal Corresponding Source and Corresponding Application
|
|
124
|
+
Code. If you use option 4d1, you must provide the Installation
|
|
125
|
+
Information in the manner specified by section 6 of the GNU GPL
|
|
126
|
+
for conveying Corresponding Source.)
|
|
127
|
+
|
|
128
|
+
5. Combined Libraries.
|
|
129
|
+
|
|
130
|
+
You may place library facilities that are a work based on the
|
|
131
|
+
Library side by side in a single library together with other library
|
|
132
|
+
facilities that are not Applications and are not covered by this
|
|
133
|
+
License, and convey such a combined library under terms of your
|
|
134
|
+
choice, if you do both of the following:
|
|
135
|
+
|
|
136
|
+
a) Accompany the combined library with a copy of the same work based
|
|
137
|
+
on the Library, uncombined with any other library facilities,
|
|
138
|
+
conveyed under the terms of this License.
|
|
139
|
+
|
|
140
|
+
b) Give prominent notice with the combined library that part of it
|
|
141
|
+
is a work based on the Library, and explaining where to find the
|
|
142
|
+
accompanying uncombined form of the same work.
|
|
143
|
+
|
|
144
|
+
6. Revised Versions of the GNU Lesser General Public License.
|
|
145
|
+
|
|
146
|
+
The Free Software Foundation may publish revised and/or new versions
|
|
147
|
+
of the GNU Lesser General Public License from time to time. Such new
|
|
148
|
+
versions will be similar in spirit to the present version, but may
|
|
149
|
+
differ in detail to address new problems or concerns.
|
|
150
|
+
|
|
151
|
+
Each version is given a distinguishing version number. If the
|
|
152
|
+
Library as you received it specifies that a certain numbered version
|
|
153
|
+
of the GNU Lesser General Public License "or any later version"
|
|
154
|
+
applies to it, you have the option of following the terms and
|
|
155
|
+
conditions either of that published version or of any later version
|
|
156
|
+
published by the Free Software Foundation. If the Library as you
|
|
157
|
+
received it does not specify a version number of the GNU Lesser
|
|
158
|
+
General Public License, you may choose any version of the GNU Lesser
|
|
159
|
+
General Public License ever published by the Free Software Foundation.
|
|
160
|
+
|
|
161
|
+
If the Library as you received it specifies that a proxy can decide
|
|
162
|
+
whether future versions of the GNU Lesser General Public License shall
|
|
163
|
+
apply, that proxy's public statement of acceptance of any version is
|
|
164
|
+
permanent authorization for you to choose that version for the
|
|
165
|
+
Library.
|
|
166
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @webda/cache module
|
|
2
|
+
|
|
3
|
+
This module is part of Webda Application Framework that allows you to quickly develop applications with all modern prerequisites: Security, Extensibility, GraphQL, REST, CloudNative [https://webda.io](https://webda.io)
|
|
4
|
+
|
|
5
|
+
<img src="https://webda.io/images/webda.svg" width="128" />
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
[](https://gitter.im/loopingz/webda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
10
|
+
[](https://codecov.io/gh/loopingz/webda.io)
|
|
11
|
+
[](https://sonarcloud.io/summary/new_code?id=loopingz_webda.io)
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
<!-- README_HEADER -->
|
|
15
|
+
|
|
16
|
+
# @webda/cache
|
|
17
|
+
|
|
18
|
+
> Method-level caching decorator library for Webda — annotate any method with `@ProcessCache` or `@ObjectCache` to add TTL, LRU, and statistics-aware memoization with no boilerplate.
|
|
19
|
+
|
|
20
|
+
## When to use it
|
|
21
|
+
|
|
22
|
+
- You want to cache expensive async lookups (database queries, HTTP calls) at the method level without manually managing cache state.
|
|
23
|
+
- You need per-instance caching (`@ObjectCache`) or process-wide shared caching (`@ProcessCache`).
|
|
24
|
+
- You need a custom cache scope (per async context, per request) via `createCacheAnnotation`.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm add @webda/cache
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
`@webda/cache` is a pure TypeScript library — it has no Webda service entry and requires no `webda.config.json` entry. Import and apply the decorators directly.
|
|
35
|
+
|
|
36
|
+
| Option | Type | Default | Description |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| `ttl` | number | — | Time-to-live in milliseconds. Entries older than this are evicted on next access. |
|
|
39
|
+
| `maxSize` | number | — | Maximum entries per instance (LRU eviction when exceeded). |
|
|
40
|
+
| `gcInterval` | number | — | Interval in ms for automatic TTL garbage collection. |
|
|
41
|
+
| `enableStats` | boolean | `false` | Track hit/miss/eviction counters. |
|
|
42
|
+
| `hashStrategy` | `"sha256"` \| `"simple"` | `"sha256"` | Key hashing algorithm for argument fingerprinting. |
|
|
43
|
+
| `shouldCache` | `(result) => boolean` | — | Predicate to skip caching specific results (e.g. nulls). |
|
|
44
|
+
| `methodKeyGenerator` | function | — | Custom function to compute the per-call cache key. |
|
|
45
|
+
| `classKeyGenerator` | function | — | Custom function to compute the per-instance cache key. |
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { ObjectCache, ProcessCache, createCacheAnnotation } from "@webda/cache";
|
|
51
|
+
|
|
52
|
+
// Per-instance cache — each class instance has its own cache
|
|
53
|
+
class UserService {
|
|
54
|
+
@ObjectCache({ ttl: 30000 })
|
|
55
|
+
async fetchUser(id: string): Promise<User> {
|
|
56
|
+
// Called at most once per unique `id` per instance within the 30s TTL
|
|
57
|
+
return db.users.findById(id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Process-wide cache — shared across all instances in the Node.js process
|
|
62
|
+
class ConfigService {
|
|
63
|
+
@ProcessCache({ ttl: 60000 })
|
|
64
|
+
getConfig(env: string): Config {
|
|
65
|
+
return loadConfigFromDisk(env);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Custom cache scope (e.g. per async context / per HTTP request)
|
|
70
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
71
|
+
const storage = new AsyncLocalStorage<object>();
|
|
72
|
+
const RequestCache = createCacheAnnotation(() => storage.getStore() ?? null, { ttl: 5000 });
|
|
73
|
+
|
|
74
|
+
class SearchService {
|
|
75
|
+
@RequestCache()
|
|
76
|
+
async search(query: string): Promise<Result[]> {
|
|
77
|
+
return performSearch(query);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Manual cache control
|
|
82
|
+
const service = new UserService();
|
|
83
|
+
ObjectCache.clear(service, "fetchUser", "123"); // clear one entry
|
|
84
|
+
ObjectCache.clearAll(service, "fetchUser"); // clear all entries for a method
|
|
85
|
+
ObjectCache.clearAll(service); // clear entire instance cache
|
|
86
|
+
|
|
87
|
+
// Statistics
|
|
88
|
+
const stats = ObjectCache.getStats();
|
|
89
|
+
// { hits: 42, misses: 8, evictions: 3, sets: 11 }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Reference
|
|
93
|
+
|
|
94
|
+
- API reference: see the auto-generated typedoc at `docs/pages/Modules/cache/`.
|
|
95
|
+
- Source: [`packages/cache`](https://github.com/loopingz/webda.io/tree/main/packages/cache)
|
|
96
|
+
- Related: [`@webda/core`](../core) for service-level caching patterns; [`@webda/decorators`](../decorators) for the underlying `createMethodDecorator` primitive used internally.
|
|
97
|
+
|
|
98
|
+
<!-- README_FOOTER -->
|
|
99
|
+
## Sponsors
|
|
100
|
+
|
|
101
|
+
<!--
|
|
102
|
+
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](mailto:sponsor@webda.io)
|
|
103
|
+
-->
|
|
104
|
+
|
|
105
|
+
Arize AI is a machine learning observability and model monitoring platform. It helps you visualize, monitor, and explain your machine learning models. [Learn more](https://arize.com)
|
|
106
|
+
|
|
107
|
+
[<img src="https://arize.com/hubfs/arize/brand/arize-logomark-1.png" width="200">](https://arize.com)
|
|
108
|
+
|
|
109
|
+
Loopingz is a software development company that provides consulting and development services. [Learn more](https://loopingz.com)
|
|
110
|
+
|
|
111
|
+
[<img src="https://loopingz.com/images/logo.png" width="200">](https://loopingz.com)
|
|
112
|
+
|
|
113
|
+
Tellae is an innovative consulting firm specialized in cities transportation issues. We provide our clients, both public and private, with solutions to support your strategic and operational decisions. [Learn more](https://tellae.fr)
|
|
114
|
+
|
|
115
|
+
[<img src="https://tellae.fr/" width="200">](https://tellae.fr)
|
package/lib/cache.d.ts
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache statistics for tracking performance metrics.
|
|
3
|
+
*/
|
|
4
|
+
export interface CacheStats {
|
|
5
|
+
hits: number;
|
|
6
|
+
misses: number;
|
|
7
|
+
evictions: number;
|
|
8
|
+
sets: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Options controlling cache key generation and storage behavior.
|
|
12
|
+
*/
|
|
13
|
+
export interface CacheOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Define how to cache the method call.
|
|
16
|
+
* If undefined is returned then no caching is done.
|
|
17
|
+
*
|
|
18
|
+
* @param property
|
|
19
|
+
* @param args
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
methodKeyGenerator?: (property: string, args: any[]) => string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Generator for the instance-level cache key (e.g., per `this`).
|
|
25
|
+
*/
|
|
26
|
+
classKeyGenerator?: (instance: object) => any;
|
|
27
|
+
/**
|
|
28
|
+
* Define how long the cache should be kept (in milliseconds).
|
|
29
|
+
*/
|
|
30
|
+
ttl?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Maximum number of entries per instance cache.
|
|
33
|
+
* When exceeded, least recently used entries are evicted.
|
|
34
|
+
*/
|
|
35
|
+
maxSize?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Automatic garbage collection interval (in milliseconds).
|
|
38
|
+
* When set, expired entries are automatically cleaned up.
|
|
39
|
+
*/
|
|
40
|
+
gcInterval?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Enable cache statistics tracking (hits, misses, evictions).
|
|
43
|
+
*/
|
|
44
|
+
enableStats?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Predicate to decide whether a result should be cached.
|
|
47
|
+
* Return `false` to skip caching for a specific result value.
|
|
48
|
+
*
|
|
49
|
+
* Called with the resolved value for async methods.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // Only cache non-null results
|
|
53
|
+
* shouldCache: (result) => result !== null
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Only cache successful HTTP responses
|
|
57
|
+
* shouldCache: (result) => result?.status === 200
|
|
58
|
+
*/
|
|
59
|
+
shouldCache?: (result: any) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Algorithm to use for default argument key generation.
|
|
62
|
+
*
|
|
63
|
+
* - `'sha256'` (default): Hashes the serialized arguments with SHA-256.
|
|
64
|
+
* Collision-resistant and produces fixed-length keys, but involves
|
|
65
|
+
* a crypto operation on every cache miss.
|
|
66
|
+
* - `'simple'`: Uses a typed, length-prefixed string encoding without
|
|
67
|
+
* hashing. Faster for hot paths but produces longer keys proportional
|
|
68
|
+
* to argument size.
|
|
69
|
+
*
|
|
70
|
+
* Has no effect when a custom `methodKeyGenerator` is provided.
|
|
71
|
+
*/
|
|
72
|
+
hashStrategy?: "sha256" | "simple";
|
|
73
|
+
/**
|
|
74
|
+
* Custom `CacheMap` implementation constructor.
|
|
75
|
+
*/
|
|
76
|
+
cacheMap?: new (options: CacheOptions) => CacheMap;
|
|
77
|
+
/**
|
|
78
|
+
* Custom `CacheStorage` implementation constructor.
|
|
79
|
+
*/
|
|
80
|
+
cacheStorage?: new (options?: CacheOptions) => CacheStorage;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Storage for cached method results for a single instance.
|
|
84
|
+
*
|
|
85
|
+
* Maintains an internal timestamp per entry to support TTL-based
|
|
86
|
+
* invalidation during reads and garbage collection.
|
|
87
|
+
*
|
|
88
|
+
* Keys are method-level cache keys produced by `methodKeyGenerator`.
|
|
89
|
+
* Supports LRU eviction when maxSize is configured.
|
|
90
|
+
*/
|
|
91
|
+
export declare class CacheStorage extends Map<string, {
|
|
92
|
+
value: any;
|
|
93
|
+
timestamp: number;
|
|
94
|
+
}> {
|
|
95
|
+
private options?;
|
|
96
|
+
stats: CacheStats;
|
|
97
|
+
/** Create a new CacheStorage.
|
|
98
|
+
* @param options - cache configuration options
|
|
99
|
+
*/
|
|
100
|
+
constructor(options?: CacheOptions | undefined);
|
|
101
|
+
/**
|
|
102
|
+
* Check whether a cached value exists and is still valid.
|
|
103
|
+
* Applies TTL: if an entry is expired, it is evicted and treated as missing.
|
|
104
|
+
*
|
|
105
|
+
* @param key - the method cache key
|
|
106
|
+
* @returns true if a valid cached entry exists
|
|
107
|
+
*/
|
|
108
|
+
hasCachedMethod(key: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Store a cached value for the given method key.
|
|
111
|
+
* Implements LRU eviction when maxSize is reached.
|
|
112
|
+
*
|
|
113
|
+
* Note: `args` is accepted for potential future strategies but not used here.
|
|
114
|
+
*
|
|
115
|
+
* @param key - the method cache key
|
|
116
|
+
* @param _args - original method arguments (reserved)
|
|
117
|
+
* @param value - the value to cache
|
|
118
|
+
*/
|
|
119
|
+
setCachedMethod(key: string, _args: any[], value: any): void;
|
|
120
|
+
/**
|
|
121
|
+
* Retrieve the cached value for the given method key (without TTL re-check).
|
|
122
|
+
*
|
|
123
|
+
* @param key - the method cache key
|
|
124
|
+
* @returns the cached value or undefined
|
|
125
|
+
*/
|
|
126
|
+
getCachedMethod(key: string): any;
|
|
127
|
+
/**
|
|
128
|
+
* Delete cache entries.
|
|
129
|
+
* If the key ends with `$`, all entries starting with the prefix are removed.
|
|
130
|
+
*
|
|
131
|
+
* @param key - the method cache key or prefix
|
|
132
|
+
*/
|
|
133
|
+
deleteCachedMethod(key: string): void;
|
|
134
|
+
/**
|
|
135
|
+
* Remove all expired entries based on TTL.
|
|
136
|
+
*/
|
|
137
|
+
garbageCollect(): void;
|
|
138
|
+
/**
|
|
139
|
+
* Get current cache statistics.
|
|
140
|
+
*
|
|
141
|
+
* @returns a copy of the current stats
|
|
142
|
+
*/
|
|
143
|
+
getStats(): CacheStats;
|
|
144
|
+
/**
|
|
145
|
+
* Reset cache statistics to zero.
|
|
146
|
+
*/
|
|
147
|
+
resetStats(): void;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Cache map storing `CacheStorage` per instance key.
|
|
151
|
+
*
|
|
152
|
+
* The instance key is produced by `classKeyGenerator`.
|
|
153
|
+
*/
|
|
154
|
+
export declare class CacheMap<T extends object = object> extends Map<T, CacheStorage> {
|
|
155
|
+
private options?;
|
|
156
|
+
private gcTimer?;
|
|
157
|
+
/** Create a new CacheMap.
|
|
158
|
+
* @param options - cache configuration options
|
|
159
|
+
*/
|
|
160
|
+
constructor(options?: CacheOptions | undefined);
|
|
161
|
+
/**
|
|
162
|
+
* Get a cached value for a given instance and method key.
|
|
163
|
+
*
|
|
164
|
+
* @param target - the instance key
|
|
165
|
+
* @param key - the method cache key
|
|
166
|
+
* @returns the cached value or undefined
|
|
167
|
+
*/
|
|
168
|
+
getCachedMethod(target: T, key: string): any;
|
|
169
|
+
/**
|
|
170
|
+
* Check if a cached value exists for the given instance and method key.
|
|
171
|
+
* Tracks cache hits when enableStats is true (misses tracked in setCachedMethod).
|
|
172
|
+
*
|
|
173
|
+
* @param target - the instance key
|
|
174
|
+
* @param key - the method cache key
|
|
175
|
+
* @returns true if a valid cached entry exists
|
|
176
|
+
*/
|
|
177
|
+
hasCachedMethod(target: T, key: string): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Store a cached value for the given instance + method key.
|
|
180
|
+
* Tracks misses when enableStats is true (only if key didn't exist).
|
|
181
|
+
*
|
|
182
|
+
* @param target - the instance key
|
|
183
|
+
* @param key - the method cache key
|
|
184
|
+
* @param _args - original method arguments (reserved)
|
|
185
|
+
* @param value - the value to cache
|
|
186
|
+
*/
|
|
187
|
+
setCachedMethod(target: T, key: string, _args: any[], value: any): void;
|
|
188
|
+
/**
|
|
189
|
+
* Trigger garbage collection on all instance stores.
|
|
190
|
+
*/
|
|
191
|
+
garbageCollect(): void;
|
|
192
|
+
/**
|
|
193
|
+
* Start automatic garbage collection timer.
|
|
194
|
+
*/
|
|
195
|
+
private startAutoGC;
|
|
196
|
+
/**
|
|
197
|
+
* Stop automatic garbage collection timer.
|
|
198
|
+
*/
|
|
199
|
+
stopAutoGC(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Get aggregated statistics across all instance caches.
|
|
202
|
+
*
|
|
203
|
+
* @returns the aggregated stats
|
|
204
|
+
*/
|
|
205
|
+
getStats(): CacheStats;
|
|
206
|
+
/**
|
|
207
|
+
* Reset statistics for all instance caches.
|
|
208
|
+
*/
|
|
209
|
+
resetStats(): void;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Compute a deterministic hash for a list of arguments.
|
|
213
|
+
*
|
|
214
|
+
* Returns a base64-encoded SHA-256 digest, or `undefined` if any
|
|
215
|
+
* argument cannot be serialized deterministically.
|
|
216
|
+
*
|
|
217
|
+
* @param args - the arguments to hash
|
|
218
|
+
* @returns base64 SHA-256 digest or undefined
|
|
219
|
+
*/
|
|
220
|
+
export declare function argumentsHash(args: any[]): string | undefined;
|
|
221
|
+
/**
|
|
222
|
+
* Compute a simple typed key for a list of arguments without hashing.
|
|
223
|
+
*
|
|
224
|
+
* Uses length-prefixed, type-tagged encoding to produce a unique string
|
|
225
|
+
* representation for each distinct argument list, or `undefined` if any
|
|
226
|
+
* argument cannot be serialized deterministically.
|
|
227
|
+
*
|
|
228
|
+
* Format per argument: `<TYPE><LENGTH>:<VALUE>` where TYPE is a single
|
|
229
|
+
* uppercase letter identifying the argument type. No separator is needed
|
|
230
|
+
* between arguments because the length prefix makes the encoding unambiguous.
|
|
231
|
+
*
|
|
232
|
+
* This is faster than {@link argumentsHash} because it skips the SHA-256
|
|
233
|
+
* step. Keys may be longer in proportion to argument size. Prefer this
|
|
234
|
+
* strategy for hot sync paths with small, simple arguments.
|
|
235
|
+
*
|
|
236
|
+
* @param args - the arguments to encode
|
|
237
|
+
* @returns typed key string or undefined
|
|
238
|
+
*/
|
|
239
|
+
export declare function argumentsSimpleKey(args: any[]): string | undefined;
|
|
240
|
+
/**
|
|
241
|
+
* Register a logger used by the cache system to report non-cacheable calls.
|
|
242
|
+
*
|
|
243
|
+
* @param logger - the logging function to register
|
|
244
|
+
*/
|
|
245
|
+
export declare function registerCacheLogger(logger: (...args: any[]) => void): void;
|
|
246
|
+
/**
|
|
247
|
+
* Create a cache annotation (method decorator) bound to a given source provider.
|
|
248
|
+
*
|
|
249
|
+
* The returned decorator caches method results based on keys generated by
|
|
250
|
+
* `methodKeyGenerator` and `classKeyGenerator`. It also exposes utility methods:
|
|
251
|
+
* - `clear(target, propertyKey, ...args)`: Clear specific cache entry
|
|
252
|
+
* - `clearAll(target, propertyKey?)`: Clear all or method-prefixed entries
|
|
253
|
+
* - `garbageCollect()`: Run TTL-based cleanup
|
|
254
|
+
*
|
|
255
|
+
* @param source - function returning the cache host for a given target
|
|
256
|
+
* @param options - cache configuration options
|
|
257
|
+
* @returns the cache method decorator with utility methods
|
|
258
|
+
*/
|
|
259
|
+
export declare function createCacheAnnotation(source: (target: object | null) => object | null, options?: CacheOptions): {
|
|
260
|
+
(value: import("@webda/decorators").AnyMethod, context: ClassMethodDecoratorContext<any, any>): void | import("@webda/decorators").AnyMethod;
|
|
261
|
+
(...args: any[]): (value: import("@webda/decorators").AnyMethod, context: ClassMethodDecoratorContext<any, any>) => void | import("@webda/decorators").AnyMethod;
|
|
262
|
+
} & {
|
|
263
|
+
clear: (target: object, propertyKey: string, ...args: any[]) => void;
|
|
264
|
+
clearAll: (target: object, propertyKey?: string) => void;
|
|
265
|
+
garbageCollect: () => void;
|
|
266
|
+
getStats: () => CacheStats;
|
|
267
|
+
resetStats: () => void;
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* Cache decorator using a process-level storage.
|
|
271
|
+
*
|
|
272
|
+
* Suitable for cross-instance caching within the same Node.js process.
|
|
273
|
+
*/
|
|
274
|
+
declare const ProcessCache: {
|
|
275
|
+
(value: import("@webda/decorators").AnyMethod, context: ClassMethodDecoratorContext<any, any>): void | import("@webda/decorators").AnyMethod;
|
|
276
|
+
(...args: any[]): (value: import("@webda/decorators").AnyMethod, context: ClassMethodDecoratorContext<any, any>) => void | import("@webda/decorators").AnyMethod;
|
|
277
|
+
} & {
|
|
278
|
+
clear: (target: object, propertyKey: string, ...args: any[]) => void;
|
|
279
|
+
clearAll: (target: object, propertyKey?: string) => void;
|
|
280
|
+
garbageCollect: () => void;
|
|
281
|
+
getStats: () => CacheStats;
|
|
282
|
+
resetStats: () => void;
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* Cache decorator using an object-level storage (per instance).
|
|
286
|
+
*
|
|
287
|
+
* Suitable for encapsulated caches tied to specific objects.
|
|
288
|
+
*/
|
|
289
|
+
declare const ObjectCache: {
|
|
290
|
+
(value: import("@webda/decorators").AnyMethod, context: ClassMethodDecoratorContext<any, any>): void | import("@webda/decorators").AnyMethod;
|
|
291
|
+
(...args: any[]): (value: import("@webda/decorators").AnyMethod, context: ClassMethodDecoratorContext<any, any>) => void | import("@webda/decorators").AnyMethod;
|
|
292
|
+
} & {
|
|
293
|
+
clear: (target: object, propertyKey: string, ...args: any[]) => void;
|
|
294
|
+
clearAll: (target: object, propertyKey?: string) => void;
|
|
295
|
+
garbageCollect: () => void;
|
|
296
|
+
getStats: () => CacheStats;
|
|
297
|
+
resetStats: () => void;
|
|
298
|
+
};
|
|
299
|
+
export { ProcessCache, ObjectCache };
|
package/lib/cache.js
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
/* c8 ignore next */
|
|
2
|
+
import { createMethodDecorator, getMetadata } from "@webda/decorators";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
/**
|
|
5
|
+
* Storage for cached method results for a single instance.
|
|
6
|
+
*
|
|
7
|
+
* Maintains an internal timestamp per entry to support TTL-based
|
|
8
|
+
* invalidation during reads and garbage collection.
|
|
9
|
+
*
|
|
10
|
+
* Keys are method-level cache keys produced by `methodKeyGenerator`.
|
|
11
|
+
* Supports LRU eviction when maxSize is configured.
|
|
12
|
+
*/
|
|
13
|
+
export class CacheStorage extends Map {
|
|
14
|
+
/** Create a new CacheStorage.
|
|
15
|
+
* @param options - cache configuration options
|
|
16
|
+
*/
|
|
17
|
+
constructor(options) {
|
|
18
|
+
super();
|
|
19
|
+
this.options = options;
|
|
20
|
+
this.stats = { hits: 0, misses: 0, evictions: 0, sets: 0 };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check whether a cached value exists and is still valid.
|
|
24
|
+
* Applies TTL: if an entry is expired, it is evicted and treated as missing.
|
|
25
|
+
*
|
|
26
|
+
* @param key - the method cache key
|
|
27
|
+
* @returns true if a valid cached entry exists
|
|
28
|
+
*/
|
|
29
|
+
hasCachedMethod(key) {
|
|
30
|
+
const exists = this.has(key);
|
|
31
|
+
// Implement TTL check if needed
|
|
32
|
+
if (this.options?.ttl && exists) {
|
|
33
|
+
const cached = this.get(key);
|
|
34
|
+
if (cached && Date.now() - cached.timestamp > this.options.ttl) {
|
|
35
|
+
this.delete(key);
|
|
36
|
+
if (this.options.enableStats) {
|
|
37
|
+
this.stats.evictions++;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return exists;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Store a cached value for the given method key.
|
|
46
|
+
* Implements LRU eviction when maxSize is reached.
|
|
47
|
+
*
|
|
48
|
+
* Note: `args` is accepted for potential future strategies but not used here.
|
|
49
|
+
*
|
|
50
|
+
* @param key - the method cache key
|
|
51
|
+
* @param _args - original method arguments (reserved)
|
|
52
|
+
* @param value - the value to cache
|
|
53
|
+
*/
|
|
54
|
+
setCachedMethod(key, _args, value) {
|
|
55
|
+
// LRU: if key exists, delete it so we can re-add it at the end (most recent)
|
|
56
|
+
if (this.has(key)) {
|
|
57
|
+
this.delete(key);
|
|
58
|
+
}
|
|
59
|
+
// Check if we need to evict the oldest entry (LRU)
|
|
60
|
+
if (this.options?.maxSize && this.size >= this.options.maxSize) {
|
|
61
|
+
// Map iteration order is insertion order, so first key is oldest
|
|
62
|
+
const oldestKey = this.keys().next().value;
|
|
63
|
+
if (oldestKey !== undefined) {
|
|
64
|
+
this.delete(oldestKey);
|
|
65
|
+
if (this.options.enableStats) {
|
|
66
|
+
this.stats.evictions++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
this.set(key, { value, timestamp: Date.now() });
|
|
71
|
+
if (this.options?.enableStats) {
|
|
72
|
+
this.stats.sets++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Retrieve the cached value for the given method key (without TTL re-check).
|
|
77
|
+
*
|
|
78
|
+
* @param key - the method cache key
|
|
79
|
+
* @returns the cached value or undefined
|
|
80
|
+
*/
|
|
81
|
+
getCachedMethod(key) {
|
|
82
|
+
const cached = this.get(key);
|
|
83
|
+
return cached?.value;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Delete cache entries.
|
|
87
|
+
* If the key ends with `$`, all entries starting with the prefix are removed.
|
|
88
|
+
*
|
|
89
|
+
* @param key - the method cache key or prefix
|
|
90
|
+
*/
|
|
91
|
+
deleteCachedMethod(key) {
|
|
92
|
+
if (key.endsWith("$")) {
|
|
93
|
+
const prefix = key.slice(0, -1); // Remove trailing $ to get the actual prefix
|
|
94
|
+
for (const k of this.keys()) {
|
|
95
|
+
if (k.startsWith(prefix)) {
|
|
96
|
+
this.delete(k);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
this.delete(key);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Remove all expired entries based on TTL.
|
|
106
|
+
*/
|
|
107
|
+
garbageCollect() {
|
|
108
|
+
if (this.options?.ttl) {
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
let evicted = 0;
|
|
111
|
+
for (const [key, { timestamp }] of this.entries()) {
|
|
112
|
+
if (now - timestamp > this.options.ttl) {
|
|
113
|
+
this.delete(key);
|
|
114
|
+
evicted++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (this.options.enableStats && evicted > 0) {
|
|
118
|
+
this.stats.evictions += evicted;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get current cache statistics.
|
|
124
|
+
*
|
|
125
|
+
* @returns a copy of the current stats
|
|
126
|
+
*/
|
|
127
|
+
getStats() {
|
|
128
|
+
return { ...this.stats };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Reset cache statistics to zero.
|
|
132
|
+
*/
|
|
133
|
+
resetStats() {
|
|
134
|
+
this.stats = { hits: 0, misses: 0, evictions: 0, sets: 0 };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Cache map storing `CacheStorage` per instance key.
|
|
139
|
+
*
|
|
140
|
+
* The instance key is produced by `classKeyGenerator`.
|
|
141
|
+
*/
|
|
142
|
+
export class CacheMap extends Map {
|
|
143
|
+
/** Create a new CacheMap.
|
|
144
|
+
* @param options - cache configuration options
|
|
145
|
+
*/
|
|
146
|
+
constructor(options) {
|
|
147
|
+
super();
|
|
148
|
+
this.options = options;
|
|
149
|
+
// Start automatic garbage collection if interval is configured
|
|
150
|
+
if (this.options?.gcInterval && this.options.gcInterval > 0) {
|
|
151
|
+
this.startAutoGC();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get a cached value for a given instance and method key.
|
|
156
|
+
*
|
|
157
|
+
* @param target - the instance key
|
|
158
|
+
* @param key - the method cache key
|
|
159
|
+
* @returns the cached value or undefined
|
|
160
|
+
*/
|
|
161
|
+
getCachedMethod(target, key) {
|
|
162
|
+
if (!this.has(target)) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return this.get(target).getCachedMethod(key);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if a cached value exists for the given instance and method key.
|
|
169
|
+
* Tracks cache hits when enableStats is true (misses tracked in setCachedMethod).
|
|
170
|
+
*
|
|
171
|
+
* @param target - the instance key
|
|
172
|
+
* @param key - the method cache key
|
|
173
|
+
* @returns true if a valid cached entry exists
|
|
174
|
+
*/
|
|
175
|
+
hasCachedMethod(target, key) {
|
|
176
|
+
if (this.has(target)) {
|
|
177
|
+
const cache = this.get(target);
|
|
178
|
+
const exists = cache.hasCachedMethod(key);
|
|
179
|
+
if (this.options?.enableStats && exists) {
|
|
180
|
+
cache.stats.hits++;
|
|
181
|
+
}
|
|
182
|
+
return exists;
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Store a cached value for the given instance + method key.
|
|
188
|
+
* Tracks misses when enableStats is true (only if key didn't exist).
|
|
189
|
+
*
|
|
190
|
+
* @param target - the instance key
|
|
191
|
+
* @param key - the method cache key
|
|
192
|
+
* @param _args - original method arguments (reserved)
|
|
193
|
+
* @param value - the value to cache
|
|
194
|
+
*/
|
|
195
|
+
setCachedMethod(target, key, _args, value) {
|
|
196
|
+
if (!this.has(target)) {
|
|
197
|
+
this.set(target, new (this.options?.cacheStorage ?? CacheStorage)(this.options));
|
|
198
|
+
}
|
|
199
|
+
const cache = this.get(target);
|
|
200
|
+
const isNewEntry = !cache.has(key);
|
|
201
|
+
cache.setCachedMethod(key, _args, value);
|
|
202
|
+
// Track miss only for new entries (not updates)
|
|
203
|
+
if (this.options?.enableStats && isNewEntry) {
|
|
204
|
+
cache.stats.misses++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Trigger garbage collection on all instance stores.
|
|
209
|
+
*/
|
|
210
|
+
garbageCollect() {
|
|
211
|
+
for (const [, cache] of this.entries()) {
|
|
212
|
+
cache.garbageCollect();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Start automatic garbage collection timer.
|
|
217
|
+
*/
|
|
218
|
+
startAutoGC() {
|
|
219
|
+
if (this.gcTimer) {
|
|
220
|
+
return; // Already running
|
|
221
|
+
}
|
|
222
|
+
this.gcTimer = setInterval(() => {
|
|
223
|
+
this.garbageCollect();
|
|
224
|
+
}, this.options.gcInterval);
|
|
225
|
+
// Allow Node.js to exit even if timer is active
|
|
226
|
+
if (this.gcTimer.unref) {
|
|
227
|
+
this.gcTimer.unref();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Stop automatic garbage collection timer.
|
|
232
|
+
*/
|
|
233
|
+
stopAutoGC() {
|
|
234
|
+
if (this.gcTimer) {
|
|
235
|
+
clearInterval(this.gcTimer);
|
|
236
|
+
this.gcTimer = undefined;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get aggregated statistics across all instance caches.
|
|
241
|
+
*
|
|
242
|
+
* @returns the aggregated stats
|
|
243
|
+
*/
|
|
244
|
+
getStats() {
|
|
245
|
+
const aggregated = { hits: 0, misses: 0, evictions: 0, sets: 0 };
|
|
246
|
+
for (const cache of this.values()) {
|
|
247
|
+
const stats = cache.getStats();
|
|
248
|
+
aggregated.hits += stats.hits;
|
|
249
|
+
aggregated.misses += stats.misses;
|
|
250
|
+
aggregated.evictions += stats.evictions;
|
|
251
|
+
aggregated.sets += stats.sets;
|
|
252
|
+
}
|
|
253
|
+
return aggregated;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Reset statistics for all instance caches.
|
|
257
|
+
*/
|
|
258
|
+
resetStats() {
|
|
259
|
+
for (const cache of this.values()) {
|
|
260
|
+
cache.resetStats();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Resolve and return the `CacheMap` from a cache provider.
|
|
266
|
+
*
|
|
267
|
+
* The provider is expected to return a host object on which `caches`
|
|
268
|
+
* will be lazily initialized to a `CacheMap`. If the provider returns
|
|
269
|
+
* `null`, caching is disabled and `null` is returned.
|
|
270
|
+
*
|
|
271
|
+
* @param provider - function returning the cache host
|
|
272
|
+
* @param options - cache configuration options
|
|
273
|
+
* @param target - the target instance or null
|
|
274
|
+
* @returns the CacheMap or null if caching is disabled
|
|
275
|
+
*/
|
|
276
|
+
function getSource(provider, options, target) {
|
|
277
|
+
const cache = provider(target);
|
|
278
|
+
if (cache === null) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
cache.caches ?? (cache.caches = new (options.cacheMap ?? CacheMap)(options));
|
|
282
|
+
return cache.caches;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Compute a deterministic hash for a list of arguments.
|
|
286
|
+
*
|
|
287
|
+
* Returns a base64-encoded SHA-256 digest, or `undefined` if any
|
|
288
|
+
* argument cannot be serialized deterministically.
|
|
289
|
+
*
|
|
290
|
+
* @param args - the arguments to hash
|
|
291
|
+
* @returns base64 SHA-256 digest or undefined
|
|
292
|
+
*/
|
|
293
|
+
export function argumentsHash(args) {
|
|
294
|
+
const hash = createHash("sha256");
|
|
295
|
+
for (const arg of args) {
|
|
296
|
+
if (arg === null) {
|
|
297
|
+
hash.update("null");
|
|
298
|
+
}
|
|
299
|
+
else if (arg === undefined) {
|
|
300
|
+
hash.update("undefined");
|
|
301
|
+
}
|
|
302
|
+
else if (typeof arg === "string" || typeof arg === "number" || typeof arg === "boolean") {
|
|
303
|
+
// Primitives can be directly stringified
|
|
304
|
+
hash.update(String(arg));
|
|
305
|
+
}
|
|
306
|
+
else if (typeof arg.toJSON === "function") {
|
|
307
|
+
// Try toJSON first for objects with custom serialization
|
|
308
|
+
try {
|
|
309
|
+
hash.update(JSON.stringify(arg.toJSON()));
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (Array.isArray(arg) || (typeof arg === "object" && arg.constructor === Object)) {
|
|
316
|
+
// Plain objects and arrays - use JSON.stringify
|
|
317
|
+
try {
|
|
318
|
+
hash.update(JSON.stringify(arg));
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
else if (typeof arg.toString === "function" && arg.toString !== Object.prototype.toString) {
|
|
325
|
+
// Custom toString implementation (not the default [object Object])
|
|
326
|
+
hash.update(arg.toString());
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// We cannot find a deterministic representation for the object
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return hash.digest("base64");
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Compute a simple typed key for a list of arguments without hashing.
|
|
337
|
+
*
|
|
338
|
+
* Uses length-prefixed, type-tagged encoding to produce a unique string
|
|
339
|
+
* representation for each distinct argument list, or `undefined` if any
|
|
340
|
+
* argument cannot be serialized deterministically.
|
|
341
|
+
*
|
|
342
|
+
* Format per argument: `<TYPE><LENGTH>:<VALUE>` where TYPE is a single
|
|
343
|
+
* uppercase letter identifying the argument type. No separator is needed
|
|
344
|
+
* between arguments because the length prefix makes the encoding unambiguous.
|
|
345
|
+
*
|
|
346
|
+
* This is faster than {@link argumentsHash} because it skips the SHA-256
|
|
347
|
+
* step. Keys may be longer in proportion to argument size. Prefer this
|
|
348
|
+
* strategy for hot sync paths with small, simple arguments.
|
|
349
|
+
*
|
|
350
|
+
* @param args - the arguments to encode
|
|
351
|
+
* @returns typed key string or undefined
|
|
352
|
+
*/
|
|
353
|
+
export function argumentsSimpleKey(args) {
|
|
354
|
+
const parts = [];
|
|
355
|
+
for (const arg of args) {
|
|
356
|
+
if (arg === null) {
|
|
357
|
+
// N — no content needed, null is unambiguous
|
|
358
|
+
parts.push("N");
|
|
359
|
+
}
|
|
360
|
+
else if (arg === undefined) {
|
|
361
|
+
// X — no content needed, undefined is unambiguous
|
|
362
|
+
parts.push("X");
|
|
363
|
+
}
|
|
364
|
+
else if (typeof arg === "string") {
|
|
365
|
+
parts.push("S" + arg.length + ":" + arg);
|
|
366
|
+
}
|
|
367
|
+
else if (typeof arg === "number") {
|
|
368
|
+
const s = String(arg);
|
|
369
|
+
parts.push("D" + s.length + ":" + s);
|
|
370
|
+
}
|
|
371
|
+
else if (typeof arg === "boolean") {
|
|
372
|
+
const s = String(arg);
|
|
373
|
+
parts.push("B" + s.length + ":" + s);
|
|
374
|
+
}
|
|
375
|
+
else if (typeof arg.toJSON === "function") {
|
|
376
|
+
try {
|
|
377
|
+
const j = JSON.stringify(arg.toJSON());
|
|
378
|
+
parts.push("J" + j.length + ":" + j);
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
else if (Array.isArray(arg) || (typeof arg === "object" && arg.constructor === Object)) {
|
|
385
|
+
try {
|
|
386
|
+
const j = JSON.stringify(arg);
|
|
387
|
+
parts.push("O" + j.length + ":" + j);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else if (typeof arg.toString === "function" && arg.toString !== Object.prototype.toString) {
|
|
394
|
+
const s = arg.toString();
|
|
395
|
+
parts.push("T" + s.length + ":" + s);
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return parts.join("");
|
|
402
|
+
}
|
|
403
|
+
let cacheLogger = (...args) => { };
|
|
404
|
+
/**
|
|
405
|
+
* Register a logger used by the cache system to report non-cacheable calls.
|
|
406
|
+
*
|
|
407
|
+
* @param logger - the logging function to register
|
|
408
|
+
*/
|
|
409
|
+
export function registerCacheLogger(logger) {
|
|
410
|
+
cacheLogger = logger;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Create a cache annotation (method decorator) bound to a given source provider.
|
|
414
|
+
*
|
|
415
|
+
* The returned decorator caches method results based on keys generated by
|
|
416
|
+
* `methodKeyGenerator` and `classKeyGenerator`. It also exposes utility methods:
|
|
417
|
+
* - `clear(target, propertyKey, ...args)`: Clear specific cache entry
|
|
418
|
+
* - `clearAll(target, propertyKey?)`: Clear all or method-prefixed entries
|
|
419
|
+
* - `garbageCollect()`: Run TTL-based cleanup
|
|
420
|
+
*
|
|
421
|
+
* @param source - function returning the cache host for a given target
|
|
422
|
+
* @param options - cache configuration options
|
|
423
|
+
* @returns the cache method decorator with utility methods
|
|
424
|
+
*/
|
|
425
|
+
export function createCacheAnnotation(source, options = {}) {
|
|
426
|
+
options.methodKeyGenerator ?? (options.methodKeyGenerator = (property, args) => {
|
|
427
|
+
if (options.hashStrategy === "simple") {
|
|
428
|
+
const key = argumentsSimpleKey(args);
|
|
429
|
+
return key !== undefined ? property + "$" + key : undefined;
|
|
430
|
+
}
|
|
431
|
+
const hash = argumentsHash(args);
|
|
432
|
+
return hash ? property + "$" + hash : undefined;
|
|
433
|
+
});
|
|
434
|
+
options.classKeyGenerator ?? (options.classKeyGenerator = (instance) => instance);
|
|
435
|
+
const globalOptions = options;
|
|
436
|
+
const annotation = createMethodDecorator((value, context, decoratorOptions) => {
|
|
437
|
+
var _a, _b;
|
|
438
|
+
const options = { ...globalOptions, ...decoratorOptions };
|
|
439
|
+
if (options.methodKeyGenerator && context.metadata) {
|
|
440
|
+
(_a = context.metadata)["webda.cache.methodKeyGenerator"] ?? (_a["webda.cache.methodKeyGenerator"] = {});
|
|
441
|
+
context.metadata["webda.cache.methodKeyGenerator"][value.name] = options.methodKeyGenerator;
|
|
442
|
+
}
|
|
443
|
+
if (options.classKeyGenerator && context.metadata) {
|
|
444
|
+
(_b = context.metadata)["webda.cache.classKeyGenerator"] ?? (_b["webda.cache.classKeyGenerator"] = {});
|
|
445
|
+
context.metadata["webda.cache.classKeyGenerator"][value.name] = options.classKeyGenerator;
|
|
446
|
+
}
|
|
447
|
+
options.methodKeyGenerator ?? (options.methodKeyGenerator = globalOptions.methodKeyGenerator);
|
|
448
|
+
options.classKeyGenerator ?? (options.classKeyGenerator = globalOptions.classKeyGenerator);
|
|
449
|
+
// eslint-disable-next-line func-names -- required to keep 'this' context
|
|
450
|
+
return function (...args) {
|
|
451
|
+
const cache = getSource(source, options, this);
|
|
452
|
+
const key = options.methodKeyGenerator(value.name, args);
|
|
453
|
+
const instanceKey = options.classKeyGenerator(this);
|
|
454
|
+
if (key && instanceKey && cache && cache.hasCachedMethod(instanceKey, key)) {
|
|
455
|
+
return cache.getCachedMethod(instanceKey, key);
|
|
456
|
+
}
|
|
457
|
+
const res = value.apply(this, args);
|
|
458
|
+
// Handle both sync and async methods
|
|
459
|
+
if (res instanceof Promise) {
|
|
460
|
+
// For async methods, cache the Promise itself to handle concurrent calls
|
|
461
|
+
// but replace it with the resolved value once it resolves
|
|
462
|
+
if (key && instanceKey && cache) {
|
|
463
|
+
cache.setCachedMethod(instanceKey, key, args, res);
|
|
464
|
+
}
|
|
465
|
+
return res
|
|
466
|
+
.then((resolvedValue) => {
|
|
467
|
+
if (key && instanceKey && cache) {
|
|
468
|
+
if (!options.shouldCache || options.shouldCache(resolvedValue)) {
|
|
469
|
+
// Replace Promise with resolved value
|
|
470
|
+
cache.setCachedMethod(instanceKey, key, args, resolvedValue);
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
// shouldCache returned false: remove the pending Promise entry
|
|
474
|
+
if (cache.has(instanceKey)) {
|
|
475
|
+
cache.get(instanceKey).deleteCachedMethod(key);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return resolvedValue;
|
|
480
|
+
})
|
|
481
|
+
.catch((error) => {
|
|
482
|
+
// Remove from cache on error so it can be retried
|
|
483
|
+
if (key && instanceKey && cache && cache.has(instanceKey)) {
|
|
484
|
+
cache.get(instanceKey).deleteCachedMethod(key);
|
|
485
|
+
}
|
|
486
|
+
throw error;
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
// Sync method
|
|
490
|
+
if (key && instanceKey && cache) {
|
|
491
|
+
if (!options.shouldCache || options.shouldCache(res)) {
|
|
492
|
+
cache.setCachedMethod(instanceKey, key, args, res);
|
|
493
|
+
}
|
|
494
|
+
// shouldCache returning false is intentional — no warning needed
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
cacheLogger("WARN", "Cache cannot be stored, no key generated", this, value.name, args);
|
|
498
|
+
}
|
|
499
|
+
return res;
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
/**
|
|
503
|
+
* Clear a specific cached entry for a target method and arguments.
|
|
504
|
+
*
|
|
505
|
+
* @param target - the instance to clear cache for
|
|
506
|
+
* @param propertyKey - the method name
|
|
507
|
+
* @param args - the method arguments identifying the entry
|
|
508
|
+
*/
|
|
509
|
+
annotation.clear = function clearCache(target, propertyKey, ...args) {
|
|
510
|
+
const cache = getSource(source, options, target);
|
|
511
|
+
if (!cache)
|
|
512
|
+
return;
|
|
513
|
+
const metadata = getMetadata((target.constructor ?? target));
|
|
514
|
+
const keyGenerator = metadata?.["webda.cache.methodKeyGenerator"]?.[propertyKey] || options.methodKeyGenerator;
|
|
515
|
+
const classKeyGen = metadata?.["webda.cache.classKeyGenerator"]?.[propertyKey] || options.classKeyGenerator;
|
|
516
|
+
const instanceKey = classKeyGen(target);
|
|
517
|
+
const key = keyGenerator(propertyKey, args);
|
|
518
|
+
if (cache.has(instanceKey)) {
|
|
519
|
+
cache.get(instanceKey).deleteCachedMethod(key);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
/**
|
|
523
|
+
* Clear all cached entries for a target, or only those for a specific method.
|
|
524
|
+
*
|
|
525
|
+
* If `propertyKey` is provided, all entries with that method prefix are removed.
|
|
526
|
+
*
|
|
527
|
+
* @param target - the instance to clear cache for
|
|
528
|
+
* @param propertyKey - optional method name to scope clearing
|
|
529
|
+
*/
|
|
530
|
+
annotation.clearAll = function clearAllCache(target, propertyKey) {
|
|
531
|
+
const cache = getSource(source, options, target);
|
|
532
|
+
if (!cache)
|
|
533
|
+
return;
|
|
534
|
+
const metadata = getMetadata((target.constructor ?? target));
|
|
535
|
+
const classKeyGen = propertyKey
|
|
536
|
+
? metadata?.["webda.cache.classKeyGenerator"]?.[propertyKey] || options.classKeyGenerator
|
|
537
|
+
: options.classKeyGenerator;
|
|
538
|
+
const instanceKey = classKeyGen(target);
|
|
539
|
+
if (cache.has(instanceKey)) {
|
|
540
|
+
if (propertyKey === undefined) {
|
|
541
|
+
cache.delete(instanceKey);
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
cache.get(instanceKey).deleteCachedMethod(propertyKey + "$");
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
/**
|
|
549
|
+
* Run garbage collection on the underlying `CacheMap`.
|
|
550
|
+
*/
|
|
551
|
+
annotation.garbageCollect = function garbageCollect() {
|
|
552
|
+
const cache = getSource(source, options, null);
|
|
553
|
+
if (cache) {
|
|
554
|
+
cache.garbageCollect();
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
/**
|
|
558
|
+
* Get aggregated cache statistics.
|
|
559
|
+
*
|
|
560
|
+
* @returns the aggregated stats
|
|
561
|
+
*/
|
|
562
|
+
annotation.getStats = function getStats() {
|
|
563
|
+
const cache = getSource(source, options, null);
|
|
564
|
+
if (cache) {
|
|
565
|
+
return cache.getStats();
|
|
566
|
+
}
|
|
567
|
+
return { hits: 0, misses: 0, evictions: 0, sets: 0 };
|
|
568
|
+
};
|
|
569
|
+
/**
|
|
570
|
+
* Reset cache statistics.
|
|
571
|
+
*/
|
|
572
|
+
annotation.resetStats = function resetStats() {
|
|
573
|
+
const cache = getSource(source, options, null);
|
|
574
|
+
if (cache) {
|
|
575
|
+
cache.resetStats();
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
return annotation;
|
|
579
|
+
}
|
|
580
|
+
const symbol = Symbol.for("webda.caches");
|
|
581
|
+
/**
|
|
582
|
+
* Cache decorator using a process-level storage.
|
|
583
|
+
*
|
|
584
|
+
* Suitable for cross-instance caching within the same Node.js process.
|
|
585
|
+
*/
|
|
586
|
+
const ProcessCache = createCacheAnnotation(() => {
|
|
587
|
+
const p = process;
|
|
588
|
+
p[symbol] ?? (p[symbol] = {});
|
|
589
|
+
return p[symbol];
|
|
590
|
+
});
|
|
591
|
+
/**
|
|
592
|
+
* Cache decorator using an object-level storage (per instance).
|
|
593
|
+
*
|
|
594
|
+
* Suitable for encapsulated caches tied to specific objects.
|
|
595
|
+
*/
|
|
596
|
+
const ObjectCache = createCacheAnnotation((target) => {
|
|
597
|
+
if (target === null)
|
|
598
|
+
return null;
|
|
599
|
+
const t = target;
|
|
600
|
+
t[symbol] ?? (t[symbol] = {});
|
|
601
|
+
return t[symbol];
|
|
602
|
+
});
|
|
603
|
+
export { ProcessCache, ObjectCache };
|
|
604
|
+
//# sourceMappingURL=cache.js.map
|
package/lib/cache.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAqFzC;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAa,SAAQ,GAA8C;IAG9E;;OAEG;IACH,YAAoB,OAAsB;QACxC,KAAK,EAAE,CAAC;QADU,YAAO,GAAP,OAAO,CAAe;QAL1C,UAAK,GAAe,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAOlE,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CAAC,GAAW;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE7B,gCAAgC;QAChC,IAAI,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,MAAM,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBAC/D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjB,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;oBAC7B,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;gBACzB,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;OASG;IACH,eAAe,CAAC,GAAW,EAAE,KAAY,EAAE,KAAU;QACnD,6EAA6E;QAC7E,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;QAED,mDAAmD;QACnD,IAAI,IAAI,CAAC,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC/D,iEAAiE;YACjE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC3C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACvB,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;oBAC7B,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,eAAe,CAAC,GAAW;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,OAAO,MAAM,EAAE,KAAK,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,GAAW;QAC5B,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,6CAA6C;YAC9E,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC5B,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACjB,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,IAAI,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClD,IAAI,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;oBACvC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACjB,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YACD,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAC5C,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAC7D,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,QAAoC,SAAQ,GAAoB;IAG3E;;OAEG;IACH,YAAoB,OAAsB;QACxC,KAAK,EAAE,CAAC;uBADU,OAAO;QAEzB,+DAA+D;QAC/D,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YAC5D,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CAAC,MAAS,EAAE,GAAW;QACpC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IAED;;;;;;;OAOG;IACH,eAAe,CAAC,MAAS,EAAE,GAAW;QACpC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,IAAI,MAAM,EAAE,CAAC;gBACxC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACrB,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;OAQG;IACH,eAAe,CAAC,MAAS,EAAE,GAAW,EAAE,KAAY,EAAE,KAAU;QAC9D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,IAAI,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;QAChC,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACzC,gDAAgD;QAChD,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC;YAC5C,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,WAAW;QACjB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,kBAAkB;QAC5B,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,EAAE,IAAI,CAAC,OAAQ,CAAC,UAAW,CAAC,CAAC;QAC9B,gDAAgD;QAChD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,QAAQ;QACN,MAAM,UAAU,GAAe,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC7E,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC/B,UAAU,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;YAC9B,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;YAClC,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC;YACxC,UAAU,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;QAChC,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YAClC,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;CACF;AASD;;;;;;;;;;;GAWG;AACH,SAAS,SAAS,CAChB,QAAqD,EACrD,OAAqB,EACrB,MAAqB;IAErB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,MAAM,KAAZ,KAAK,CAAC,MAAM,GAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAC;IAC7D,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,IAAW;IACvC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,SAAS,EAAE,CAAC;YAC1F,yCAAyC;YACzC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC5C,yDAAyD;YACzD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,KAAK,MAAM,CAAC,EAAE,CAAC;YACzF,gDAAgD;YAChD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YAC5F,mEAAmE;YACnE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,+DAA+D;YAC/D,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAW;IAC5C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,6CAA6C;YAC7C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,kDAAkD;YAClD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC5C,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;gBACvC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,KAAK,MAAM,CAAC,EAAE,CAAC;YACzF,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YAC5F,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,IAAI,WAAW,GAA6B,CAAC,GAAG,IAAW,EAAE,EAAE,GAAE,CAAC,CAAC;AACnE;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAgC;IAClE,WAAW,GAAG,MAAM,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAgD,EAAE,OAAO,GAAiB,EAAE;IAChH,OAAO,CAAC,kBAAkB,KAA1B,OAAO,CAAC,kBAAkB,GAAK,CAAC,QAAgB,EAAE,IAAW,EAAE,EAAE;QAC/D,IAAI,OAAO,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YACrC,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC,EAAC;IAEF,OAAO,CAAC,iBAAiB,KAAzB,OAAO,CAAC,iBAAiB,GAAK,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,EAAC;IAC7D,MAAM,aAAa,GAAG,OAAO,CAAC;IAE9B,MAAM,UAAU,GAAG,qBAAqB,CACtC,CACE,KAAU,EACV,OAAoC,EACpC,gBAGC,EACD,EAAE;;QACF,MAAM,OAAO,GAAiB,EAAE,GAAG,aAAa,EAAE,GAAG,gBAAgB,EAAE,CAAC;QACxE,IAAI,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnD,MAAC,OAAO,CAAC,QAAgB,EAAC,gCAAgC,SAAhC,gCAAgC,IAAM,EAAE,EAAC;YAClE,OAAO,CAAC,QAAgB,CAAC,gCAAgC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;QACvG,CAAC;QACD,IAAI,OAAO,CAAC,iBAAiB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YAClD,MAAC,OAAO,CAAC,QAAgB,EAAC,+BAA+B,SAA/B,+BAA+B,IAAM,EAAE,EAAC;YACjE,OAAO,CAAC,QAAgB,CAAC,+BAA+B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACrG,CAAC;QACD,OAAO,CAAC,kBAAkB,KAA1B,OAAO,CAAC,kBAAkB,GAAK,aAAa,CAAC,kBAAkB,EAAC;QAChE,OAAO,CAAC,iBAAiB,KAAzB,OAAO,CAAC,iBAAiB,GAAK,aAAa,CAAC,iBAAiB,EAAC;QAE9D,yEAAyE;QACzE,OAAO,UAAqB,GAAG,IAAW;YACxC,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,kBAAmB,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAkB,CAAC,IAAI,CAAC,CAAC;YAErD,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK,IAAI,KAAK,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC3E,OAAO,KAAK,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YACjD,CAAC;YAED,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAEpC,qCAAqC;YACrC,IAAI,GAAG,YAAY,OAAO,EAAE,CAAC;gBAC3B,yEAAyE;gBACzE,0DAA0D;gBAC1D,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;oBAChC,KAAK,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;gBACrD,CAAC;gBAED,OAAO,GAAG;qBACP,IAAI,CAAC,CAAC,aAAkB,EAAE,EAAE;oBAC3B,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;wBAChC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC;4BAC/D,sCAAsC;4BACtC,KAAK,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;wBAC/D,CAAC;6BAAM,CAAC;4BACN,+DAA+D;4BAC/D,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gCAC3B,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;4BAClD,CAAC;wBACH,CAAC;oBACH,CAAC;oBACD,OAAO,aAAa,CAAC;gBACvB,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;oBACpB,kDAAkD;oBAClD,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;wBAC1D,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;oBAClD,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC,CAAC,CAAC;YACP,CAAC;YAED,cAAc;YACd,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;oBACrD,KAAK,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;gBACrD,CAAC;gBACD,iEAAiE;YACnE,CAAC;iBAAM,CAAC;gBACN,WAAW,CAAC,MAAM,EAAE,0CAA0C,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC1F,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC;IACJ,CAAC,CAOF,CAAC;IAEF;;;;;;OAMG;IACH,UAAU,CAAC,KAAK,GAAG,SAAS,UAAU,CAAC,MAAc,EAAE,WAAmB,EAAE,GAAG,IAAW;QACxF,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAQ,CAAQ,CAAC;QAC3E,MAAM,YAAY,GAAG,QAAQ,EAAE,CAAC,gCAAgC,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,kBAAmB,CAAC;QAChH,MAAM,WAAW,GAAG,QAAQ,EAAE,CAAC,+BAA+B,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,iBAAkB,CAAC;QAC7G,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC5C,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;IACH,CAAC,CAAC;IAEF;;;;;;;OAOG;IACH,UAAU,CAAC,QAAQ,GAAG,SAAS,aAAa,CAAC,MAAc,EAAE,WAAoB;QAC/E,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAQ,CAAQ,CAAC;QAC3E,MAAM,WAAW,GAAG,WAAW;YAC7B,CAAC,CAAC,QAAQ,EAAE,CAAC,+BAA+B,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,iBAAkB;YAC1F,CAAC,CAAC,OAAO,CAAC,iBAAkB,CAAC;QAC/B,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAExC,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,kBAAkB,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF;;OAEG;IACH,UAAU,CAAC,cAAc,GAAG,SAAS,cAAc;QACjD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IAEF;;;;OAIG;IACH,UAAU,CAAC,QAAQ,GAAG,SAAS,QAAQ;QACrC,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC1B,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACvD,CAAC,CAAC;IAEF;;OAEG;IACH,UAAU,CAAC,UAAU,GAAG,SAAS,UAAU;QACzC,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAE1C;;;;GAIG;AACH,MAAM,YAAY,GAAG,qBAAqB,CAAC,GAAG,EAAE;IAC9C,MAAM,CAAC,GAAG,OAAc,CAAC;IACzB,CAAC,CAAC,MAAM,MAAR,CAAC,CAAC,MAAM,IAAM,EAAE,EAAC;IACjB,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,WAAW,GAAG,qBAAqB,CAAC,CAAC,MAAqB,EAAE,EAAE;IAClE,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,CAAC,GAAG,MAAa,CAAC;IACxB,CAAC,CAAC,MAAM,MAAR,CAAC,CAAC,MAAM,IAAM,EAAE,EAAC;IACjB,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./cache.js";
|
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webda/cache",
|
|
3
|
+
"version": "4.0.0-beta.3",
|
|
4
|
+
"description": "A flexible method-level caching library with decorator support, TTL expiration, and multiple storage strategies",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"webda"
|
|
7
|
+
],
|
|
8
|
+
"author": "Remi Cattiau <remi@cattiau.com>",
|
|
9
|
+
"repository": "git://github.com/loopingz/webda.io.git",
|
|
10
|
+
"main": "lib/cache.js",
|
|
11
|
+
"typings": "lib/cache.d.ts",
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/node": "25.5.0",
|
|
14
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
15
|
+
"jscodeshift": "^17.3.0",
|
|
16
|
+
"skott": "^0.35.8",
|
|
17
|
+
"typescript": "7.1.0-dev.20260929.1",
|
|
18
|
+
"vite": "^6.0.0",
|
|
19
|
+
"vitest": "^4.1.2",
|
|
20
|
+
"@webda/compiler": "^4.0.0-beta.3",
|
|
21
|
+
"@webda/decorators": "^4.0.0-beta.3",
|
|
22
|
+
"@webda/test": "4.0.0-beta.3"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"lib"
|
|
26
|
+
],
|
|
27
|
+
"c8": {
|
|
28
|
+
"report-dir": "./reports",
|
|
29
|
+
"reporter": [
|
|
30
|
+
"html",
|
|
31
|
+
"lcov",
|
|
32
|
+
"json",
|
|
33
|
+
"text"
|
|
34
|
+
],
|
|
35
|
+
"exclude": [
|
|
36
|
+
"src/test.ts",
|
|
37
|
+
"**/*.spec.ts",
|
|
38
|
+
"test/**/*",
|
|
39
|
+
"*/stores/webdaql/WebdaQL*"
|
|
40
|
+
],
|
|
41
|
+
"excludeNodeModules": true
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://webda.io",
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"type": "module",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=22.0.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc",
|
|
53
|
+
"build:watch": "tsc --watch",
|
|
54
|
+
"pretest": "npm run build",
|
|
55
|
+
"format": "prettier --check src/**/*",
|
|
56
|
+
"format:fix": "prettier --write src/**/*",
|
|
57
|
+
"lint": "eslint",
|
|
58
|
+
"lint:fix": "eslint --fix",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:watch": "vitest",
|
|
61
|
+
"test:debug": "vitest debug",
|
|
62
|
+
"test:coverage": "vitest run --coverage",
|
|
63
|
+
"deps:graph": "skott --showCircularDependencies --no-trackTypeOnlyDependencies --displayMode=raw -e .ts"
|
|
64
|
+
}
|
|
65
|
+
}
|