@teamvelix/cache-redis 0.1.0 → 5.3.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/dist/index.d.ts +80 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/package.json +9 -9
- package/LICENSE +0 -21
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options de configuration pour RedisCacheAdapter
|
|
5
|
+
*/
|
|
6
|
+
type RedisCacheAdapterOptions = {
|
|
7
|
+
/** URL de connexion Redis. Ex: 'redis://localhost:6379' */
|
|
8
|
+
url?: string;
|
|
9
|
+
/** Instance ioredis pré-configurée (prioritaire sur `url`) */
|
|
10
|
+
client?: Redis;
|
|
11
|
+
/** Préfixe pour toutes les clés Velix dans Redis. Défaut: 'velix:' */
|
|
12
|
+
keyPrefix?: string;
|
|
13
|
+
/** TTL par défaut en millisecondes. Défaut: undefined (pas d'expiration) */
|
|
14
|
+
defaultTTL?: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Structure interne stockée dans Redis (sérialisée en JSON)
|
|
18
|
+
*/
|
|
19
|
+
type StoredEntry<T> = {
|
|
20
|
+
value: T;
|
|
21
|
+
tags: string[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
interface ICacheAdapter {
|
|
25
|
+
get<T>(key: string): Promise<T | null>;
|
|
26
|
+
set<T>(key: string, value: T, options?: CacheSetOptions): Promise<void>;
|
|
27
|
+
delete(key: string): Promise<void>;
|
|
28
|
+
deleteByTag(tag: string): Promise<void>;
|
|
29
|
+
deleteByPrefix(prefix: string): Promise<void>;
|
|
30
|
+
clear(): Promise<void>;
|
|
31
|
+
has(key: string): Promise<boolean>;
|
|
32
|
+
}
|
|
33
|
+
type CacheSetOptions = {
|
|
34
|
+
/** TTL en millisecondes */
|
|
35
|
+
ttl?: number;
|
|
36
|
+
/** Tags pour l'invalidation groupée */
|
|
37
|
+
tags?: string[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Adaptateur de cache Redis pour Velix.
|
|
41
|
+
* Implémente ICacheAdapter via ioredis.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { RedisCacheAdapter } from '@velix/cache-redis';
|
|
46
|
+
* import { defineConfig } from 'velix';
|
|
47
|
+
*
|
|
48
|
+
* export default defineConfig({
|
|
49
|
+
* cache: {
|
|
50
|
+
* adapter: new RedisCacheAdapter({ url: process.env.REDIS_URL }),
|
|
51
|
+
* }
|
|
52
|
+
* });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare class RedisCacheAdapter implements ICacheAdapter {
|
|
56
|
+
private redis;
|
|
57
|
+
private prefix;
|
|
58
|
+
private defaultTTL?;
|
|
59
|
+
constructor(options?: RedisCacheAdapterOptions);
|
|
60
|
+
private key;
|
|
61
|
+
private tagKey;
|
|
62
|
+
get<T>(key: string): Promise<T | null>;
|
|
63
|
+
set<T>(key: string, value: T, options?: CacheSetOptions): Promise<void>;
|
|
64
|
+
delete(key: string): Promise<void>;
|
|
65
|
+
deleteByTag(tag: string): Promise<void>;
|
|
66
|
+
deleteByPrefix(prefix: string): Promise<void>;
|
|
67
|
+
clear(): Promise<void>;
|
|
68
|
+
has(key: string): Promise<boolean>;
|
|
69
|
+
/**
|
|
70
|
+
* Ferme proprement les connexions Redis.
|
|
71
|
+
* À appeler au shutdown de l'application.
|
|
72
|
+
*/
|
|
73
|
+
disconnect(): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Expose l'instance Redis sous-jacente pour les cas avancés.
|
|
76
|
+
*/
|
|
77
|
+
getClient(): Redis;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { type CacheSetOptions, type ICacheAdapter, RedisCacheAdapter, type RedisCacheAdapterOptions, type StoredEntry };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
|
|
3
|
+
// src/redis.adapter.ts
|
|
4
|
+
var DELETE_BY_TAG_LUA = `
|
|
5
|
+
local keys = redis.call('SMEMBERS', KEYS[1])
|
|
6
|
+
if #keys > 0 then
|
|
7
|
+
redis.call('DEL', unpack(keys))
|
|
8
|
+
end
|
|
9
|
+
redis.call('DEL', KEYS[1])
|
|
10
|
+
return #keys
|
|
11
|
+
`;
|
|
12
|
+
var RedisCacheAdapter = class {
|
|
13
|
+
redis;
|
|
14
|
+
prefix;
|
|
15
|
+
defaultTTL;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.redis = options.client ?? new Redis(options.url ?? "redis://localhost:6379");
|
|
18
|
+
this.prefix = options.keyPrefix ?? "velix:";
|
|
19
|
+
this.defaultTTL = options.defaultTTL;
|
|
20
|
+
}
|
|
21
|
+
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
22
|
+
key(k) {
|
|
23
|
+
return `${this.prefix}${k}`;
|
|
24
|
+
}
|
|
25
|
+
tagKey(tag) {
|
|
26
|
+
return `${this.prefix}tag:${tag}`;
|
|
27
|
+
}
|
|
28
|
+
// ── ICacheAdapter ─────────────────────────────────────────────────────────
|
|
29
|
+
async get(key) {
|
|
30
|
+
const raw = await this.redis.get(this.key(key));
|
|
31
|
+
if (!raw) return null;
|
|
32
|
+
try {
|
|
33
|
+
const entry = JSON.parse(raw);
|
|
34
|
+
return entry.value;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async set(key, value, options = {}) {
|
|
40
|
+
const entry = {
|
|
41
|
+
value,
|
|
42
|
+
tags: options.tags ?? []
|
|
43
|
+
};
|
|
44
|
+
const serialized = JSON.stringify(entry);
|
|
45
|
+
const k = this.key(key);
|
|
46
|
+
const ttlMs = options.ttl ?? this.defaultTTL;
|
|
47
|
+
if (ttlMs) {
|
|
48
|
+
await this.redis.set(k, serialized, "PX", ttlMs);
|
|
49
|
+
} else {
|
|
50
|
+
await this.redis.set(k, serialized);
|
|
51
|
+
}
|
|
52
|
+
if (options.tags?.length) {
|
|
53
|
+
await Promise.all(
|
|
54
|
+
options.tags.map((tag) => this.redis.sadd(this.tagKey(tag), k))
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async delete(key) {
|
|
59
|
+
await this.redis.del(this.key(key));
|
|
60
|
+
}
|
|
61
|
+
async deleteByTag(tag) {
|
|
62
|
+
await this.redis.eval(DELETE_BY_TAG_LUA, 1, this.tagKey(tag));
|
|
63
|
+
}
|
|
64
|
+
async deleteByPrefix(prefix) {
|
|
65
|
+
const fullPrefix = this.key(prefix);
|
|
66
|
+
let cursor = "0";
|
|
67
|
+
do {
|
|
68
|
+
const [nextCursor, keys] = await this.redis.scan(
|
|
69
|
+
cursor,
|
|
70
|
+
"MATCH",
|
|
71
|
+
`${fullPrefix}*`,
|
|
72
|
+
"COUNT",
|
|
73
|
+
100
|
|
74
|
+
);
|
|
75
|
+
cursor = nextCursor;
|
|
76
|
+
if (keys.length > 0) {
|
|
77
|
+
await this.redis.del(...keys);
|
|
78
|
+
}
|
|
79
|
+
} while (cursor !== "0");
|
|
80
|
+
}
|
|
81
|
+
async clear() {
|
|
82
|
+
let cursor = "0";
|
|
83
|
+
do {
|
|
84
|
+
const [nextCursor, keys] = await this.redis.scan(
|
|
85
|
+
cursor,
|
|
86
|
+
"MATCH",
|
|
87
|
+
`${this.prefix}*`,
|
|
88
|
+
"COUNT",
|
|
89
|
+
100
|
|
90
|
+
);
|
|
91
|
+
cursor = nextCursor;
|
|
92
|
+
if (keys.length > 0) await this.redis.del(...keys);
|
|
93
|
+
} while (cursor !== "0");
|
|
94
|
+
}
|
|
95
|
+
async has(key) {
|
|
96
|
+
return await this.redis.exists(this.key(key)) === 1;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Ferme proprement les connexions Redis.
|
|
100
|
+
* À appeler au shutdown de l'application.
|
|
101
|
+
*/
|
|
102
|
+
async disconnect() {
|
|
103
|
+
await this.redis.quit();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Expose l'instance Redis sous-jacente pour les cas avancés.
|
|
107
|
+
*/
|
|
108
|
+
getClient() {
|
|
109
|
+
return this.redis;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export { RedisCacheAdapter };
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
115
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/redis.adapter.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import Redis from 'ioredis';\nimport type { RedisCacheAdapterOptions, StoredEntry } from './types.js';\n\n// ============================================================================\n// ICacheAdapter — inline pour éviter la dépendance circulaire et permettre\n// à @velix/cache-redis d'être utilisable sans velix-core installé\n// ============================================================================\n\nexport interface ICacheAdapter {\n get<T>(key: string): Promise<T | null>;\n set<T>(key: string, value: T, options?: CacheSetOptions): Promise<void>;\n delete(key: string): Promise<void>;\n deleteByTag(tag: string): Promise<void>;\n deleteByPrefix(prefix: string): Promise<void>;\n clear(): Promise<void>;\n has(key: string): Promise<boolean>;\n}\n\nexport type CacheSetOptions = {\n /** TTL en millisecondes */\n ttl?: number;\n /** Tags pour l'invalidation groupée */\n tags?: string[];\n};\n\n// ============================================================================\n// Script Lua inline pour deleteByTag — atomicité garantie\n// ============================================================================\n\nconst DELETE_BY_TAG_LUA = `\nlocal keys = redis.call('SMEMBERS', KEYS[1])\nif #keys > 0 then\n redis.call('DEL', unpack(keys))\nend\nredis.call('DEL', KEYS[1])\nreturn #keys\n`;\n\n// ============================================================================\n// RedisCacheAdapter\n// ============================================================================\n\n/**\n * Adaptateur de cache Redis pour Velix.\n * Implémente ICacheAdapter via ioredis.\n *\n * @example\n * ```ts\n * import { RedisCacheAdapter } from '@velix/cache-redis';\n * import { defineConfig } from 'velix';\n *\n * export default defineConfig({\n * cache: {\n * adapter: new RedisCacheAdapter({ url: process.env.REDIS_URL }),\n * }\n * });\n * ```\n */\nexport class RedisCacheAdapter implements ICacheAdapter {\n private redis: Redis;\n private prefix: string;\n private defaultTTL?: number;\n\n constructor(options: RedisCacheAdapterOptions = {}) {\n this.redis = options.client ?? new Redis(options.url ?? 'redis://localhost:6379');\n this.prefix = options.keyPrefix ?? 'velix:';\n this.defaultTTL = options.defaultTTL;\n }\n\n // ── Helpers ──────────────────────────────────────────────────────────────\n\n private key(k: string): string {\n return `${this.prefix}${k}`;\n }\n\n private tagKey(tag: string): string {\n return `${this.prefix}tag:${tag}`;\n }\n\n // ── ICacheAdapter ─────────────────────────────────────────────────────────\n\n async get<T>(key: string): Promise<T | null> {\n const raw = await this.redis.get(this.key(key));\n if (!raw) return null;\n try {\n const entry = JSON.parse(raw) as StoredEntry<T>;\n return entry.value;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T, options: CacheSetOptions = {}): Promise<void> {\n const entry: StoredEntry<T> = {\n value,\n tags: options.tags ?? [],\n };\n const serialized = JSON.stringify(entry);\n const k = this.key(key);\n const ttlMs = options.ttl ?? this.defaultTTL;\n\n if (ttlMs) {\n await this.redis.set(k, serialized, 'PX', ttlMs);\n } else {\n await this.redis.set(k, serialized);\n }\n\n // Indexer la clé dans chaque tag (Redis Set pour invalidation rapide)\n if (options.tags?.length) {\n await Promise.all(\n options.tags.map(tag => this.redis.sadd(this.tagKey(tag), k))\n );\n }\n }\n\n async delete(key: string): Promise<void> {\n await this.redis.del(this.key(key));\n }\n\n async deleteByTag(tag: string): Promise<void> {\n // Script Lua atomique — évite les race conditions entre SMEMBERS et DEL\n await this.redis.eval(DELETE_BY_TAG_LUA, 1, this.tagKey(tag));\n }\n\n async deleteByPrefix(prefix: string): Promise<void> {\n // SCAN non-bloquant — ne jamais utiliser KEYS en production\n const fullPrefix = this.key(prefix);\n let cursor = '0';\n do {\n const [nextCursor, keys] = await this.redis.scan(\n cursor, 'MATCH', `${fullPrefix}*`, 'COUNT', 100\n );\n cursor = nextCursor;\n if (keys.length > 0) {\n await this.redis.del(...keys);\n }\n } while (cursor !== '0');\n }\n\n async clear(): Promise<void> {\n // SCAN + DELETE toutes les clés avec le préfixe Velix (non-bloquant)\n let cursor = '0';\n do {\n const [nextCursor, keys] = await this.redis.scan(\n cursor, 'MATCH', `${this.prefix}*`, 'COUNT', 100\n );\n cursor = nextCursor;\n if (keys.length > 0) await this.redis.del(...keys);\n } while (cursor !== '0');\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.redis.exists(this.key(key))) === 1;\n }\n\n /**\n * Ferme proprement les connexions Redis.\n * À appeler au shutdown de l'application.\n */\n async disconnect(): Promise<void> {\n await this.redis.quit();\n }\n\n /**\n * Expose l'instance Redis sous-jacente pour les cas avancés.\n */\n getClient(): Redis {\n return this.redis;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamvelix/cache-redis",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.3.3",
|
|
4
4
|
"description": "Redis cache adapter for Velix — implements ICacheAdapter via ioredis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,13 @@
|
|
|
16
16
|
"README.md",
|
|
17
17
|
"LICENSE"
|
|
18
18
|
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
21
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
19
26
|
"keywords": [
|
|
20
27
|
"velix",
|
|
21
28
|
"cache",
|
|
@@ -36,12 +43,5 @@
|
|
|
36
43
|
},
|
|
37
44
|
"publishConfig": {
|
|
38
45
|
"access": "public"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
42
|
-
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
43
|
-
"typecheck": "tsc --noEmit",
|
|
44
|
-
"test": "vitest run",
|
|
45
|
-
"test:watch": "vitest"
|
|
46
46
|
}
|
|
47
|
-
}
|
|
47
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Velix Team
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|