@carno.js/core 1.1.1 → 1.2.0
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 +21 -21
- package/README.md +188 -188
- package/dist/Carno.js +45 -26
- package/dist/Carno.mjs +45 -26
- package/dist/bun/index.js +4 -4
- package/dist/bun/index.js.map +30 -29
- package/dist/compression/CompressionMiddleware.js +110 -0
- package/dist/compression/CompressionMiddleware.mjs +90 -0
- package/dist/index.js +3 -1
- package/dist/index.mjs +2 -0
- package/package.json +2 -2
- package/src/Carno.ts +728 -673
- package/src/DefaultRoutes.ts +34 -34
- package/src/cache/CacheDriver.ts +50 -50
- package/src/cache/CacheService.ts +139 -139
- package/src/cache/MemoryDriver.ts +104 -104
- package/src/cache/RedisDriver.ts +116 -116
- package/src/compiler/JITCompiler.ts +167 -167
- package/src/compression/CompressionMiddleware.ts +221 -0
- package/src/container/Container.ts +168 -168
- package/src/context/Context.ts +130 -130
- package/src/cors/CorsHandler.ts +145 -145
- package/src/decorators/Controller.ts +63 -63
- package/src/decorators/Inject.ts +16 -16
- package/src/decorators/Middleware.ts +22 -22
- package/src/decorators/Service.ts +18 -18
- package/src/decorators/methods.ts +58 -58
- package/src/decorators/params.ts +47 -47
- package/src/events/Lifecycle.ts +97 -97
- package/src/exceptions/HttpException.ts +99 -99
- package/src/index.ts +99 -95
- package/src/metadata.ts +46 -46
- package/src/middleware/CarnoMiddleware.ts +20 -14
- package/src/router/RadixRouter.ts +225 -225
- package/src/testing/TestHarness.ts +185 -185
- package/src/utils/Metadata.ts +43 -43
- package/src/utils/parseQuery.ts +161 -161
- package/src/validation/ValibotAdapter.ts +95 -95
- package/src/validation/ValidatorAdapter.ts +69 -69
- package/src/validation/ZodAdapter.ts +102 -102
- package/dist/Carno.d.js +0 -14
- package/dist/Carno.d.mjs +0 -1
- package/dist/DefaultRoutes.d.js +0 -13
- package/dist/DefaultRoutes.d.mjs +0 -0
- package/dist/cache/CacheDriver.d.js +0 -13
- package/dist/cache/CacheDriver.d.mjs +0 -0
- package/dist/cache/CacheService.d.js +0 -13
- package/dist/cache/CacheService.d.mjs +0 -0
- package/dist/cache/MemoryDriver.d.js +0 -13
- package/dist/cache/MemoryDriver.d.mjs +0 -0
- package/dist/cache/RedisDriver.d.js +0 -13
- package/dist/cache/RedisDriver.d.mjs +0 -0
- package/dist/compiler/JITCompiler.d.js +0 -13
- package/dist/compiler/JITCompiler.d.mjs +0 -0
- package/dist/container/Container.d.js +0 -13
- package/dist/container/Container.d.mjs +0 -0
- package/dist/context/Context.d.js +0 -13
- package/dist/context/Context.d.mjs +0 -0
- package/dist/cors/CorsHandler.d.js +0 -13
- package/dist/cors/CorsHandler.d.mjs +0 -0
- package/dist/decorators/Controller.d.js +0 -13
- package/dist/decorators/Controller.d.mjs +0 -0
- package/dist/decorators/Inject.d.js +0 -13
- package/dist/decorators/Inject.d.mjs +0 -0
- package/dist/decorators/Middleware.d.js +0 -13
- package/dist/decorators/Middleware.d.mjs +0 -0
- package/dist/decorators/Service.d.js +0 -13
- package/dist/decorators/Service.d.mjs +0 -0
- package/dist/decorators/methods.d.js +0 -13
- package/dist/decorators/methods.d.mjs +0 -0
- package/dist/decorators/params.d.js +0 -13
- package/dist/decorators/params.d.mjs +0 -0
- package/dist/events/Lifecycle.d.js +0 -13
- package/dist/events/Lifecycle.d.mjs +0 -0
- package/dist/exceptions/HttpException.d.js +0 -13
- package/dist/exceptions/HttpException.d.mjs +0 -0
- package/dist/index.d.js +0 -130
- package/dist/index.d.mjs +0 -78
- package/dist/metadata.d.js +0 -13
- package/dist/metadata.d.mjs +0 -0
- package/dist/middleware/CarnoMiddleware.d.js +0 -13
- package/dist/middleware/CarnoMiddleware.d.mjs +0 -0
- package/dist/router/RadixRouter.d.js +0 -13
- package/dist/router/RadixRouter.d.mjs +0 -0
- package/dist/testing/TestHarness.d.js +0 -13
- package/dist/testing/TestHarness.d.mjs +0 -0
- package/dist/utils/Metadata.d.js +0 -13
- package/dist/utils/Metadata.d.mjs +0 -0
- package/dist/utils/parseQuery.d.js +0 -13
- package/dist/utils/parseQuery.d.mjs +0 -0
- package/dist/validation/ValibotAdapter.d.js +0 -13
- package/dist/validation/ValibotAdapter.d.mjs +0 -0
- package/dist/validation/ValidatorAdapter.d.js +0 -13
- package/dist/validation/ValidatorAdapter.d.mjs +0 -0
- package/dist/validation/ZodAdapter.d.js +0 -13
- package/dist/validation/ZodAdapter.d.mjs +0 -0
- package/src/Carno.d.ts +0 -135
- package/src/DefaultRoutes.d.ts +0 -19
- package/src/cache/CacheDriver.d.ts +0 -43
- package/src/cache/CacheService.d.ts +0 -89
- package/src/cache/MemoryDriver.d.ts +0 -32
- package/src/cache/RedisDriver.d.ts +0 -34
- package/src/compiler/JITCompiler.d.ts +0 -36
- package/src/container/Container.d.ts +0 -38
- package/src/context/Context.d.ts +0 -36
- package/src/cors/CorsHandler.d.ts +0 -47
- package/src/decorators/Controller.d.ts +0 -13
- package/src/decorators/Inject.d.ts +0 -6
- package/src/decorators/Middleware.d.ts +0 -5
- package/src/decorators/Service.d.ts +0 -9
- package/src/decorators/methods.d.ts +0 -7
- package/src/decorators/params.d.ts +0 -13
- package/src/events/Lifecycle.d.ts +0 -54
- package/src/exceptions/HttpException.d.ts +0 -43
- package/src/index.d.ts +0 -42
- package/src/metadata.d.ts +0 -41
- package/src/middleware/CarnoMiddleware.d.ts +0 -12
- package/src/router/RadixRouter.d.ts +0 -19
- package/src/testing/TestHarness.d.ts +0 -71
- package/src/utils/Metadata.d.ts +0 -20
- package/src/utils/parseQuery.d.ts +0 -23
- package/src/validation/ValibotAdapter.d.ts +0 -30
- package/src/validation/ValidatorAdapter.d.ts +0 -54
- package/src/validation/ZodAdapter.d.ts +0 -35
package/src/DefaultRoutes.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { Controller } from './decorators/Controller';
|
|
2
|
-
import { Get } from './decorators/methods';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Default routes controller.
|
|
6
|
-
* Auto-registered by Turbo for common endpoints.
|
|
7
|
-
*/
|
|
8
|
-
@Controller()
|
|
9
|
-
export class DefaultRoutes {
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Favicon - returns empty response to prevent 404.
|
|
13
|
-
*/
|
|
14
|
-
@Get('/favicon.ico')
|
|
15
|
-
favicon() {
|
|
16
|
-
return new Response(null, { status: 204 });
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Pre-compiled static responses for maximum performance.
|
|
22
|
-
* Use these directly in Bun.serve static routes.
|
|
23
|
-
*/
|
|
24
|
-
export const DEFAULT_STATIC_ROUTES = {
|
|
25
|
-
'/health': new Response('{"status":"ok"}', {
|
|
26
|
-
status: 200,
|
|
27
|
-
headers: { 'Content-Type': 'application/json' }
|
|
28
|
-
}),
|
|
29
|
-
'/ready': new Response('{"ready":true}', {
|
|
30
|
-
status: 200,
|
|
31
|
-
headers: { 'Content-Type': 'application/json' }
|
|
32
|
-
}),
|
|
33
|
-
'/favicon.ico': new Response(null, { status: 204 })
|
|
34
|
-
};
|
|
1
|
+
import { Controller } from './decorators/Controller';
|
|
2
|
+
import { Get } from './decorators/methods';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Default routes controller.
|
|
6
|
+
* Auto-registered by Turbo for common endpoints.
|
|
7
|
+
*/
|
|
8
|
+
@Controller()
|
|
9
|
+
export class DefaultRoutes {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Favicon - returns empty response to prevent 404.
|
|
13
|
+
*/
|
|
14
|
+
@Get('/favicon.ico')
|
|
15
|
+
favicon() {
|
|
16
|
+
return new Response(null, { status: 204 });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pre-compiled static responses for maximum performance.
|
|
22
|
+
* Use these directly in Bun.serve static routes.
|
|
23
|
+
*/
|
|
24
|
+
export const DEFAULT_STATIC_ROUTES = {
|
|
25
|
+
'/health': new Response('{"status":"ok"}', {
|
|
26
|
+
status: 200,
|
|
27
|
+
headers: { 'Content-Type': 'application/json' }
|
|
28
|
+
}),
|
|
29
|
+
'/ready': new Response('{"ready":true}', {
|
|
30
|
+
status: 200,
|
|
31
|
+
headers: { 'Content-Type': 'application/json' }
|
|
32
|
+
}),
|
|
33
|
+
'/favicon.ico': new Response(null, { status: 204 })
|
|
34
|
+
};
|
package/src/cache/CacheDriver.ts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cache Driver Interface.
|
|
3
|
-
* Implement this to add new cache backends (Redis, Memcached, etc.)
|
|
4
|
-
*/
|
|
5
|
-
export interface CacheDriver {
|
|
6
|
-
/**
|
|
7
|
-
* Driver name for debugging.
|
|
8
|
-
*/
|
|
9
|
-
readonly name: string;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Get a value from cache.
|
|
13
|
-
*/
|
|
14
|
-
get<T>(key: string): Promise<T | null>;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Set a value in cache.
|
|
18
|
-
* @param ttl Time to live in seconds (optional)
|
|
19
|
-
*/
|
|
20
|
-
set<T>(key: string, value: T, ttl?: number): Promise<boolean>;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Delete a value from cache.
|
|
24
|
-
*/
|
|
25
|
-
del(key: string): Promise<boolean>;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Check if key exists.
|
|
29
|
-
*/
|
|
30
|
-
has(key: string): Promise<boolean>;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Clear all cached values.
|
|
34
|
-
*/
|
|
35
|
-
clear(): Promise<void>;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Close connection (for Redis, etc.)
|
|
39
|
-
*/
|
|
40
|
-
close?(): Promise<void>;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Cache configuration.
|
|
45
|
-
*/
|
|
46
|
-
export interface CacheConfig {
|
|
47
|
-
driver?: CacheDriver;
|
|
48
|
-
prefix?: string;
|
|
49
|
-
defaultTtl?: number;
|
|
50
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Cache Driver Interface.
|
|
3
|
+
* Implement this to add new cache backends (Redis, Memcached, etc.)
|
|
4
|
+
*/
|
|
5
|
+
export interface CacheDriver {
|
|
6
|
+
/**
|
|
7
|
+
* Driver name for debugging.
|
|
8
|
+
*/
|
|
9
|
+
readonly name: string;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get a value from cache.
|
|
13
|
+
*/
|
|
14
|
+
get<T>(key: string): Promise<T | null>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Set a value in cache.
|
|
18
|
+
* @param ttl Time to live in seconds (optional)
|
|
19
|
+
*/
|
|
20
|
+
set<T>(key: string, value: T, ttl?: number): Promise<boolean>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Delete a value from cache.
|
|
24
|
+
*/
|
|
25
|
+
del(key: string): Promise<boolean>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if key exists.
|
|
29
|
+
*/
|
|
30
|
+
has(key: string): Promise<boolean>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Clear all cached values.
|
|
34
|
+
*/
|
|
35
|
+
clear(): Promise<void>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Close connection (for Redis, etc.)
|
|
39
|
+
*/
|
|
40
|
+
close?(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Cache configuration.
|
|
45
|
+
*/
|
|
46
|
+
export interface CacheConfig {
|
|
47
|
+
driver?: CacheDriver;
|
|
48
|
+
prefix?: string;
|
|
49
|
+
defaultTtl?: number;
|
|
50
|
+
}
|
|
@@ -1,139 +1,139 @@
|
|
|
1
|
-
import type { CacheDriver, CacheConfig } from './CacheDriver';
|
|
2
|
-
import { MemoryDriver } from './MemoryDriver';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* CacheService - High-performance caching with driver pattern.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - In-memory (default) or Redis backend
|
|
9
|
-
* - getOrSet for cache-aside pattern
|
|
10
|
-
* - Key prefixing for namespacing
|
|
11
|
-
* - Configurable default TTL
|
|
12
|
-
*
|
|
13
|
-
* Usage:
|
|
14
|
-
* ```typescript
|
|
15
|
-
* const cache = new CacheService();
|
|
16
|
-
*
|
|
17
|
-
* // Basic operations
|
|
18
|
-
* await cache.set('user:123', { name: 'John' }, 3600);
|
|
19
|
-
* const user = await cache.get<User>('user:123');
|
|
20
|
-
*
|
|
21
|
-
* // Cache-aside pattern
|
|
22
|
-
* const user = await cache.getOrSet('user:123',
|
|
23
|
-
* async () => db.findUser(123),
|
|
24
|
-
* 3600
|
|
25
|
-
* );
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export class CacheService {
|
|
29
|
-
private driver: CacheDriver;
|
|
30
|
-
private prefix: string;
|
|
31
|
-
private defaultTtl: number | undefined;
|
|
32
|
-
|
|
33
|
-
constructor(config: CacheConfig = {}) {
|
|
34
|
-
this.driver = config.driver || new MemoryDriver();
|
|
35
|
-
this.prefix = config.prefix || '';
|
|
36
|
-
this.defaultTtl = config.defaultTtl;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Get the full key with prefix.
|
|
41
|
-
*/
|
|
42
|
-
private key(key: string): string {
|
|
43
|
-
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Get a value from cache.
|
|
48
|
-
*/
|
|
49
|
-
async get<T>(key: string): Promise<T | null> {
|
|
50
|
-
return this.driver.get<T>(this.key(key));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Set a value in cache.
|
|
55
|
-
* @param ttl Time to live in seconds
|
|
56
|
-
*/
|
|
57
|
-
async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
|
|
58
|
-
return this.driver.set(this.key(key), value, ttl ?? this.defaultTtl);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Delete a value from cache.
|
|
63
|
-
*/
|
|
64
|
-
async del(key: string): Promise<boolean> {
|
|
65
|
-
return this.driver.del(this.key(key));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Check if key exists.
|
|
70
|
-
*/
|
|
71
|
-
async has(key: string): Promise<boolean> {
|
|
72
|
-
return this.driver.has(this.key(key));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Clear all cached values.
|
|
77
|
-
*/
|
|
78
|
-
async clear(): Promise<void> {
|
|
79
|
-
return this.driver.clear();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Get value from cache or compute and store it.
|
|
84
|
-
* This is the cache-aside pattern - most commonly used method.
|
|
85
|
-
*
|
|
86
|
-
* @param key Cache key
|
|
87
|
-
* @param cb Callback to compute value if not cached
|
|
88
|
-
* @param ttl Time to live in seconds
|
|
89
|
-
*/
|
|
90
|
-
async getOrSet<T>(key: string, cb: () => Promise<T>, ttl?: number): Promise<T> {
|
|
91
|
-
const cached = await this.get<T>(key);
|
|
92
|
-
|
|
93
|
-
if (cached !== null) {
|
|
94
|
-
return cached;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const value = await cb();
|
|
98
|
-
await this.set(key, value, ttl);
|
|
99
|
-
|
|
100
|
-
return value;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get multiple values at once.
|
|
105
|
-
*/
|
|
106
|
-
async getMany<T>(keys: string[]): Promise<(T | null)[]> {
|
|
107
|
-
return Promise.all(keys.map(key => this.get<T>(key)));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Set multiple values at once.
|
|
112
|
-
*/
|
|
113
|
-
async setMany<T>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<boolean[]> {
|
|
114
|
-
return Promise.all(
|
|
115
|
-
entries.map(entry => this.set(entry.key, entry.value, entry.ttl))
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Delete multiple values at once.
|
|
121
|
-
*/
|
|
122
|
-
async delMany(keys: string[]): Promise<boolean[]> {
|
|
123
|
-
return Promise.all(keys.map(key => this.del(key)));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Close the cache driver connection.
|
|
128
|
-
*/
|
|
129
|
-
async close(): Promise<void> {
|
|
130
|
-
await this.driver.close?.();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Get the underlying driver (for advanced use).
|
|
135
|
-
*/
|
|
136
|
-
getDriver(): CacheDriver {
|
|
137
|
-
return this.driver;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
1
|
+
import type { CacheDriver, CacheConfig } from './CacheDriver';
|
|
2
|
+
import { MemoryDriver } from './MemoryDriver';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CacheService - High-performance caching with driver pattern.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - In-memory (default) or Redis backend
|
|
9
|
+
* - getOrSet for cache-aside pattern
|
|
10
|
+
* - Key prefixing for namespacing
|
|
11
|
+
* - Configurable default TTL
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const cache = new CacheService();
|
|
16
|
+
*
|
|
17
|
+
* // Basic operations
|
|
18
|
+
* await cache.set('user:123', { name: 'John' }, 3600);
|
|
19
|
+
* const user = await cache.get<User>('user:123');
|
|
20
|
+
*
|
|
21
|
+
* // Cache-aside pattern
|
|
22
|
+
* const user = await cache.getOrSet('user:123',
|
|
23
|
+
* async () => db.findUser(123),
|
|
24
|
+
* 3600
|
|
25
|
+
* );
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class CacheService {
|
|
29
|
+
private driver: CacheDriver;
|
|
30
|
+
private prefix: string;
|
|
31
|
+
private defaultTtl: number | undefined;
|
|
32
|
+
|
|
33
|
+
constructor(config: CacheConfig = {}) {
|
|
34
|
+
this.driver = config.driver || new MemoryDriver();
|
|
35
|
+
this.prefix = config.prefix || '';
|
|
36
|
+
this.defaultTtl = config.defaultTtl;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the full key with prefix.
|
|
41
|
+
*/
|
|
42
|
+
private key(key: string): string {
|
|
43
|
+
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get a value from cache.
|
|
48
|
+
*/
|
|
49
|
+
async get<T>(key: string): Promise<T | null> {
|
|
50
|
+
return this.driver.get<T>(this.key(key));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Set a value in cache.
|
|
55
|
+
* @param ttl Time to live in seconds
|
|
56
|
+
*/
|
|
57
|
+
async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
|
|
58
|
+
return this.driver.set(this.key(key), value, ttl ?? this.defaultTtl);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Delete a value from cache.
|
|
63
|
+
*/
|
|
64
|
+
async del(key: string): Promise<boolean> {
|
|
65
|
+
return this.driver.del(this.key(key));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if key exists.
|
|
70
|
+
*/
|
|
71
|
+
async has(key: string): Promise<boolean> {
|
|
72
|
+
return this.driver.has(this.key(key));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Clear all cached values.
|
|
77
|
+
*/
|
|
78
|
+
async clear(): Promise<void> {
|
|
79
|
+
return this.driver.clear();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get value from cache or compute and store it.
|
|
84
|
+
* This is the cache-aside pattern - most commonly used method.
|
|
85
|
+
*
|
|
86
|
+
* @param key Cache key
|
|
87
|
+
* @param cb Callback to compute value if not cached
|
|
88
|
+
* @param ttl Time to live in seconds
|
|
89
|
+
*/
|
|
90
|
+
async getOrSet<T>(key: string, cb: () => Promise<T>, ttl?: number): Promise<T> {
|
|
91
|
+
const cached = await this.get<T>(key);
|
|
92
|
+
|
|
93
|
+
if (cached !== null) {
|
|
94
|
+
return cached;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const value = await cb();
|
|
98
|
+
await this.set(key, value, ttl);
|
|
99
|
+
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get multiple values at once.
|
|
105
|
+
*/
|
|
106
|
+
async getMany<T>(keys: string[]): Promise<(T | null)[]> {
|
|
107
|
+
return Promise.all(keys.map(key => this.get<T>(key)));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Set multiple values at once.
|
|
112
|
+
*/
|
|
113
|
+
async setMany<T>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<boolean[]> {
|
|
114
|
+
return Promise.all(
|
|
115
|
+
entries.map(entry => this.set(entry.key, entry.value, entry.ttl))
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Delete multiple values at once.
|
|
121
|
+
*/
|
|
122
|
+
async delMany(keys: string[]): Promise<boolean[]> {
|
|
123
|
+
return Promise.all(keys.map(key => this.del(key)));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Close the cache driver connection.
|
|
128
|
+
*/
|
|
129
|
+
async close(): Promise<void> {
|
|
130
|
+
await this.driver.close?.();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get the underlying driver (for advanced use).
|
|
135
|
+
*/
|
|
136
|
+
getDriver(): CacheDriver {
|
|
137
|
+
return this.driver;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
import type { CacheDriver } from './CacheDriver';
|
|
2
|
-
|
|
3
|
-
interface CacheEntry<T> {
|
|
4
|
-
value: T;
|
|
5
|
-
expiresAt: number | null;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* In-Memory Cache Driver.
|
|
10
|
-
* Ultra-fast, perfect for single-instance applications.
|
|
11
|
-
*
|
|
12
|
-
* Features:
|
|
13
|
-
* - O(1) get/set/del operations
|
|
14
|
-
* - Lazy expiration (checked on access)
|
|
15
|
-
* - Periodic cleanup of expired entries
|
|
16
|
-
*/
|
|
17
|
-
export class MemoryDriver implements CacheDriver {
|
|
18
|
-
readonly name = 'MemoryDriver';
|
|
19
|
-
|
|
20
|
-
private cache = new Map<string, CacheEntry<any>>();
|
|
21
|
-
private cleanupInterval: Timer | null = null;
|
|
22
|
-
|
|
23
|
-
constructor(cleanupIntervalMs: number = 0) {
|
|
24
|
-
// Periodic cleanup of expired entries (disabled by default for performance)
|
|
25
|
-
if (cleanupIntervalMs > 0) {
|
|
26
|
-
this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async get<T>(key: string): Promise<T | null> {
|
|
31
|
-
const entry = this.cache.get(key);
|
|
32
|
-
|
|
33
|
-
if (!entry) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Check expiration
|
|
38
|
-
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
39
|
-
this.cache.delete(key);
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return entry.value;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
|
|
47
|
-
const expiresAt = ttl ? Date.now() + ttl : null;
|
|
48
|
-
|
|
49
|
-
this.cache.set(key, { value, expiresAt });
|
|
50
|
-
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async del(key: string): Promise<boolean> {
|
|
55
|
-
return this.cache.delete(key);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async has(key: string): Promise<boolean> {
|
|
59
|
-
const entry = this.cache.get(key);
|
|
60
|
-
|
|
61
|
-
if (!entry) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
66
|
-
this.cache.delete(key);
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async clear(): Promise<void> {
|
|
74
|
-
this.cache.clear();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async close(): Promise<void> {
|
|
78
|
-
if (this.cleanupInterval) {
|
|
79
|
-
clearInterval(this.cleanupInterval);
|
|
80
|
-
this.cleanupInterval = null;
|
|
81
|
-
}
|
|
82
|
-
this.cache.clear();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Remove expired entries.
|
|
87
|
-
*/
|
|
88
|
-
private cleanup(): void {
|
|
89
|
-
const now = Date.now();
|
|
90
|
-
|
|
91
|
-
for (const [key, entry] of this.cache) {
|
|
92
|
-
if (entry.expiresAt !== null && now > entry.expiresAt) {
|
|
93
|
-
this.cache.delete(key);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Get cache stats (for debugging).
|
|
100
|
-
*/
|
|
101
|
-
stats(): { size: number } {
|
|
102
|
-
return { size: this.cache.size };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
1
|
+
import type { CacheDriver } from './CacheDriver';
|
|
2
|
+
|
|
3
|
+
interface CacheEntry<T> {
|
|
4
|
+
value: T;
|
|
5
|
+
expiresAt: number | null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* In-Memory Cache Driver.
|
|
10
|
+
* Ultra-fast, perfect for single-instance applications.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - O(1) get/set/del operations
|
|
14
|
+
* - Lazy expiration (checked on access)
|
|
15
|
+
* - Periodic cleanup of expired entries
|
|
16
|
+
*/
|
|
17
|
+
export class MemoryDriver implements CacheDriver {
|
|
18
|
+
readonly name = 'MemoryDriver';
|
|
19
|
+
|
|
20
|
+
private cache = new Map<string, CacheEntry<any>>();
|
|
21
|
+
private cleanupInterval: Timer | null = null;
|
|
22
|
+
|
|
23
|
+
constructor(cleanupIntervalMs: number = 0) {
|
|
24
|
+
// Periodic cleanup of expired entries (disabled by default for performance)
|
|
25
|
+
if (cleanupIntervalMs > 0) {
|
|
26
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async get<T>(key: string): Promise<T | null> {
|
|
31
|
+
const entry = this.cache.get(key);
|
|
32
|
+
|
|
33
|
+
if (!entry) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check expiration
|
|
38
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
39
|
+
this.cache.delete(key);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return entry.value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
|
|
47
|
+
const expiresAt = ttl ? Date.now() + ttl : null;
|
|
48
|
+
|
|
49
|
+
this.cache.set(key, { value, expiresAt });
|
|
50
|
+
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async del(key: string): Promise<boolean> {
|
|
55
|
+
return this.cache.delete(key);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async has(key: string): Promise<boolean> {
|
|
59
|
+
const entry = this.cache.get(key);
|
|
60
|
+
|
|
61
|
+
if (!entry) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
66
|
+
this.cache.delete(key);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async clear(): Promise<void> {
|
|
74
|
+
this.cache.clear();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async close(): Promise<void> {
|
|
78
|
+
if (this.cleanupInterval) {
|
|
79
|
+
clearInterval(this.cleanupInterval);
|
|
80
|
+
this.cleanupInterval = null;
|
|
81
|
+
}
|
|
82
|
+
this.cache.clear();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Remove expired entries.
|
|
87
|
+
*/
|
|
88
|
+
private cleanup(): void {
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
|
|
91
|
+
for (const [key, entry] of this.cache) {
|
|
92
|
+
if (entry.expiresAt !== null && now > entry.expiresAt) {
|
|
93
|
+
this.cache.delete(key);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get cache stats (for debugging).
|
|
100
|
+
*/
|
|
101
|
+
stats(): { size: number } {
|
|
102
|
+
return { size: this.cache.size };
|
|
103
|
+
}
|
|
104
|
+
}
|