npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

cachemind

v0.1.1

Published

A lightweight, universal JavaScript cache library with multiple caching strategies

Readme

CacheMind

Uma biblioteca de cache JavaScript leve, universal e modular com múltiplas estratégias de cache.

License: MIT

🎯 Características

  • Performance O(1): Operações de leitura e escrita com complexidade de tempo constante
  • 🌐 Universal (Isomórfico): Funciona tanto em navegadores modernos quanto no Node.js
  • 📦 Bundle Leve: Sem dependências externas, otimizado para tree-shaking
  • 🧪 Bem Testado: Alta cobertura de testes unitários
  • 📚 Bem Documentado: JSDoc completo e exemplos claros
  • 🔧 Modular: Arquitetura extensível para novas estratégias de cache

📦 Instalação

npm install cachemind
yarn add cachemind
pnpm add cachemind

🚀 Uso Básico

Importação

import { BaseCache, TTLCache } from 'cachemind';

Exemplo Simples com BaseCache

import { BaseCache } from 'cachemind';

// Criar uma instância de cache
const cache = new BaseCache<string>();

// Armazenar valores
cache.set('user:1', 'John Doe');
cache.set('user:2', 'Jane Smith');

// Recuperar valores
const user1 = cache.get('user:1'); // 'John Doe'
const user2 = cache.get('user:2'); // 'Jane Smith'

// Verificar existência
if (cache.has('user:1')) {
  console.log('Usuário existe no cache');
}

// Remover item
cache.delete('user:1');

// Limpar todo o cache
cache.clear();

Exemplo com TTLCache (Estratégia TTL)

import { TTLCache } from 'cachemind';

// Criar cache com TTL padrão de 1 hora
const cache = new TTLCache<string>({ defaultTTL: 3600000 });

// Armazenar com TTL padrão
cache.set('user:1', 'John Doe');

// Armazenar com TTL customizado (5 minutos)
cache.set('session:123', 'active', { ttl: 5 * 60 * 1000 });

// Verificar se item está expirado (stale)
if (cache.isStale('user:1')) {
  // Item existe mas está expirado - pode fazer refresh
  cache.set('user:1', await fetchFreshData(), { ttl: 3600000 });
}

// Verificar tempo restante até expiração
const remaining = cache.getRemainingTTL('session:123');
if (remaining !== undefined) {
  console.log(`Sessão expira em ${remaining}ms`);
}

Exemplo com SWRCache (Estratégia SWR)

import { SWRCache } from 'cachemind';

// Criar cache SWR com TTL padrão de 1 hora
const cache = new SWRCache<string>({ defaultTTL: 3600000 });

// Configurar item com função de fetch para revalidação automática
await cache.setWithFetch('user:1', 'John Doe', {
  ttl: 3600000,
  fetch: async () => {
    const response = await fetch('/api/user/1');
    const data = await response.json();
    return data.name;
  }
});

// Primeira vez: retorna valor imediatamente
const user = cache.get('user:1'); // 'John Doe'

// Após expirar: retorna valor stale imediatamente e revalida em background
// (o valor stale é retornado sem esperar pela revalidação)
const staleUser = cache.get('user:1'); // 'John Doe' (stale, mas retornado)
// Em background: fetch é chamado e cache é atualizado silenciosamente

Exemplo com LRUCache (Estratégia LRU)

import { LRUCache } from 'cachemind';

// Criar cache LRU com capacidade máxima de 3 itens
const cache = new LRUCache<string>({ maxSize: 3 });

// Preenche cache até capacidade máxima
cache.set('key1', 'value1');
cache.set('key2', 'value2');
cache.set('key3', 'value3');

// Acessa key1 (torna-se mais recentemente usado)
cache.get('key1');

// Adiciona novo item - key2 é removido (menos recentemente usado)
cache.set('key4', 'value4');
// key2 não está mais no cache

Exemplo com DTTCache (Estratégia Dynamic TTL)

import { DTTCache } from 'cachemind';

const cache = new DTTCache<string>();

