rust-node-cache 0.1.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 -0
- package/README.md +390 -0
- package/binding.d.ts +54 -0
- package/binding.js +315 -0
- package/dist/express.d.mts +34 -0
- package/dist/express.d.ts +34 -0
- package/dist/express.js +58 -0
- package/dist/express.js.map +1 -0
- package/dist/express.mjs +33 -0
- package/dist/express.mjs.map +1 -0
- package/dist/fastify.d.mts +33 -0
- package/dist/fastify.d.ts +33 -0
- package/dist/fastify.js +73 -0
- package/dist/fastify.js.map +1 -0
- package/dist/fastify.mjs +48 -0
- package/dist/fastify.mjs.map +1 -0
- package/dist/index.d.mts +91 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +56 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nestjs.d.mts +46 -0
- package/dist/nestjs.d.ts +46 -0
- package/dist/nestjs.js +61 -0
- package/dist/nestjs.js.map +1 -0
- package/dist/nestjs.mjs +36 -0
- package/dist/nestjs.mjs.map +1 -0
- package/package.json +109 -0
- package/rust-node-cache.darwin-arm64.node +0 -0
- package/rust-node-cache.darwin-x64.node +0 -0
- package/rust-node-cache.linux-arm64-gnu.node +0 -0
- package/rust-node-cache.linux-x64-gnu.node +0 -0
- package/rust-node-cache.win32-x64-msvc.node +0 -0
package/dist/fastify.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// js/fastify.ts
|
|
2
|
+
var CACHE_KEY = /* @__PURE__ */ Symbol("rustNodeCacheKey");
|
|
3
|
+
async function cachePlugin(fastify, options) {
|
|
4
|
+
const { cache } = options;
|
|
5
|
+
const ttlSeconds = options.ttlSeconds;
|
|
6
|
+
const methods = options.methods ?? ["GET"];
|
|
7
|
+
const keyGenerator = options.keyGenerator ?? ((req) => `${req.method}:${req.url}`);
|
|
8
|
+
fastify.addHook(
|
|
9
|
+
"onRequest",
|
|
10
|
+
(request, reply, done) => {
|
|
11
|
+
if (!methods.includes(request.method)) {
|
|
12
|
+
done();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const key = keyGenerator(request);
|
|
16
|
+
const cached = cache.get(key);
|
|
17
|
+
if (cached !== null) {
|
|
18
|
+
reply.header("X-Cache", "HIT");
|
|
19
|
+
reply.send(cached);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
reply.header("X-Cache", "MISS");
|
|
23
|
+
request[CACHE_KEY] = key;
|
|
24
|
+
done();
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
fastify.addHook(
|
|
28
|
+
"onSend",
|
|
29
|
+
(request, reply, payload, done) => {
|
|
30
|
+
const key = request[CACHE_KEY];
|
|
31
|
+
if (key && typeof payload === "string" && reply.statusCode >= 200 && reply.statusCode < 300) {
|
|
32
|
+
try {
|
|
33
|
+
cache.set(
|
|
34
|
+
key,
|
|
35
|
+
JSON.parse(payload),
|
|
36
|
+
ttlSeconds ? { ttlSeconds } : void 0
|
|
37
|
+
);
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
done(null, payload);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
cachePlugin
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=fastify.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/fastify.ts"],"sourcesContent":["/**\n * Integração com Fastify: cache de respostas JSON via plugin.\n *\n * Uso:\n * import { Cache } from \"rust-node-cache\";\n * import { cachePlugin } from \"rust-node-cache/fastify\";\n *\n * const cache = new Cache();\n * fastify.register(cachePlugin, { cache, ttlSeconds: 60 });\n *\n * Fluxo: o hook `onRequest` checa o cache e, num HIT, responde imediatamente\n * (curto-circuito). Num MISS, o hook `onSend` guarda o payload serializado.\n */\n\nimport type {\n FastifyInstance,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport type { Cache } from \"./index\";\n\nexport interface CachePluginOptions {\n /** Instância de cache a usar. */\n cache: Cache;\n /** TTL aplicado às respostas guardadas (em segundos). */\n ttlSeconds?: number;\n /** Métodos HTTP elegíveis para cache. Padrão: `[\"GET\"]`. */\n methods?: string[];\n /** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */\n keyGenerator?: (req: FastifyRequest) => string;\n}\n\n// Guardamos a chave calculada na própria request entre os hooks.\nconst CACHE_KEY = Symbol(\"rustNodeCacheKey\");\n\n/**\n * Plugin Fastify que cacheia respostas JSON. Use com `fastify.register`.\n */\nexport async function cachePlugin(\n fastify: FastifyInstance,\n options: CachePluginOptions,\n): Promise<void> {\n const { cache } = options;\n const ttlSeconds = options.ttlSeconds;\n const methods = options.methods ?? [\"GET\"];\n const keyGenerator =\n options.keyGenerator ?? ((req: FastifyRequest) => `${req.method}:${req.url}`);\n\n fastify.addHook(\n \"onRequest\",\n (request: FastifyRequest, reply: FastifyReply, done: () => void) => {\n if (!methods.includes(request.method)) {\n done();\n return;\n }\n\n const key = keyGenerator(request);\n const cached = cache.get(key);\n if (cached !== null) {\n reply.header(\"X-Cache\", \"HIT\");\n reply.send(cached);\n return; // não chama done(): a resposta já foi enviada.\n }\n\n reply.header(\"X-Cache\", \"MISS\");\n (request as unknown as Record<symbol, string>)[CACHE_KEY] = key;\n done();\n },\n );\n\n fastify.addHook(\n \"onSend\",\n (\n request: FastifyRequest,\n reply: FastifyReply,\n payload: unknown,\n done: (err: Error | null, value?: unknown) => void,\n ) => {\n const key = (request as unknown as Record<symbol, string | undefined>)[\n CACHE_KEY\n ];\n if (\n key &&\n typeof payload === \"string\" &&\n reply.statusCode >= 200 &&\n reply.statusCode < 300\n ) {\n try {\n cache.set(\n key,\n JSON.parse(payload),\n ttlSeconds ? { ttlSeconds } : undefined,\n );\n } catch {\n // payload não-JSON: simplesmente não cacheia.\n }\n }\n done(null, payload);\n },\n );\n}\n"],"mappings":";AAiCA,IAAM,YAAY,uBAAO,kBAAkB;AAK3C,eAAsB,YACpB,SACA,SACe;AACf,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,aAAa,QAAQ;AAC3B,QAAM,UAAU,QAAQ,WAAW,CAAC,KAAK;AACzC,QAAM,eACJ,QAAQ,iBAAiB,CAAC,QAAwB,GAAG,IAAI,MAAM,IAAI,IAAI,GAAG;AAE5E,UAAQ;AAAA,IACN;AAAA,IACA,CAAC,SAAyB,OAAqB,SAAqB;AAClE,UAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,GAAG;AACrC,aAAK;AACL;AAAA,MACF;AAEA,YAAM,MAAM,aAAa,OAAO;AAChC,YAAM,SAAS,MAAM,IAAI,GAAG;AAC5B,UAAI,WAAW,MAAM;AACnB,cAAM,OAAO,WAAW,KAAK;AAC7B,cAAM,KAAK,MAAM;AACjB;AAAA,MACF;AAEA,YAAM,OAAO,WAAW,MAAM;AAC9B,MAAC,QAA8C,SAAS,IAAI;AAC5D,WAAK;AAAA,IACP;AAAA,EACF;AAEA,UAAQ;AAAA,IACN;AAAA,IACA,CACE,SACA,OACA,SACA,SACG;AACH,YAAM,MAAO,QACX,SACF;AACA,UACE,OACA,OAAO,YAAY,YACnB,MAAM,cAAc,OACpB,MAAM,aAAa,KACnB;AACA,YAAI;AACF,gBAAM;AAAA,YACJ;AAAA,YACA,KAAK,MAAM,OAAO;AAAA,YAClB,aAAa,EAAE,WAAW,IAAI;AAAA,UAChC;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AACA,WAAK,MAAM,OAAO;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rust-node-cache — API pública (TypeScript).
|
|
3
|
+
*
|
|
4
|
+
* "Ultra-fast in-memory cache powered by Rust."
|
|
5
|
+
*
|
|
6
|
+
* Esta camada é um wrapper fino e tipado sobre a classe `Cache` nativa gerada
|
|
7
|
+
* pelo Rust/napi-rs. Por que envolver em vez de re-exportar direto?
|
|
8
|
+
* - permite **genéricos** ergonômicos: `cache.get<User>("user:1")`;
|
|
9
|
+
* - normaliza `undefined`/`null` para sempre devolver `null` num miss;
|
|
10
|
+
* - dá um único lugar para JSDoc e para evoluir a API sem quebrar o core Rust.
|
|
11
|
+
*
|
|
12
|
+
* O custo é uma chamada de função extra por operação — desprezível frente ao
|
|
13
|
+
* trabalho real (serialização + acesso ao DashMap) que acontece no Rust.
|
|
14
|
+
*/
|
|
15
|
+
/** Opções do construtor do cache. */
|
|
16
|
+
interface CacheOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Limite máximo de chaves. Ao ser atingido, `set` de uma chave **nova**
|
|
19
|
+
* retorna `false` (sobrescrever chave existente continua permitido).
|
|
20
|
+
* Sem valor => cache ilimitado.
|
|
21
|
+
*/
|
|
22
|
+
maxSize?: number;
|
|
23
|
+
}
|
|
24
|
+
/** Opções por operação de escrita. */
|
|
25
|
+
interface SetOptions {
|
|
26
|
+
/** Tempo de vida em segundos. Ausente => a entrada não expira por tempo. */
|
|
27
|
+
ttlSeconds?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Estatísticas acumuladas do cache (mais o tamanho atual). */
|
|
30
|
+
interface CacheStats {
|
|
31
|
+
/** Leituras que encontraram uma entrada válida. */
|
|
32
|
+
hits: number;
|
|
33
|
+
/** Leituras sem chave válida (ausente ou expirada). */
|
|
34
|
+
misses: number;
|
|
35
|
+
/** Total de escritas (`set`). */
|
|
36
|
+
sets: number;
|
|
37
|
+
/** Total de remoções explícitas (`delete`). */
|
|
38
|
+
deletes: number;
|
|
39
|
+
/** Total de entradas removidas por expiração. */
|
|
40
|
+
expired: number;
|
|
41
|
+
/** Número de chaves armazenadas agora. */
|
|
42
|
+
size: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Cache em memória ultrarrápido com núcleo em Rust (DashMap + contadores
|
|
46
|
+
* atômicos). Thread-safe e com suporte a TTL por entrada.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { Cache } from "rust-node-cache";
|
|
51
|
+
*
|
|
52
|
+
* const cache = new Cache();
|
|
53
|
+
* cache.set("user:1", { id: 1, name: "Roberto" });
|
|
54
|
+
* cache.get<{ id: number; name: string }>("user:1"); // { id: 1, name: "Roberto" }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
declare class Cache {
|
|
58
|
+
/** Instância da classe nativa (Rust). */
|
|
59
|
+
private readonly native;
|
|
60
|
+
constructor(options?: CacheOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
|
|
63
|
+
*
|
|
64
|
+
* @returns `true` em sucesso; `false` se `maxSize` foi atingido e a chave é nova.
|
|
65
|
+
*/
|
|
66
|
+
set<T>(key: string, value: T, options?: SetOptions): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Lê um valor. Aplica expiração preguiçosa: chaves vencidas contam como miss.
|
|
69
|
+
*
|
|
70
|
+
* @returns o valor desserializado, ou `null` se ausente/expirado.
|
|
71
|
+
*/
|
|
72
|
+
get<T = unknown>(key: string): T | null;
|
|
73
|
+
/** Remove uma chave. Retorna `true` se ela existia. */
|
|
74
|
+
delete(key: string): boolean;
|
|
75
|
+
/** Indica se a chave existe e está válida (não expirada). */
|
|
76
|
+
exists(key: string): boolean;
|
|
77
|
+
/** Esvazia o cache (não zera os contadores históricos de `stats`). */
|
|
78
|
+
clear(): void;
|
|
79
|
+
/** Número de chaves armazenadas no momento. */
|
|
80
|
+
size(): number;
|
|
81
|
+
/**
|
|
82
|
+
* Varre e remove todas as entradas expiradas de uma só vez.
|
|
83
|
+
*
|
|
84
|
+
* @returns quantas entradas foram removidas.
|
|
85
|
+
*/
|
|
86
|
+
cleanupExpired(): number;
|
|
87
|
+
/** Retorna as estatísticas acumuladas + o tamanho atual. */
|
|
88
|
+
stats(): CacheStats;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { Cache, type CacheOptions, type CacheStats, type SetOptions };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rust-node-cache — API pública (TypeScript).
|
|
3
|
+
*
|
|
4
|
+
* "Ultra-fast in-memory cache powered by Rust."
|
|
5
|
+
*
|
|
6
|
+
* Esta camada é um wrapper fino e tipado sobre a classe `Cache` nativa gerada
|
|
7
|
+
* pelo Rust/napi-rs. Por que envolver em vez de re-exportar direto?
|
|
8
|
+
* - permite **genéricos** ergonômicos: `cache.get<User>("user:1")`;
|
|
9
|
+
* - normaliza `undefined`/`null` para sempre devolver `null` num miss;
|
|
10
|
+
* - dá um único lugar para JSDoc e para evoluir a API sem quebrar o core Rust.
|
|
11
|
+
*
|
|
12
|
+
* O custo é uma chamada de função extra por operação — desprezível frente ao
|
|
13
|
+
* trabalho real (serialização + acesso ao DashMap) que acontece no Rust.
|
|
14
|
+
*/
|
|
15
|
+
/** Opções do construtor do cache. */
|
|
16
|
+
interface CacheOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Limite máximo de chaves. Ao ser atingido, `set` de uma chave **nova**
|
|
19
|
+
* retorna `false` (sobrescrever chave existente continua permitido).
|
|
20
|
+
* Sem valor => cache ilimitado.
|
|
21
|
+
*/
|
|
22
|
+
maxSize?: number;
|
|
23
|
+
}
|
|
24
|
+
/** Opções por operação de escrita. */
|
|
25
|
+
interface SetOptions {
|
|
26
|
+
/** Tempo de vida em segundos. Ausente => a entrada não expira por tempo. */
|
|
27
|
+
ttlSeconds?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Estatísticas acumuladas do cache (mais o tamanho atual). */
|
|
30
|
+
interface CacheStats {
|
|
31
|
+
/** Leituras que encontraram uma entrada válida. */
|
|
32
|
+
hits: number;
|
|
33
|
+
/** Leituras sem chave válida (ausente ou expirada). */
|
|
34
|
+
misses: number;
|
|
35
|
+
/** Total de escritas (`set`). */
|
|
36
|
+
sets: number;
|
|
37
|
+
/** Total de remoções explícitas (`delete`). */
|
|
38
|
+
deletes: number;
|
|
39
|
+
/** Total de entradas removidas por expiração. */
|
|
40
|
+
expired: number;
|
|
41
|
+
/** Número de chaves armazenadas agora. */
|
|
42
|
+
size: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Cache em memória ultrarrápido com núcleo em Rust (DashMap + contadores
|
|
46
|
+
* atômicos). Thread-safe e com suporte a TTL por entrada.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { Cache } from "rust-node-cache";
|
|
51
|
+
*
|
|
52
|
+
* const cache = new Cache();
|
|
53
|
+
* cache.set("user:1", { id: 1, name: "Roberto" });
|
|
54
|
+
* cache.get<{ id: number; name: string }>("user:1"); // { id: 1, name: "Roberto" }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
declare class Cache {
|
|
58
|
+
/** Instância da classe nativa (Rust). */
|
|
59
|
+
private readonly native;
|
|
60
|
+
constructor(options?: CacheOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
|
|
63
|
+
*
|
|
64
|
+
* @returns `true` em sucesso; `false` se `maxSize` foi atingido e a chave é nova.
|
|
65
|
+
*/
|
|
66
|
+
set<T>(key: string, value: T, options?: SetOptions): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Lê um valor. Aplica expiração preguiçosa: chaves vencidas contam como miss.
|
|
69
|
+
*
|
|
70
|
+
* @returns o valor desserializado, ou `null` se ausente/expirado.
|
|
71
|
+
*/
|
|
72
|
+
get<T = unknown>(key: string): T | null;
|
|
73
|
+
/** Remove uma chave. Retorna `true` se ela existia. */
|
|
74
|
+
delete(key: string): boolean;
|
|
75
|
+
/** Indica se a chave existe e está válida (não expirada). */
|
|
76
|
+
exists(key: string): boolean;
|
|
77
|
+
/** Esvazia o cache (não zera os contadores históricos de `stats`). */
|
|
78
|
+
clear(): void;
|
|
79
|
+
/** Número de chaves armazenadas no momento. */
|
|
80
|
+
size(): number;
|
|
81
|
+
/**
|
|
82
|
+
* Varre e remove todas as entradas expiradas de uma só vez.
|
|
83
|
+
*
|
|
84
|
+
* @returns quantas entradas foram removidas.
|
|
85
|
+
*/
|
|
86
|
+
cleanupExpired(): number;
|
|
87
|
+
/** Retorna as estatísticas acumuladas + o tamanho atual. */
|
|
88
|
+
stats(): CacheStats;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { Cache, type CacheOptions, type CacheStats, type SetOptions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// js/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
Cache: () => Cache2
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var native = __toESM(require("../binding.js"));
|
|
37
|
+
var Cache2 = class {
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
this.native = options.maxSize !== void 0 ? new native.Cache({ maxSize: options.maxSize }) : new native.Cache();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
|
|
43
|
+
*
|
|
44
|
+
* @returns `true` em sucesso; `false` se `maxSize` foi atingido e a chave é nova.
|
|
45
|
+
*/
|
|
46
|
+
set(key, value, options) {
|
|
47
|
+
return this.native.set(key, value, options);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Lê um valor. Aplica expiração preguiçosa: chaves vencidas contam como miss.
|
|
51
|
+
*
|
|
52
|
+
* @returns o valor desserializado, ou `null` se ausente/expirado.
|
|
53
|
+
*/
|
|
54
|
+
get(key) {
|
|
55
|
+
const value = this.native.get(key);
|
|
56
|
+
return value === null || value === void 0 ? null : value;
|
|
57
|
+
}
|
|
58
|
+
/** Remove uma chave. Retorna `true` se ela existia. */
|
|
59
|
+
delete(key) {
|
|
60
|
+
return this.native.delete(key);
|
|
61
|
+
}
|
|
62
|
+
/** Indica se a chave existe e está válida (não expirada). */
|
|
63
|
+
exists(key) {
|
|
64
|
+
return this.native.exists(key);
|
|
65
|
+
}
|
|
66
|
+
/** Esvazia o cache (não zera os contadores históricos de `stats`). */
|
|
67
|
+
clear() {
|
|
68
|
+
this.native.clear();
|
|
69
|
+
}
|
|
70
|
+
/** Número de chaves armazenadas no momento. */
|
|
71
|
+
size() {
|
|
72
|
+
return this.native.size();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Varre e remove todas as entradas expiradas de uma só vez.
|
|
76
|
+
*
|
|
77
|
+
* @returns quantas entradas foram removidas.
|
|
78
|
+
*/
|
|
79
|
+
cleanupExpired() {
|
|
80
|
+
return this.native.cleanupExpired();
|
|
81
|
+
}
|
|
82
|
+
/** Retorna as estatísticas acumuladas + o tamanho atual. */
|
|
83
|
+
stats() {
|
|
84
|
+
return this.native.stats();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
88
|
+
0 && (module.exports = {
|
|
89
|
+
Cache
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/index.ts"],"sourcesContent":["/**\n * rust-node-cache — API pública (TypeScript).\n *\n * \"Ultra-fast in-memory cache powered by Rust.\"\n *\n * Esta camada é um wrapper fino e tipado sobre a classe `Cache` nativa gerada\n * pelo Rust/napi-rs. Por que envolver em vez de re-exportar direto?\n * - permite **genéricos** ergonômicos: `cache.get<User>(\"user:1\")`;\n * - normaliza `undefined`/`null` para sempre devolver `null` num miss;\n * - dá um único lugar para JSDoc e para evoluir a API sem quebrar o core Rust.\n *\n * O custo é uma chamada de função extra por operação — desprezível frente ao\n * trabalho real (serialização + acesso ao DashMap) que acontece no Rust.\n */\n\n// Namespace import: funciona igual em CommonJS e ESM ao consumir o addon nativo\n// (que é um módulo CJS gerado pelo napi-rs).\nimport * as native from \"../binding.js\";\n\n/** Opções do construtor do cache. */\nexport interface CacheOptions {\n /**\n * Limite máximo de chaves. Ao ser atingido, `set` de uma chave **nova**\n * retorna `false` (sobrescrever chave existente continua permitido).\n * Sem valor => cache ilimitado.\n */\n maxSize?: number;\n}\n\n/** Opções por operação de escrita. */\nexport interface SetOptions {\n /** Tempo de vida em segundos. Ausente => a entrada não expira por tempo. */\n ttlSeconds?: number;\n}\n\n/** Estatísticas acumuladas do cache (mais o tamanho atual). */\nexport interface CacheStats {\n /** Leituras que encontraram uma entrada válida. */\n hits: number;\n /** Leituras sem chave válida (ausente ou expirada). */\n misses: number;\n /** Total de escritas (`set`). */\n sets: number;\n /** Total de remoções explícitas (`delete`). */\n deletes: number;\n /** Total de entradas removidas por expiração. */\n expired: number;\n /** Número de chaves armazenadas agora. */\n size: number;\n}\n\n/**\n * Cache em memória ultrarrápido com núcleo em Rust (DashMap + contadores\n * atômicos). Thread-safe e com suporte a TTL por entrada.\n *\n * @example\n * ```ts\n * import { Cache } from \"rust-node-cache\";\n *\n * const cache = new Cache();\n * cache.set(\"user:1\", { id: 1, name: \"Roberto\" });\n * cache.get<{ id: number; name: string }>(\"user:1\"); // { id: 1, name: \"Roberto\" }\n * ```\n */\nexport class Cache {\n /** Instância da classe nativa (Rust). */\n private readonly native: native.Cache;\n\n constructor(options: CacheOptions = {}) {\n // Só repassamos o objeto de opções ao Rust quando há algo relevante.\n this.native =\n options.maxSize !== undefined\n ? new native.Cache({ maxSize: options.maxSize })\n : new native.Cache();\n }\n\n /**\n * Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.\n *\n * @returns `true` em sucesso; `false` se `maxSize` foi atingido e a chave é nova.\n */\n set<T>(key: string, value: T, options?: SetOptions): boolean {\n return this.native.set(key, value as unknown as object, options);\n }\n\n /**\n * Lê um valor. Aplica expiração preguiçosa: chaves vencidas contam como miss.\n *\n * @returns o valor desserializado, ou `null` se ausente/expirado.\n */\n get<T = unknown>(key: string): T | null {\n const value = this.native.get(key);\n return value === null || value === undefined ? null : (value as T);\n }\n\n /** Remove uma chave. Retorna `true` se ela existia. */\n delete(key: string): boolean {\n return this.native.delete(key);\n }\n\n /** Indica se a chave existe e está válida (não expirada). */\n exists(key: string): boolean {\n return this.native.exists(key);\n }\n\n /** Esvazia o cache (não zera os contadores históricos de `stats`). */\n clear(): void {\n this.native.clear();\n }\n\n /** Número de chaves armazenadas no momento. */\n size(): number {\n return this.native.size();\n }\n\n /**\n * Varre e remove todas as entradas expiradas de uma só vez.\n *\n * @returns quantas entradas foram removidas.\n */\n cleanupExpired(): number {\n return this.native.cleanupExpired();\n }\n\n /** Retorna as estatísticas acumuladas + o tamanho atual. */\n stats(): CacheStats {\n return this.native.stats();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,eAAAA;AAAA;AAAA;AAiBA,aAAwB;AA+CjB,IAAMA,SAAN,MAAY;AAAA,EAIjB,YAAY,UAAwB,CAAC,GAAG;AAEtC,SAAK,SACH,QAAQ,YAAY,SAChB,IAAW,aAAM,EAAE,SAAS,QAAQ,QAAQ,CAAC,IAC7C,IAAW,aAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAO,KAAa,OAAU,SAA+B;AAC3D,WAAO,KAAK,OAAO,IAAI,KAAK,OAA4B,OAAO;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAiB,KAAuB;AACtC,UAAM,QAAQ,KAAK,OAAO,IAAI,GAAG;AACjC,WAAO,UAAU,QAAQ,UAAU,SAAY,OAAQ;AAAA,EACzD;AAAA;AAAA,EAGA,OAAO,KAAsB;AAC3B,WAAO,KAAK,OAAO,OAAO,GAAG;AAAA,EAC/B;AAAA;AAAA,EAGA,OAAO,KAAsB;AAC3B,WAAO,KAAK,OAAO,OAAO,GAAG;AAAA,EAC/B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA;AAAA,EAGA,OAAe;AACb,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAyB;AACvB,WAAO,KAAK,OAAO,eAAe;AAAA,EACpC;AAAA;AAAA,EAGA,QAAoB;AAClB,WAAO,KAAK,OAAO,MAAM;AAAA,EAC3B;AACF;","names":["Cache"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// js/index.ts
|
|
2
|
+
import * as native from "../binding.js";
|
|
3
|
+
var Cache2 = class {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.native = options.maxSize !== void 0 ? new native.Cache({ maxSize: options.maxSize }) : new native.Cache();
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
|
|
9
|
+
*
|
|
10
|
+
* @returns `true` em sucesso; `false` se `maxSize` foi atingido e a chave é nova.
|
|
11
|
+
*/
|
|
12
|
+
set(key, value, options) {
|
|
13
|
+
return this.native.set(key, value, options);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Lê um valor. Aplica expiração preguiçosa: chaves vencidas contam como miss.
|
|
17
|
+
*
|
|
18
|
+
* @returns o valor desserializado, ou `null` se ausente/expirado.
|
|
19
|
+
*/
|
|
20
|
+
get(key) {
|
|
21
|
+
const value = this.native.get(key);
|
|
22
|
+
return value === null || value === void 0 ? null : value;
|
|
23
|
+
}
|
|
24
|
+
/** Remove uma chave. Retorna `true` se ela existia. */
|
|
25
|
+
delete(key) {
|
|
26
|
+
return this.native.delete(key);
|
|
27
|
+
}
|
|
28
|
+
/** Indica se a chave existe e está válida (não expirada). */
|
|
29
|
+
exists(key) {
|
|
30
|
+
return this.native.exists(key);
|
|
31
|
+
}
|
|
32
|
+
/** Esvazia o cache (não zera os contadores históricos de `stats`). */
|
|
33
|
+
clear() {
|
|
34
|
+
this.native.clear();
|
|
35
|
+
}
|
|
36
|
+
/** Número de chaves armazenadas no momento. */
|
|
37
|
+
size() {
|
|
38
|
+
return this.native.size();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Varre e remove todas as entradas expiradas de uma só vez.
|
|
42
|
+
*
|
|
43
|
+
* @returns quantas entradas foram removidas.
|
|
44
|
+
*/
|
|
45
|
+
cleanupExpired() {
|
|
46
|
+
return this.native.cleanupExpired();
|
|
47
|
+
}
|
|
48
|
+
/** Retorna as estatísticas acumuladas + o tamanho atual. */
|
|
49
|
+
stats() {
|
|
50
|
+
return this.native.stats();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
Cache2 as Cache
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/index.ts"],"sourcesContent":["/**\n * rust-node-cache — API pública (TypeScript).\n *\n * \"Ultra-fast in-memory cache powered by Rust.\"\n *\n * Esta camada é um wrapper fino e tipado sobre a classe `Cache` nativa gerada\n * pelo Rust/napi-rs. Por que envolver em vez de re-exportar direto?\n * - permite **genéricos** ergonômicos: `cache.get<User>(\"user:1\")`;\n * - normaliza `undefined`/`null` para sempre devolver `null` num miss;\n * - dá um único lugar para JSDoc e para evoluir a API sem quebrar o core Rust.\n *\n * O custo é uma chamada de função extra por operação — desprezível frente ao\n * trabalho real (serialização + acesso ao DashMap) que acontece no Rust.\n */\n\n// Namespace import: funciona igual em CommonJS e ESM ao consumir o addon nativo\n// (que é um módulo CJS gerado pelo napi-rs).\nimport * as native from \"../binding.js\";\n\n/** Opções do construtor do cache. */\nexport interface CacheOptions {\n /**\n * Limite máximo de chaves. Ao ser atingido, `set` de uma chave **nova**\n * retorna `false` (sobrescrever chave existente continua permitido).\n * Sem valor => cache ilimitado.\n */\n maxSize?: number;\n}\n\n/** Opções por operação de escrita. */\nexport interface SetOptions {\n /** Tempo de vida em segundos. Ausente => a entrada não expira por tempo. */\n ttlSeconds?: number;\n}\n\n/** Estatísticas acumuladas do cache (mais o tamanho atual). */\nexport interface CacheStats {\n /** Leituras que encontraram uma entrada válida. */\n hits: number;\n /** Leituras sem chave válida (ausente ou expirada). */\n misses: number;\n /** Total de escritas (`set`). */\n sets: number;\n /** Total de remoções explícitas (`delete`). */\n deletes: number;\n /** Total de entradas removidas por expiração. */\n expired: number;\n /** Número de chaves armazenadas agora. */\n size: number;\n}\n\n/**\n * Cache em memória ultrarrápido com núcleo em Rust (DashMap + contadores\n * atômicos). Thread-safe e com suporte a TTL por entrada.\n *\n * @example\n * ```ts\n * import { Cache } from \"rust-node-cache\";\n *\n * const cache = new Cache();\n * cache.set(\"user:1\", { id: 1, name: \"Roberto\" });\n * cache.get<{ id: number; name: string }>(\"user:1\"); // { id: 1, name: \"Roberto\" }\n * ```\n */\nexport class Cache {\n /** Instância da classe nativa (Rust). */\n private readonly native: native.Cache;\n\n constructor(options: CacheOptions = {}) {\n // Só repassamos o objeto de opções ao Rust quando há algo relevante.\n this.native =\n options.maxSize !== undefined\n ? new native.Cache({ maxSize: options.maxSize })\n : new native.Cache();\n }\n\n /**\n * Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.\n *\n * @returns `true` em sucesso; `false` se `maxSize` foi atingido e a chave é nova.\n */\n set<T>(key: string, value: T, options?: SetOptions): boolean {\n return this.native.set(key, value as unknown as object, options);\n }\n\n /**\n * Lê um valor. Aplica expiração preguiçosa: chaves vencidas contam como miss.\n *\n * @returns o valor desserializado, ou `null` se ausente/expirado.\n */\n get<T = unknown>(key: string): T | null {\n const value = this.native.get(key);\n return value === null || value === undefined ? null : (value as T);\n }\n\n /** Remove uma chave. Retorna `true` se ela existia. */\n delete(key: string): boolean {\n return this.native.delete(key);\n }\n\n /** Indica se a chave existe e está válida (não expirada). */\n exists(key: string): boolean {\n return this.native.exists(key);\n }\n\n /** Esvazia o cache (não zera os contadores históricos de `stats`). */\n clear(): void {\n this.native.clear();\n }\n\n /** Número de chaves armazenadas no momento. */\n size(): number {\n return this.native.size();\n }\n\n /**\n * Varre e remove todas as entradas expiradas de uma só vez.\n *\n * @returns quantas entradas foram removidas.\n */\n cleanupExpired(): number {\n return this.native.cleanupExpired();\n }\n\n /** Retorna as estatísticas acumuladas + o tamanho atual. */\n stats(): CacheStats {\n return this.native.stats();\n }\n}\n"],"mappings":";AAiBA,YAAY,YAAY;AA+CjB,IAAMA,SAAN,MAAY;AAAA,EAIjB,YAAY,UAAwB,CAAC,GAAG;AAEtC,SAAK,SACH,QAAQ,YAAY,SAChB,IAAW,aAAM,EAAE,SAAS,QAAQ,QAAQ,CAAC,IAC7C,IAAW,aAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAO,KAAa,OAAU,SAA+B;AAC3D,WAAO,KAAK,OAAO,IAAI,KAAK,OAA4B,OAAO;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAiB,KAAuB;AACtC,UAAM,QAAQ,KAAK,OAAO,IAAI,GAAG;AACjC,WAAO,UAAU,QAAQ,UAAU,SAAY,OAAQ;AAAA,EACzD;AAAA;AAAA,EAGA,OAAO,KAAsB;AAC3B,WAAO,KAAK,OAAO,OAAO,GAAG;AAAA,EAC/B;AAAA;AAAA,EAGA,OAAO,KAAsB;AAC3B,WAAO,KAAK,OAAO,OAAO,GAAG;AAAA,EAC/B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA;AAAA,EAGA,OAAe;AACb,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAyB;AACvB,WAAO,KAAK,OAAO,eAAe;AAAA,EACpC;AAAA;AAAA,EAGA,QAAoB;AAClB,WAAO,KAAK,OAAO,MAAM;AAAA,EAC3B;AACF;","names":["Cache"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { Cache } from './index.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Integração com NestJS: interceptor de cache de respostas.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* import { Cache } from "rust-node-cache";
|
|
10
|
+
* import { CacheInterceptor } from "rust-node-cache/nestjs";
|
|
11
|
+
*
|
|
12
|
+
* const cache = new Cache();
|
|
13
|
+
* app.useGlobalInterceptors(new CacheInterceptor({ cache, ttlSeconds: 60 }));
|
|
14
|
+
*
|
|
15
|
+
* Usamos `import type` para `@nestjs/common`, ou seja, NÃO há import em runtime
|
|
16
|
+
* do Nest aqui — o pacote não força o Nest como dependência. A única dependência
|
|
17
|
+
* de runtime são os operadores `of`/`tap` do RxJS (presentes em qualquer app Nest).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface CacheInterceptorOptions {
|
|
21
|
+
/** Instância de cache a usar. */
|
|
22
|
+
cache: Cache;
|
|
23
|
+
/** TTL aplicado às respostas guardadas (em segundos). */
|
|
24
|
+
ttlSeconds?: number;
|
|
25
|
+
/** Métodos HTTP elegíveis para cache. Padrão: `["GET"]`. */
|
|
26
|
+
methods?: string[];
|
|
27
|
+
/** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */
|
|
28
|
+
keyGenerator?: (req: {
|
|
29
|
+
method: string;
|
|
30
|
+
url: string;
|
|
31
|
+
}) => string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Interceptor NestJS que cacheia o valor retornado pelos handlers. Num HIT,
|
|
35
|
+
* devolve o valor do cache sem executar o handler.
|
|
36
|
+
*/
|
|
37
|
+
declare class CacheInterceptor implements NestInterceptor {
|
|
38
|
+
private readonly cache;
|
|
39
|
+
private readonly ttlSeconds?;
|
|
40
|
+
private readonly methods;
|
|
41
|
+
private readonly keyGenerator;
|
|
42
|
+
constructor(options: CacheInterceptorOptions);
|
|
43
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { CacheInterceptor, type CacheInterceptorOptions };
|
package/dist/nestjs.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { Cache } from './index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Integração com NestJS: interceptor de cache de respostas.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* import { Cache } from "rust-node-cache";
|
|
10
|
+
* import { CacheInterceptor } from "rust-node-cache/nestjs";
|
|
11
|
+
*
|
|
12
|
+
* const cache = new Cache();
|
|
13
|
+
* app.useGlobalInterceptors(new CacheInterceptor({ cache, ttlSeconds: 60 }));
|
|
14
|
+
*
|
|
15
|
+
* Usamos `import type` para `@nestjs/common`, ou seja, NÃO há import em runtime
|
|
16
|
+
* do Nest aqui — o pacote não força o Nest como dependência. A única dependência
|
|
17
|
+
* de runtime são os operadores `of`/`tap` do RxJS (presentes em qualquer app Nest).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface CacheInterceptorOptions {
|
|
21
|
+
/** Instância de cache a usar. */
|
|
22
|
+
cache: Cache;
|
|
23
|
+
/** TTL aplicado às respostas guardadas (em segundos). */
|
|
24
|
+
ttlSeconds?: number;
|
|
25
|
+
/** Métodos HTTP elegíveis para cache. Padrão: `["GET"]`. */
|
|
26
|
+
methods?: string[];
|
|
27
|
+
/** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */
|
|
28
|
+
keyGenerator?: (req: {
|
|
29
|
+
method: string;
|
|
30
|
+
url: string;
|
|
31
|
+
}) => string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Interceptor NestJS que cacheia o valor retornado pelos handlers. Num HIT,
|
|
35
|
+
* devolve o valor do cache sem executar o handler.
|
|
36
|
+
*/
|
|
37
|
+
declare class CacheInterceptor implements NestInterceptor {
|
|
38
|
+
private readonly cache;
|
|
39
|
+
private readonly ttlSeconds?;
|
|
40
|
+
private readonly methods;
|
|
41
|
+
private readonly keyGenerator;
|
|
42
|
+
constructor(options: CacheInterceptorOptions);
|
|
43
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { CacheInterceptor, type CacheInterceptorOptions };
|
package/dist/nestjs.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// js/nestjs.ts
|
|
21
|
+
var nestjs_exports = {};
|
|
22
|
+
__export(nestjs_exports, {
|
|
23
|
+
CacheInterceptor: () => CacheInterceptor
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(nestjs_exports);
|
|
26
|
+
var import_rxjs = require("rxjs");
|
|
27
|
+
var CacheInterceptor = class {
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.cache = options.cache;
|
|
30
|
+
this.ttlSeconds = options.ttlSeconds;
|
|
31
|
+
this.methods = options.methods ?? ["GET"];
|
|
32
|
+
this.keyGenerator = options.keyGenerator ?? ((req) => `${req.method}:${req.url}`);
|
|
33
|
+
}
|
|
34
|
+
intercept(context, next) {
|
|
35
|
+
const req = context.switchToHttp().getRequest();
|
|
36
|
+
if (!this.methods.includes(req.method)) {
|
|
37
|
+
return next.handle();
|
|
38
|
+
}
|
|
39
|
+
const key = this.keyGenerator(req);
|
|
40
|
+
const cached = this.cache.get(key);
|
|
41
|
+
if (cached !== null) {
|
|
42
|
+
return (0, import_rxjs.of)(cached);
|
|
43
|
+
}
|
|
44
|
+
return next.handle().pipe(
|
|
45
|
+
(0, import_rxjs.tap)((body) => {
|
|
46
|
+
if (body !== void 0 && body !== null) {
|
|
47
|
+
this.cache.set(
|
|
48
|
+
key,
|
|
49
|
+
body,
|
|
50
|
+
this.ttlSeconds ? { ttlSeconds: this.ttlSeconds } : void 0
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
58
|
+
0 && (module.exports = {
|
|
59
|
+
CacheInterceptor
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=nestjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/nestjs.ts"],"sourcesContent":["/**\n * Integração com NestJS: interceptor de cache de respostas.\n *\n * Uso:\n * import { Cache } from \"rust-node-cache\";\n * import { CacheInterceptor } from \"rust-node-cache/nestjs\";\n *\n * const cache = new Cache();\n * app.useGlobalInterceptors(new CacheInterceptor({ cache, ttlSeconds: 60 }));\n *\n * Usamos `import type` para `@nestjs/common`, ou seja, NÃO há import em runtime\n * do Nest aqui — o pacote não força o Nest como dependência. A única dependência\n * de runtime são os operadores `of`/`tap` do RxJS (presentes em qualquer app Nest).\n */\n\nimport type {\n CallHandler,\n ExecutionContext,\n NestInterceptor,\n} from \"@nestjs/common\";\nimport type { Observable } from \"rxjs\";\nimport { of, tap } from \"rxjs\";\nimport type { Cache } from \"./index\";\n\nexport interface CacheInterceptorOptions {\n /** Instância de cache a usar. */\n cache: Cache;\n /** TTL aplicado às respostas guardadas (em segundos). */\n ttlSeconds?: number;\n /** Métodos HTTP elegíveis para cache. Padrão: `[\"GET\"]`. */\n methods?: string[];\n /** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */\n keyGenerator?: (req: { method: string; url: string }) => string;\n}\n\n/**\n * Interceptor NestJS que cacheia o valor retornado pelos handlers. Num HIT,\n * devolve o valor do cache sem executar o handler.\n */\nexport class CacheInterceptor implements NestInterceptor {\n private readonly cache: Cache;\n private readonly ttlSeconds?: number;\n private readonly methods: string[];\n private readonly keyGenerator: (req: {\n method: string;\n url: string;\n }) => string;\n\n constructor(options: CacheInterceptorOptions) {\n this.cache = options.cache;\n this.ttlSeconds = options.ttlSeconds;\n this.methods = options.methods ?? [\"GET\"];\n this.keyGenerator =\n options.keyGenerator ?? ((req) => `${req.method}:${req.url}`);\n }\n\n intercept(\n context: ExecutionContext,\n next: CallHandler,\n ): Observable<unknown> {\n const req = context.switchToHttp().getRequest<{\n method: string;\n url: string;\n }>();\n\n if (!this.methods.includes(req.method)) {\n return next.handle();\n }\n\n const key = this.keyGenerator(req);\n const cached = this.cache.get(key);\n if (cached !== null) {\n return of(cached);\n }\n\n return next.handle().pipe(\n tap((body) => {\n if (body !== undefined && body !== null) {\n this.cache.set(\n key,\n body,\n this.ttlSeconds ? { ttlSeconds: this.ttlSeconds } : undefined,\n );\n }\n }),\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,kBAAwB;AAkBjB,IAAM,mBAAN,MAAkD;AAAA,EASvD,YAAY,SAAkC;AAC5C,SAAK,QAAQ,QAAQ;AACrB,SAAK,aAAa,QAAQ;AAC1B,SAAK,UAAU,QAAQ,WAAW,CAAC,KAAK;AACxC,SAAK,eACH,QAAQ,iBAAiB,CAAC,QAAQ,GAAG,IAAI,MAAM,IAAI,IAAI,GAAG;AAAA,EAC9D;AAAA,EAEA,UACE,SACA,MACqB;AACrB,UAAM,MAAM,QAAQ,aAAa,EAAE,WAGhC;AAEH,QAAI,CAAC,KAAK,QAAQ,SAAS,IAAI,MAAM,GAAG;AACtC,aAAO,KAAK,OAAO;AAAA,IACrB;AAEA,UAAM,MAAM,KAAK,aAAa,GAAG;AACjC,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,WAAW,MAAM;AACnB,iBAAO,gBAAG,MAAM;AAAA,IAClB;AAEA,WAAO,KAAK,OAAO,EAAE;AAAA,UACnB,iBAAI,CAAC,SAAS;AACZ,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC,eAAK,MAAM;AAAA,YACT;AAAA,YACA;AAAA,YACA,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI;AAAA,UACtD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
package/dist/nestjs.mjs
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// js/nestjs.ts
|
|
2
|
+
import { of, tap } from "rxjs";
|
|
3
|
+
var CacheInterceptor = class {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.cache = options.cache;
|
|
6
|
+
this.ttlSeconds = options.ttlSeconds;
|
|
7
|
+
this.methods = options.methods ?? ["GET"];
|
|
8
|
+
this.keyGenerator = options.keyGenerator ?? ((req) => `${req.method}:${req.url}`);
|
|
9
|
+
}
|
|
10
|
+
intercept(context, next) {
|
|
11
|
+
const req = context.switchToHttp().getRequest();
|
|
12
|
+
if (!this.methods.includes(req.method)) {
|
|
13
|
+
return next.handle();
|
|
14
|
+
}
|
|
15
|
+
const key = this.keyGenerator(req);
|
|
16
|
+
const cached = this.cache.get(key);
|
|
17
|
+
if (cached !== null) {
|
|
18
|
+
return of(cached);
|
|
19
|
+
}
|
|
20
|
+
return next.handle().pipe(
|
|
21
|
+
tap((body) => {
|
|
22
|
+
if (body !== void 0 && body !== null) {
|
|
23
|
+
this.cache.set(
|
|
24
|
+
key,
|
|
25
|
+
body,
|
|
26
|
+
this.ttlSeconds ? { ttlSeconds: this.ttlSeconds } : void 0
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export {
|
|
34
|
+
CacheInterceptor
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=nestjs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/nestjs.ts"],"sourcesContent":["/**\n * Integração com NestJS: interceptor de cache de respostas.\n *\n * Uso:\n * import { Cache } from \"rust-node-cache\";\n * import { CacheInterceptor } from \"rust-node-cache/nestjs\";\n *\n * const cache = new Cache();\n * app.useGlobalInterceptors(new CacheInterceptor({ cache, ttlSeconds: 60 }));\n *\n * Usamos `import type` para `@nestjs/common`, ou seja, NÃO há import em runtime\n * do Nest aqui — o pacote não força o Nest como dependência. A única dependência\n * de runtime são os operadores `of`/`tap` do RxJS (presentes em qualquer app Nest).\n */\n\nimport type {\n CallHandler,\n ExecutionContext,\n NestInterceptor,\n} from \"@nestjs/common\";\nimport type { Observable } from \"rxjs\";\nimport { of, tap } from \"rxjs\";\nimport type { Cache } from \"./index\";\n\nexport interface CacheInterceptorOptions {\n /** Instância de cache a usar. */\n cache: Cache;\n /** TTL aplicado às respostas guardadas (em segundos). */\n ttlSeconds?: number;\n /** Métodos HTTP elegíveis para cache. Padrão: `[\"GET\"]`. */\n methods?: string[];\n /** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */\n keyGenerator?: (req: { method: string; url: string }) => string;\n}\n\n/**\n * Interceptor NestJS que cacheia o valor retornado pelos handlers. Num HIT,\n * devolve o valor do cache sem executar o handler.\n */\nexport class CacheInterceptor implements NestInterceptor {\n private readonly cache: Cache;\n private readonly ttlSeconds?: number;\n private readonly methods: string[];\n private readonly keyGenerator: (req: {\n method: string;\n url: string;\n }) => string;\n\n constructor(options: CacheInterceptorOptions) {\n this.cache = options.cache;\n this.ttlSeconds = options.ttlSeconds;\n this.methods = options.methods ?? [\"GET\"];\n this.keyGenerator =\n options.keyGenerator ?? ((req) => `${req.method}:${req.url}`);\n }\n\n intercept(\n context: ExecutionContext,\n next: CallHandler,\n ): Observable<unknown> {\n const req = context.switchToHttp().getRequest<{\n method: string;\n url: string;\n }>();\n\n if (!this.methods.includes(req.method)) {\n return next.handle();\n }\n\n const key = this.keyGenerator(req);\n const cached = this.cache.get(key);\n if (cached !== null) {\n return of(cached);\n }\n\n return next.handle().pipe(\n tap((body) => {\n if (body !== undefined && body !== null) {\n this.cache.set(\n key,\n body,\n this.ttlSeconds ? { ttlSeconds: this.ttlSeconds } : undefined,\n );\n }\n }),\n );\n }\n}\n"],"mappings":";AAqBA,SAAS,IAAI,WAAW;AAkBjB,IAAM,mBAAN,MAAkD;AAAA,EASvD,YAAY,SAAkC;AAC5C,SAAK,QAAQ,QAAQ;AACrB,SAAK,aAAa,QAAQ;AAC1B,SAAK,UAAU,QAAQ,WAAW,CAAC,KAAK;AACxC,SAAK,eACH,QAAQ,iBAAiB,CAAC,QAAQ,GAAG,IAAI,MAAM,IAAI,IAAI,GAAG;AAAA,EAC9D;AAAA,EAEA,UACE,SACA,MACqB;AACrB,UAAM,MAAM,QAAQ,aAAa,EAAE,WAGhC;AAEH,QAAI,CAAC,KAAK,QAAQ,SAAS,IAAI,MAAM,GAAG;AACtC,aAAO,KAAK,OAAO;AAAA,IACrB;AAEA,UAAM,MAAM,KAAK,aAAa,GAAG;AACjC,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,WAAW,MAAM;AACnB,aAAO,GAAG,MAAM;AAAA,IAClB;AAEA,WAAO,KAAK,OAAO,EAAE;AAAA,MACnB,IAAI,CAAC,SAAS;AACZ,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC,eAAK,MAAM;AAAA,YACT;AAAA,YACA;AAAA,YACA,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI;AAAA,UACtD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|