rust-node-cache 0.1.0 → 0.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/README.md CHANGED
@@ -15,6 +15,8 @@ is **no compiler required at install time** on supported platforms.
15
15
  ![node](https://img.shields.io/badge/node-%3E%3D18-43853d)
16
16
  ![license](https://img.shields.io/badge/license-MIT-blue)
17
17
 
18
+ 🌐 **Website:** [rust-node-cache.vercel.app](https://rust-node-cache.vercel.app/)
19
+
18
20
  ---
19
21
 
20
22
  ## Features
@@ -22,8 +24,10 @@ is **no compiler required at install time** on supported platforms.
22
24
  - 🦀 **Rust-powered** core for predictable, low-overhead performance
23
25
  - 🔒 **Thread-safe** via `DashMap` (lock-sharded concurrent map)
24
26
  - ⏱️ **TTL support** per entry (lazy expiration + active cleanup)
27
+ - 🧹 **Background expiration** — optional sweeper thread (`cleanupIntervalSeconds`)
28
+ - 🧠 **LRU eviction** — bound the cache by `maxSize` with `evictionPolicy: "lru"`
25
29
  - ⚡ **Fast reads** and **fast writes**
26
- - 📊 Built-in **statistics** (hits, misses, sets, deletes, expired, size)
30
+ - 📊 Built-in **statistics** (hits, misses, sets, deletes, expired, evicted, size)
27
31
  - 🧩 **TypeScript** support with generics out of the box
28
32
  - 🌐 **Framework agnostic** — works with Express, Fastify, NestJS, Hono,
29
33
  Next.js, or plain Node.js
@@ -140,6 +144,35 @@ an active sweep:
140
144
  const removed = cache.cleanupExpired(); // number of entries removed
141
145
  ```
142
146
 
147
+ Or let the cache sweep for you in the background — set `cleanupIntervalSeconds`
148
+ and a thread reclaims expired entries on its own (no manual `cleanupExpired()`):
149
+
150
+ ```ts
151
+ const cache = new Cache({ cleanupIntervalSeconds: 30 });
152
+ ```
153
+
154
+ The thread is tied to the cache's lifetime: it stops automatically when the cache
155
+ is garbage-collected.
156
+
157
+ ---
158
+
159
+ ## Eviction (maxSize)
160
+
161
+ Cap the number of keys with `maxSize`. When the cache is full and a **new** key
162
+ is written, `evictionPolicy` decides what happens:
163
+
164
+ ```ts
165
+ // Default: reject the write (set returns false), keep existing entries.
166
+ const a = new Cache({ maxSize: 1000 }); // evictionPolicy: "reject"
167
+
168
+ // LRU: evict the least-recently-used entry to make room, then insert.
169
+ const b = new Cache({ maxSize: 1000, evictionPolicy: "lru" });
170
+ b.evictionPolicy; // "lru"
171
+ ```
172
+
173
+ LRU recency is tracked per entry (updated on every `get` hit) and the evicted
174
+ count is surfaced in `stats().evicted`. Overwriting an existing key never evicts.
175
+
143
176
  ---
144
177
 
145
178
  ## Statistics
@@ -157,6 +190,7 @@ Returns:
157
190
  sets: 800,
158
191
  deletes: 20,
159
192
  expired: 15,
193
+ evicted: 40,
160
194
  size: 780
161
195
  }
162
196
  ```
@@ -206,8 +240,9 @@ Bincode) later without touching the cache logic.
206
240
 
207
241
  | Method | Returns | Description |
208
242
  | ------------------------------ | -------------- | ----------------------------------------------------------------- |
209
- | `new Cache(options?)` | `Cache` | Create a cache. `options.maxSize` caps the number of keys. |
243
+ | `new Cache(options?)` | `Cache` | Create a cache (`maxSize`, `evictionPolicy`, `cleanupIntervalSeconds`). |
210
244
  | `set(key, value, options?)` | `boolean` | Store/overwrite a value. `options.ttlSeconds` sets expiration. |
245
+ | `evictionPolicy` (getter) | `string` | The active policy: `"reject"` or `"lru"`. |
211
246
  | `get<T>(key)` | `T \| null` | Read a value (lazy-expires stale entries). |
212
247
  | `delete(key)` | `boolean` | Remove a key. `true` if it existed. |
213
248
  | `exists(key)` | `boolean` | Whether the key exists and is valid. |
@@ -221,6 +256,8 @@ Bincode) later without touching the cache logic.
221
256
  ```ts
222
257
  interface CacheOptions {
223
258
  maxSize?: number;
259
+ evictionPolicy?: "reject" | "lru"; // default "reject"
260
+ cleanupIntervalSeconds?: number; // enables the background sweeper
224
261
  }
225
262
 
226
263
  interface SetOptions {
@@ -233,6 +270,7 @@ interface CacheStats {
233
270
  sets: number;
234
271
  deletes: number;
235
272
  expired: number;
273
+ evicted: number;
236
274
  size: number;
237
275
  }
238
276
  ```
@@ -321,15 +359,14 @@ Coming soon.
321
359
 
322
360
  ## Roadmap
323
361
 
324
- | Version | Feature |
325
- | ------- | ------------------------ |
326
- | v0.1 | Basic cache |
327
- | v0.2 | TTL cleanup thread |
328
- | v0.3 | LRU cache |
329
- | v0.4 | LFU cache |
330
- | v0.5 | Redis synchronization |
331
- | v0.6 | Prometheus metrics |
332
- | v0.7 | ImmutableLog integration |
362
+ | Version | Feature | Status |
363
+ | ------- | ------------------------ | ------ |
364
+ | v0.1 | Basic cache | ✅ |
365
+ | v0.2 | TTL cleanup thread + LRU eviction | ✅ |
366
+ | v0.3 | LFU cache | 🔜 |
367
+ | v0.4 | Redis synchronization | 🔜 |
368
+ | v0.5 | Prometheus metrics | 🔜 |
369
+ | v0.6 | ImmutableLog integration | 🔜 |
333
370
 
334
371
  ### Future: ImmutableLog Integration
335
372
 
package/binding.d.ts CHANGED
@@ -3,10 +3,26 @@
3
3
 
4
4
  /* auto-generated by NAPI-RS */
5
5
 
6
- /** Opções do construtor: `new Cache({ maxSize })`. */
6
+ /**
7
+ * Opções do construtor:
8
+ * `new Cache({ maxSize, evictionPolicy, cleanupIntervalSeconds })`.
9
+ */
7
10
  export interface CacheOptions {
8
- /** Limite opcional de chaves. Ao atingir, `set` de chave nova retorna `false`. */
11
+ /**
12
+ * Limite opcional de chaves. Comportamento ao atingir depende de
13
+ * `evictionPolicy`.
14
+ */
9
15
  maxSize?: number
16
+ /**
17
+ * `"reject"` (padrão) — `set` de chave nova retorna `false` quando cheio;
18
+ * `"lru"` — remove a entrada menos recentemente usada e prossegue.
19
+ */
20
+ evictionPolicy?: string
21
+ /**
22
+ * Se definido (> 0), liga uma thread que varre entradas expiradas a cada
23
+ * N segundos (expiração em background, além da lazy).
24
+ */
25
+ cleanupIntervalSeconds?: number
10
26
  }
11
27
  /** Opções por escrita: `cache.set(key, value, { ttlSeconds })`. */
12
28
  export interface SetOptions {
@@ -20,6 +36,7 @@ export interface CacheStatsObject {
20
36
  sets: number
21
37
  deletes: number
22
38
  expired: number
39
+ evicted: number
23
40
  size: number
24
41
  }
25
42
  /**
@@ -30,8 +47,10 @@ export interface CacheStatsObject {
30
47
  * concorrente por dentro, várias chamadas podem rodar em paralelo.
31
48
  */
32
49
  export declare class Cache {
33
- /** `new Cache()` ou `new Cache({ maxSize })`. */
50
+ /** `new Cache()` ou `new Cache({ maxSize, evictionPolicy, cleanupIntervalSeconds })`. */
34
51
  constructor(options?: CacheOptions | undefined | null)
52
+ /** A política de evicção ativa: `"reject"` ou `"lru"`. */
53
+ get evictionPolicy(): string
35
54
  /**
36
55
  * Insere/atualiza uma chave. Retorna `true` em sucesso, `false` se o cache
37
56
  * estiver cheio (`maxSize`) e a chave for nova.
package/dist/index.d.mts CHANGED
@@ -12,14 +12,26 @@
12
12
  * O custo é uma chamada de função extra por operação — desprezível frente ao
13
13
  * trabalho real (serialização + acesso ao DashMap) que acontece no Rust.
14
14
  */
15
+ /** Estratégia de evicção quando `maxSize` é atingido. */
16
+ type EvictionPolicy = "reject" | "lru";
15
17
  /** Opções do construtor do cache. */
16
18
  interface CacheOptions {
17
19
  /**
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.
20
+ * Limite máximo de chaves. O que acontece ao atingir depende de
21
+ * `evictionPolicy`. Sem valor => cache ilimitado.
21
22
  */
22
23
  maxSize?: number;
24
+ /**
25
+ * Política ao atingir `maxSize` numa chave **nova**:
26
+ * - `"reject"` (padrão): `set` retorna `false` (sobrescrever continua ok);
27
+ * - `"lru"`: remove a entrada menos recentemente usada e prossegue.
28
+ */
29
+ evictionPolicy?: EvictionPolicy;
30
+ /**
31
+ * Se definido (> 0), liga uma thread que varre entradas expiradas a cada
32
+ * N segundos (expiração em background, além da preguiçosa por acesso).
33
+ */
34
+ cleanupIntervalSeconds?: number;
23
35
  }
24
36
  /** Opções por operação de escrita. */
25
37
  interface SetOptions {
@@ -38,6 +50,8 @@ interface CacheStats {
38
50
  deletes: number;
39
51
  /** Total de entradas removidas por expiração. */
40
52
  expired: number;
53
+ /** Total de entradas removidas por evicção (política LRU ao atingir `maxSize`). */
54
+ evicted: number;
41
55
  /** Número de chaves armazenadas agora. */
42
56
  size: number;
43
57
  }
@@ -58,6 +72,8 @@ declare class Cache {
58
72
  /** Instância da classe nativa (Rust). */
59
73
  private readonly native;
60
74
  constructor(options?: CacheOptions);
75
+ /** A política de evicção ativa: `"reject"` ou `"lru"`. */
76
+ get evictionPolicy(): EvictionPolicy;
61
77
  /**
62
78
  * Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
63
79
  *
@@ -88,4 +104,4 @@ declare class Cache {
88
104
  stats(): CacheStats;
89
105
  }
90
106
 
91
- export { Cache, type CacheOptions, type CacheStats, type SetOptions };
107
+ export { Cache, type CacheOptions, type CacheStats, type EvictionPolicy, type SetOptions };
package/dist/index.d.ts CHANGED
@@ -12,14 +12,26 @@
12
12
  * O custo é uma chamada de função extra por operação — desprezível frente ao
13
13
  * trabalho real (serialização + acesso ao DashMap) que acontece no Rust.
14
14
  */
15
+ /** Estratégia de evicção quando `maxSize` é atingido. */
16
+ type EvictionPolicy = "reject" | "lru";
15
17
  /** Opções do construtor do cache. */
16
18
  interface CacheOptions {
17
19
  /**
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.
20
+ * Limite máximo de chaves. O que acontece ao atingir depende de
21
+ * `evictionPolicy`. Sem valor => cache ilimitado.
21
22
  */
22
23
  maxSize?: number;
24
+ /**
25
+ * Política ao atingir `maxSize` numa chave **nova**:
26
+ * - `"reject"` (padrão): `set` retorna `false` (sobrescrever continua ok);
27
+ * - `"lru"`: remove a entrada menos recentemente usada e prossegue.
28
+ */
29
+ evictionPolicy?: EvictionPolicy;
30
+ /**
31
+ * Se definido (> 0), liga uma thread que varre entradas expiradas a cada
32
+ * N segundos (expiração em background, além da preguiçosa por acesso).
33
+ */
34
+ cleanupIntervalSeconds?: number;
23
35
  }
24
36
  /** Opções por operação de escrita. */
25
37
  interface SetOptions {
@@ -38,6 +50,8 @@ interface CacheStats {
38
50
  deletes: number;
39
51
  /** Total de entradas removidas por expiração. */
40
52
  expired: number;
53
+ /** Total de entradas removidas por evicção (política LRU ao atingir `maxSize`). */
54
+ evicted: number;
41
55
  /** Número de chaves armazenadas agora. */
42
56
  size: number;
43
57
  }
@@ -58,6 +72,8 @@ declare class Cache {
58
72
  /** Instância da classe nativa (Rust). */
59
73
  private readonly native;
60
74
  constructor(options?: CacheOptions);
75
+ /** A política de evicção ativa: `"reject"` ou `"lru"`. */
76
+ get evictionPolicy(): EvictionPolicy;
61
77
  /**
62
78
  * Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
63
79
  *
@@ -88,4 +104,4 @@ declare class Cache {
88
104
  stats(): CacheStats;
89
105
  }
90
106
 
91
- export { Cache, type CacheOptions, type CacheStats, type SetOptions };
107
+ export { Cache, type CacheOptions, type CacheStats, type EvictionPolicy, type SetOptions };
package/dist/index.js CHANGED
@@ -36,7 +36,16 @@ module.exports = __toCommonJS(index_exports);
36
36
  var native = __toESM(require("../binding.js"));
37
37
  var Cache2 = class {
38
38
  constructor(options = {}) {
39
- this.native = options.maxSize !== void 0 ? new native.Cache({ maxSize: options.maxSize }) : new native.Cache();
39
+ const hasOptions = options.maxSize !== void 0 || options.evictionPolicy !== void 0 || options.cleanupIntervalSeconds !== void 0;
40
+ this.native = hasOptions ? new native.Cache({
41
+ maxSize: options.maxSize,
42
+ evictionPolicy: options.evictionPolicy,
43
+ cleanupIntervalSeconds: options.cleanupIntervalSeconds
44
+ }) : new native.Cache();
45
+ }
46
+ /** A política de evicção ativa: `"reject"` ou `"lru"`. */
47
+ get evictionPolicy() {
48
+ return this.native.evictionPolicy;
40
49
  }
41
50
  /**
42
51
  * Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
package/dist/index.js.map CHANGED
@@ -1 +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"]}
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/** Estratégia de evicção quando `maxSize` é atingido. */\nexport type EvictionPolicy = \"reject\" | \"lru\";\n\n/** Opções do construtor do cache. */\nexport interface CacheOptions {\n /**\n * Limite máximo de chaves. O que acontece ao atingir depende de\n * `evictionPolicy`. Sem valor => cache ilimitado.\n */\n maxSize?: number;\n /**\n * Política ao atingir `maxSize` numa chave **nova**:\n * - `\"reject\"` (padrão): `set` retorna `false` (sobrescrever continua ok);\n * - `\"lru\"`: remove a entrada menos recentemente usada e prossegue.\n */\n evictionPolicy?: EvictionPolicy;\n /**\n * Se definido (> 0), liga uma thread que varre entradas expiradas a cada\n * N segundos (expiração em background, além da preguiçosa por acesso).\n */\n cleanupIntervalSeconds?: 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 /** Total de entradas removidas por evicção (política LRU ao atingir `maxSize`). */\n evicted: 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 um objeto de opções ao Rust quando há algo relevante.\n const hasOptions =\n options.maxSize !== undefined ||\n options.evictionPolicy !== undefined ||\n options.cleanupIntervalSeconds !== undefined;\n this.native = hasOptions\n ? new native.Cache({\n maxSize: options.maxSize,\n evictionPolicy: options.evictionPolicy,\n cleanupIntervalSeconds: options.cleanupIntervalSeconds,\n })\n : new native.Cache();\n }\n\n /** A política de evicção ativa: `\"reject\"` ou `\"lru\"`. */\n get evictionPolicy(): EvictionPolicy {\n return this.native.evictionPolicy as EvictionPolicy;\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;AA8DjB,IAAMA,SAAN,MAAY;AAAA,EAIjB,YAAY,UAAwB,CAAC,GAAG;AAEtC,UAAM,aACJ,QAAQ,YAAY,UACpB,QAAQ,mBAAmB,UAC3B,QAAQ,2BAA2B;AACrC,SAAK,SAAS,aACV,IAAW,aAAM;AAAA,MACf,SAAS,QAAQ;AAAA,MACjB,gBAAgB,QAAQ;AAAA,MACxB,wBAAwB,QAAQ;AAAA,IAClC,CAAC,IACD,IAAW,aAAM;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,iBAAiC;AACnC,WAAO,KAAK,OAAO;AAAA,EACrB;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 CHANGED
@@ -2,7 +2,16 @@
2
2
  import * as native from "../binding.js";
3
3
  var Cache2 = class {
4
4
  constructor(options = {}) {
5
- this.native = options.maxSize !== void 0 ? new native.Cache({ maxSize: options.maxSize }) : new native.Cache();
5
+ const hasOptions = options.maxSize !== void 0 || options.evictionPolicy !== void 0 || options.cleanupIntervalSeconds !== void 0;
6
+ this.native = hasOptions ? new native.Cache({
7
+ maxSize: options.maxSize,
8
+ evictionPolicy: options.evictionPolicy,
9
+ cleanupIntervalSeconds: options.cleanupIntervalSeconds
10
+ }) : new native.Cache();
11
+ }
12
+ /** A política de evicção ativa: `"reject"` ou `"lru"`. */
13
+ get evictionPolicy() {
14
+ return this.native.evictionPolicy;
6
15
  }
7
16
  /**
8
17
  * Armazena (ou sobrescreve) um valor. O valor é serializado como JSON no core.
@@ -1 +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"]}
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/** Estratégia de evicção quando `maxSize` é atingido. */\nexport type EvictionPolicy = \"reject\" | \"lru\";\n\n/** Opções do construtor do cache. */\nexport interface CacheOptions {\n /**\n * Limite máximo de chaves. O que acontece ao atingir depende de\n * `evictionPolicy`. Sem valor => cache ilimitado.\n */\n maxSize?: number;\n /**\n * Política ao atingir `maxSize` numa chave **nova**:\n * - `\"reject\"` (padrão): `set` retorna `false` (sobrescrever continua ok);\n * - `\"lru\"`: remove a entrada menos recentemente usada e prossegue.\n */\n evictionPolicy?: EvictionPolicy;\n /**\n * Se definido (> 0), liga uma thread que varre entradas expiradas a cada\n * N segundos (expiração em background, além da preguiçosa por acesso).\n */\n cleanupIntervalSeconds?: 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 /** Total de entradas removidas por evicção (política LRU ao atingir `maxSize`). */\n evicted: 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 um objeto de opções ao Rust quando há algo relevante.\n const hasOptions =\n options.maxSize !== undefined ||\n options.evictionPolicy !== undefined ||\n options.cleanupIntervalSeconds !== undefined;\n this.native = hasOptions\n ? new native.Cache({\n maxSize: options.maxSize,\n evictionPolicy: options.evictionPolicy,\n cleanupIntervalSeconds: options.cleanupIntervalSeconds,\n })\n : new native.Cache();\n }\n\n /** A política de evicção ativa: `\"reject\"` ou `\"lru\"`. */\n get evictionPolicy(): EvictionPolicy {\n return this.native.evictionPolicy as EvictionPolicy;\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;AA8DjB,IAAMA,SAAN,MAAY;AAAA,EAIjB,YAAY,UAAwB,CAAC,GAAG;AAEtC,UAAM,aACJ,QAAQ,YAAY,UACpB,QAAQ,mBAAmB,UAC3B,QAAQ,2BAA2B;AACrC,SAAK,SAAS,aACV,IAAW,aAAM;AAAA,MACf,SAAS,QAAQ;AAAA,MACjB,gBAAgB,QAAQ;AAAA,MACxB,wBAAwB,QAAQ;AAAA,IAClC,CAAC,IACD,IAAW,aAAM;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,iBAAiC;AACnC,WAAO,KAAK,OAAO;AAAA,EACrB;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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rust-node-cache",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Ultra-fast in-memory cache for Node.js powered by Rust.",
5
5
  "keywords": [
6
6
  "cache",
@@ -23,7 +23,7 @@
23
23
  "type": "git",
24
24
  "url": "https://github.com/robertolima-dev/rust-node-cache.git"
25
25
  },
26
- "homepage": "https://github.com/robertolima-dev/rust-node-cache",
26
+ "homepage": "https://rust-node-cache.vercel.app",
27
27
  "main": "dist/index.js",
28
28
  "module": "dist/index.mjs",
29
29
  "types": "dist/index.d.ts",
Binary file
Binary file
Binary file
Binary file