// TTL baseado em headers HTTP
await cache.setWithDynamicTTL('api:data', 'response data', {
  ttlCalculator: (value, metadata) => {
    const cacheControl = metadata?.headers?.['cache-control'];
    if (cacheControl) {
      const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
      if (maxAgeMatch) {
        return parseInt(maxAgeMatch[1], 10) * 1000; // Converte para ms
      }
    }
    return 3600000; // Fallback: 1 hora
  },
  metadata: {
    headers: {
      'cache-control': 'max-age=300', // 5 minutos
    },
  },
});

// TTL baseado em propriedade do dado
interface Product {
  isPremium: boolean;
  category: string;
}

const productCache = new DTTCache<Product>();

await productCache.setWithDynamicTTL('product:1', product, {
  ttlCalculator: (value) => {
    // Produtos premium têm TTL maior
    return value.isPremium ? 7200000 : 3600000;
  },
});

📖 API Reference

BaseCache<T>

Classe base para cache em memória. Permite TTL opcional.

TTLCache<T>

Estratégia de cache baseada em TTL (Time-To-Live). Garante que todos os itens tenham TTL definido.

Construtor

new TTLCache<T>(options: { defaultTTL: number })

Cria uma nova instância de cache com TTL obrigatório.

Parâmetros:

  • options.defaultTTL: TTL padrão em milissegundos (obrigatório)

Exemplo:

// Cache com TTL padrão de 1 hora
const cache = new TTLCache<string>({ defaultTTL: 3600000 });

// Cache com TTL padrão de 5 minutos
const sessionCache = new TTLCache<Session>({ defaultTTL: 5 * 60 * 1000 });

Métodos Específicos

isStale(key: string): boolean

Verifica se um item está expirado (stale) sem removê-lo.

Complexidade: O(1)

Parâmetros:

  • key: Chave do item a ser verificado

Retorna: true se o item existe mas está expirado, false caso contrário

Exemplo:

if (cache.isStale('key')) {
  // Item expirado - fazer refresh
  cache.set('key', await fetchFreshData(), { ttl: 3600000 });
}
getRemainingTTL(key: string): number | undefined

Retorna o tempo restante até a expiração de um item.

Complexidade: O(1)

Parâmetros:

  • key: Chave do item a ser verificado

Retorna: Tempo restante em milissegundos, ou undefined se o item não existe

Exemplo:

const remaining = cache.getRemainingTTL('session:123');
if (remaining !== undefined && remaining < 60000) {
  // Menos de 1 minuto restante - avisar usuário
  console.log('Sessão expira em breve');
}

Métodos Herdados

TTLCache implementa a interface ICache<T>, então todos os métodos de BaseCache estão disponíveis:

  • get(key), getAsync(key), set(key, value, options), has(key), delete(key), clear(), size

Nota: Em TTLCache, o método set() sempre aplica TTL. Se options.ttl não for fornecido, usa o defaultTTL.

SWRCache<T>

Estratégia de cache baseada em Stale-While-Revalidate (SWR). Retorna dados stale imediatamente enquanto revalida em background.

Construtor

new SWRCache<T>(options: { defaultTTL: number })

Cria uma nova instância de cache SWR com TTL obrigatório.

Parâmetros:

  • options.defaultTTL: TTL padrão em milissegundos (obrigatório)

Exemplo:

// Cache SWR com TTL padrão de 1 hora
const cache = new SWRCache<string>({ defaultTTL: 3600000 });

Métodos Específicos

setWithFetch(key: string, initialValue: T | Promise<T>, options: SWROptions<T>): Promise<void>

Configura um item no cache com função de fetch para revalidação automática.

Parâmetros:

  • key: Chave do item
  • initialValue: Valor inicial (ou Promise que resolve para o valor)
  • options: Opções incluindo ttl e fetch

Exemplo:

await cache.setWithFetch('user:1', 'John Doe', {
  ttl: 3600000,
  fetch: async () => {
    const response = await fetch('/api/user/1');
    return response.json().name;
  }
});
isStale(key: string): boolean

Verifica se um item está expirado (stale).

Complexidade: O(1)

Parâmetros:

  • key: Chave do item a ser verificado

Retorna: true se o item está stale, false caso contrário

Métodos Herdados

SWRCache implementa a interface ICache<T>, então todos os métodos de BaseCache estão disponíveis:

  • get(key), getAsync(key), set(key, value, options), has(key), delete(key), clear(), size

Nota: Quando um item está stale, get() retorna o valor stale imediatamente e inicia revalidação em background (se houver função de fetch configurada).

LRUCache<T>

Estratégia de cache baseada em LRU (Least Recently Used). Remove o item menos recentemente usado quando a capacidade máxima é atingida.

Construtor

new LRUCache<T>(options: { maxSize: number })

Cria uma nova instância de cache LRU com capacidade máxima.

Parâmetros:

  • options.maxSize: Capacidade máxima do cache (obrigatório, mínimo 1)

Exemplo:

// Cache LRU com capacidade máxima de 100 itens
const cache = new LRUCache<string>({ maxSize: 100 });

Métodos Específicos

maxSizeProperty: number (readonly)

Retorna a capacidade máxima do cache.

Complexidade: O(1)

Métodos Herdados

LRUCache implementa a interface ICache<T>, então todos os métodos de BaseCache estão disponíveis:

  • get(key), getAsync(key), set(key, value, options), has(key), delete(key), clear(), size

Nota:

  • Ao acessar um item (get() ou set()), ele torna-se mais recentemente usado
  • Quando a capacidade máxima é atingida e um novo item é inserido, o item menos recentemente usado é removido automaticamente
  • Ordem de uso é atualizada a cada acesso (leitura ou escrita)

DTTCache<T>

Estratégia de cache baseada em Dynamic TTL (TTL Dinâmico). Calcula TTL dinamicamente com base em metadados da resposta (headers HTTP, propriedades do dado, etc.).

Construtor

new DTTCache<T>()

Cria uma nova instância de cache DTTC.

Exemplo:

const cache = new DTTCache<string>();

Métodos Específicos

setWithDynamicTTL(key: string, value: T | Promise<T>, options: DTTCOptions<T>): Promise<void>

Armazena um valor no cache com TTL calculado dinamicamente.

Parâmetros:

  • key: Chave do item
  • value: Valor a ser armazenado (ou Promise que resolve para o valor)
  • options: Opções incluindo função de cálculo de TTL e metadados

Exemplo:

// TTL baseado em headers HTTP
await cache.setWithDynamicTTL('api:data', responseData, {
  ttlCalculator: (value, metadata) => {
    const maxAge = metadata?.headers?.['cache-control'];
    return parseMaxAge(maxAge) * 1000;
  },
  metadata: { headers: response.headers },
});

// TTL baseado em propriedade do dado
await cache.setWithDynamicTTL('product:1', product, {
  ttlCalculator: (value) => {
    return value.isPremium ? 7200000 : 3600000;
  },
});

Nota:

  • Se a função ttlCalculator retornar undefined ou lançar erro, o ttl estático será usado como fallback (se fornecido)
  • A função recebe o valor resolvido e metadados opcionais (headers HTTP, etc.)
  • Suporta Promises - resolve automaticamente antes de calcular TTL

Métodos Herdados

DTTCache implementa a interface ICache<T>, então todos os métodos de BaseCache estão disponíveis:

  • get(key), getAsync(key), set(key, value, options), has(key), delete(key), clear(), size

Nota: Para usar TTL dinâmico, use setWithDynamicTTL(). O método set() padrão funciona normalmente com TTL estático.

BaseCache<T>

Classe base para cache em memória. Permite TTL opcional.

Construtor

new BaseCache<T>()

Cria uma nova instância de cache.

Exemplo:

const cache = new BaseCache<string>();
const numberCache = new BaseCache<number>();

Métodos

get(key: string): T | undefined

Recupera um valor do cache pela chave (síncrono).

Complexidade: O(1)

Parâmetros:

  • key: Chave do item a ser recuperado

Retorna: O valor associado à chave (síncrono), ou undefined se não existir, tiver expirado, ou for uma Promise ainda pendente

Nota: Para valores assíncronos (Promises), use getAsync.

Exemplo:

const value = cache.get('myKey');
if (value !== undefined) {
  console.log(value);
}
getAsync(key: string): Promise<T | undefined>

Recupera um valor do cache pela chave, aguardando resolução de Promises se necessário.

Complexidade: O(1) para acesso, mas pode aguardar resolução de Promise

Este método é inteligente o suficiente para:

  • Retornar valores síncronos imediatamente
  • Aguardar a resolução de Promises se os dados estiverem sendo buscados pela primeira vez
  • Retornar valores já resolvidos de Promises anteriores

Parâmetros:

  • key: Chave do item a ser recuperado

Retorna: Promise que resolve para o valor, ou undefined se não existir ou tiver expirado

Exemplo:

// Valor síncrono
const syncValue = await cache.getAsync('syncKey'); // Retorna imediatamente

// Valor assíncrono
const asyncValue = await cache.getAsync('asyncKey'); // Aguarda resolução
set(key: string, value: T | Promise<T>, options?: CacheOptions): boolean

Armazena um valor no cache. Suporta valores síncronos e assíncronos (Promises).

Complexidade: O(1)

Parâmetros:

  • key: Chave do item a ser armazenado
  • value: Valor a ser armazenado (síncrono ou Promise)
  • options (opcional): Opções adicionais
    • ttl: Tempo de vida em milissegundos

Retorna: true se o valor foi armazenado com sucesso

Exemplo:

// Armazenar valor síncrono
cache.set('key', 'value');

// Armazenar Promise
cache.set('key', fetch('/api/data').then(r => r.json()));

// Armazenar com TTL de 1 hora
cache.set('key', 'value', { ttl: 3600000 });
has(key: string): boolean

Verifica se uma chave existe no cache e não expirou.

Complexidade: O(1)

Parâmetros:

  • key: Chave a ser verificada

Retorna: true se a chave existe e não expirou, false caso contrário

Exemplo:

if (cache.has('myKey')) {
  const value = cache.get('myKey');
}
delete(key: string): boolean

Remove um item do cache pela chave.

Complexidade: O(1)

Parâmetros:

  • key: Chave do item a ser removido

Retorna: true se o item foi removido, false se não existia

Exemplo:

const removed = cache.delete('myKey');
if (removed) {
  console.log('Item removido com sucesso');
}
clear(): void

Remove todos os itens do cache.

Complexidade: O(n) onde n é o número de itens

Exemplo:

cache.clear();
console.log(cache.size); // 0

Propriedades

size: number (readonly)

Retorna o número de itens ativos no cache (não expirados).

Exemplo:

cache.set('key1', 'value1');
cache.set('key2', 'value2');
console.log(cache.size); // 2

💡 Exemplos de Uso

Cache com TTL (Time To Live)

import { BaseCache } from 'cachemind';

const cache = new BaseCache<string>();

// Armazenar com expiração de 1 hora (3600000ms)
cache.set('session:user123', 'active', { ttl: 3600000 });

// Armazenar com expiração de 5 minutos
cache.set('temp:data', 'temporary', { ttl: 5 * 60 * 1000 });

// O item será automaticamente removido após expirar
setTimeout(() => {
  const value = cache.get('temp:data'); // undefined (expirado)
}, 6 * 60 * 1000);

Cache de Objetos Complexos

import { BaseCache } from 'cachemind';

interface User {
  id: number;
  name: string;
  email: string;
}

const userCache = new BaseCache<User>();

userCache.set('user:1', {
  id: 1,
  name: 'John Doe',
  email: '[email protected]'
});

const user = userCache.get('user:1');
console.log(user?.name); // 'John Doe'

Cache de Resultados de Funções (Memoization)

import { BaseCache } from 'cachemind';

const resultCache = new BaseCache<number>();

function expensiveCalculation(n: number): number {
  // Verifica se o resultado já está em cache
  const cached = resultCache.get(`calc:${n}`);
  if (cached !== undefined) {
    return cached;
  }

  // Realiza cálculo caro
  const result = n * n * n; // Exemplo simplificado

  // Armazena no cache por 1 hora
  resultCache.set(`calc:${n}`, result, { ttl: 3600000 });

  return result;
}

// Primeira chamada: calcula e armazena
const result1 = expensiveCalculation(10); // Calcula

// Segunda chamada: retorna do cache
const result2 = expensiveCalculation(10); // Cache hit!

Cache de Requisições HTTP com Promises

import { BaseCache } from 'cachemind';

const apiCache = new BaseCache<{ id: string; name: string }>();

async function fetchUserData(userId: string) {
  const cacheKey = `api:user:${userId}`;
  
  // Verifica cache síncrono (valores já resolvidos)
  const cached = apiCache.get(cacheKey);
  if (cached) {
    return cached;
  }

  // Faz requisição e armazena a Promise no cache
  const promise = fetch(`/api/users/${userId}`)
    .then(r => r.json());
  
  // Armazena a Promise no cache por 5 minutos
  apiCache.set(cacheKey, promise, { ttl: 5 * 60 * 1000 });

  // Aguarda resolução (primeira vez) ou retorna valor cacheado
  return await apiCache.getAsync(cacheKey);
}

Cache de Funções Assíncronas (Memoization)

import { BaseCache } from 'cachemind';

const resultCache = new BaseCache<number>();

async function expensiveAsyncCalculation(n: number): Promise<number> {
  const cacheKey = `calc:${n}`;
  
  // Verifica se já está em cache
  const cached = await resultCache.getAsync(cacheKey);
  if (cached !== undefined) {
    return cached;
  }

  // Realiza cálculo assíncrono caro
  const promise = new Promise<number>(resolve => {
    setTimeout(() => {
      resolve(n * n * n);
    }, 1000);
  });

  // Armazena a Promise no cache
  resultCache.set(cacheKey, promise, { ttl: 3600000 });

  // Aguarda e retorna o resultado
  return await resultCache.getAsync(cacheKey);
}

// Primeira chamada: calcula e cacheia
const result1 = await expensiveAsyncCalculation(10); // Aguarda 1s

// Segunda chamada: retorna do cache imediatamente
const result2 = await expensiveAsyncCalculation(10); // Retorna instantaneamente

🏗️ Arquitetura

A biblioteca foi projetada com modularidade em mente (RNF06). A interface ICache define o contrato base que todas as estratégias devem seguir:

interface ICache<T> {
  get(key: string): T | undefined;
  set(key: string, value: T, options?: CacheOptions): boolean;
  has(key: string): boolean;
  delete(key: string): boolean;
  clear(): void;
  readonly size: number;
}

Isso permite que futuras estratégias (LRU, FIFO, LFU, etc.) sejam facilmente adicionadas mantendo a mesma API.

⚡ Performance

A implementação utiliza Map nativo do JavaScript, garantindo:

  • O(1) para operações get, set, has e delete
  • O(n) para clear e size (onde n é o número de itens)

Benchmarks

Em testes com 10.000 itens:

  • set: ~0.001ms por operação
  • get: ~0.001ms por operação
  • has: ~0.001ms por operação
  • delete: ~0.001ms por operação

🧪 Testes

Execute os testes:

npm test

Com cobertura:

npm run test:coverage

Interface de testes (UI):

npm run test:ui

📝 Requisitos Não-Funcionais

  • RNF01: Performance O(1) para get/set em memória
  • RNF02: Universal (browser + Node.js)
  • RNF03: Bundle size reduzido (sem dependências)
  • RNF04: Alta cobertura de testes
  • RNF05: Documentação completa (JSDoc + README)
  • RNF06: Arquitetura modular e extensível

🎯 Estratégias de Cache

TTLCache (RF03) ✅

Estratégia baseada em TTL (Time-To-Live) que garante que todos os itens tenham tempo de expiração definido.

Características:

  • TTL obrigatório para todos os itens
  • Métodos isStale() e getRemainingTTL() para gerenciamento avançado
  • Ideal para caches que precisam de expiração automática

Exemplo:

const cache = new TTLCache<string>({ defaultTTL: 3600000 });

// Todos os itens terão TTL
cache.set('key1', 'value1'); // Usa defaultTTL
cache.set('key2', 'value2', { ttl: 5000 }); // TTL customizado

// Verificar expiração
if (cache.isStale('key1')) {
  // Fazer refresh
}

SWRCache (RF04) ✅

Estratégia Stale-While-Revalidate (SWR) que retorna dados stale imediatamente enquanto revalida em background.

Características:

  • Retorna dados stale imediatamente quando item expirou
  • Revalidação automática em background quando há função de fetch
  • Atualização silenciosa do cache quando novos dados chegam
  • Deduplicação de revalidações simultâneas
  • Ideal para caches de API com revalidação automática

Exemplo:

import { SWRCache } from 'cachemind';

const cache = new SWRCache<string>({ defaultTTL: 3600000 });

// Configurar item com função de fetch
await cache.setWithFetch('user:1', 'initial value', {
  ttl: 3600000,
  fetch: async () => {
    const response = await fetch('/api/user/1');
    return response.json().name;
  }
});

// Primeira vez: retorna valor imediatamente
const user = cache.get('user:1'); // 'initial value'

// Após expirar: retorna valor stale e revalida em background
// (o valor stale é retornado imediatamente, enquanto a revalidação acontece)
const staleUser = cache.get('user:1'); // 'initial value' (stale, mas retornado)
// Em background: fetch é chamado e cache é atualizado silenciosamente

LRUCache (RF05) ✅

Estratégia Least Recently Used (LRU) que remove o item menos recentemente usado quando a capacidade máxima é atingida.

Características:

  • Capacidade máxima configurável
  • Remove automaticamente o item menos recentemente usado quando atinge capacidade
  • Ordem de uso atualizada a cada acesso (leitura ou escrita)
  • Ideal para caches com limite de memória

Exemplo:

const cache = new LRUCache<string>({ maxSize: 3 });

// Preenche cache até capacidade máxima
cache.set('key1', 'value1');
cache.set('key2', 'value2');
cache.set('key3', 'value3');

// Acessa key1 (torna-se mais recentemente usado)
cache.get('key1');

// Adiciona novo item - key2 é removido (menos recentemente usado)
cache.set('key4', 'value4');
// key2 não está mais no cache

DTTCache (RF06) ✅

Estratégia Dynamic TTL (TTL Dinâmico) que calcula TTL dinamicamente com base em metadados da resposta.

Características:

  • TTL calculado dinamicamente com base em metadados (headers HTTP, propriedades do dado)
  • Suporte para headers HTTP (Cache-Control, Expires)
  • Suporte para cálculo baseado em propriedades do dado
  • Fallback para TTL estático se função não calcular TTL
  • Ideal para caches de API que respeitam headers HTTP

Exemplo:

const cache = new DTTCache<string>();

// TTL baseado em Cache-Control header
await cache.setWithDynamicTTL('api:data', 'response data', {
  ttlCalculator: (value, metadata) => {
    const cacheControl = metadata?.headers?.['cache-control'];
    if (cacheControl) {
      const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
      if (maxAgeMatch) {
        return parseInt(maxAgeMatch[1], 10) * 1000;
      }
    }
    return 3600000; // Fallback
  },
  metadata: {
    headers: { 'cache-control': 'max-age=300' },
  },
});

🔄 Roadmap

  • [x] Estratégia TTL (Time-To-Live) - ✅ Implementado
  • [x] Estratégia SWR (Stale-While-Revalidate) - ✅ Implementado
  • [x] Estratégia LRU (Least Recently Used) - ✅ Implementado
  • [x] Estratégia DTTC (Dynamic TTL) - ✅ Implementado
  • [ ] Estratégia FIFO (First In First Out)
  • [ ] Estratégia LFU (Least Frequently Used)
  • [ ] Cache em disco (persistência)
  • [ ] Cache distribuído (Redis adapter)
  • [ ] Métricas e estatísticas de cache

📄 Licença

MIT

🤝 Contribuindo

Contribuições são bem-vindas! Por favor, abra uma issue ou pull request.


Desenvolvido com foco em performance, modularidade e simplicidade.