Documentation 13 min read

Easy Storage Manager

Published: April 21, 2025

Introdução

O Easy Storage Manager é uma biblioteca JavaScript abrangente projetada para simplificar o gerenciamento de armazenamento no navegador. Ele oferece uma interface unificada para diferentes tipos de armazenamento, incluindo localStorage, sessionStorage, IndexedDB, e cookies. Além disso, o Easy Storage Manager incorpora funcionalidades avançadas como compressão de dados usando um algoritmo baseado em LZW e criptografia segura utilizando a Web Crypto API (AES-GCM com PBKDF2).

Principais funcionalidades do Easy Storage Manager:

  • Suporte para múltiplos backends de armazenamento (localStorage, sessionStorage, IndexedDB, cookies, e um fallback em memória).
  • Compressão de dados opcional para otimizar o uso de armazenamento (aplicável a IndexedDB e Cookies).
  • Criptografia de dados opcional (AES-GCM) para garantir a segurança das informações armazenadas (aplicável a IndexedDB).
  • Interface totalmente assíncrona (baseada em Promises) para melhor desempenho e compatibilidade.
  • Sistema de eventos para monitorar operações como set, get, remove, clear, e update.
  • Operações utilitárias como incrementos, decrementos, manipulação de listas (push, pop), e iteração (each).
  • Sincronização entre instâncias, exportação e importação de dados.
  • Facilidade de integração e configuração flexível através de um objeto de opções.
  • Interface de gerenciamento visual (modal) opcional, acessível via tecla F2, para depuração, visualização e manipulação de dados em tempo real.

Características Principais

  • Suporte Multi-Armazenamento: Interface unificada para localStorage, sessionStorage, IndexedDB, e cookies.
  • Compressão de Dados: Utiliza um algoritmo LZW para comprimir dados antes do armazenamento em IndexedDB (com ou sem criptografia) e Cookies, reduzindo o espaço utilizado. Deve ser habilitada via opções.
  • Criptografia Segura: Implementa criptografia AES-GCM com PBKDF2 (SHA-256) via Web Crypto API para proteger dados em IndexedDB. Cookies não suportam criptografia.
  • Interface Assíncrona: Todos os métodos retornam Promises, garantindo operações não bloqueantes.
  • Eventos Personalizados: Permite escutar eventos como set, remove, update, clear e storageTypeChange.
  • Operações Avançadas: Suporte para increment, decrement, manipulação de listas (push, pop), iteração (each), e sincronização (sync).
  • Configuração Flexível: Permite personalizar namespaces, tipo de armazenamento padrão, opções de criptografia, e configurações específicas para IndexedDB e Cookies.
  • Exportação e Importação: Métodos export (para objeto) e import (de objeto) para migração e backup.
  • Interface de Gerenciamento Visual: Um modal de depuração opcional (ativado por modalEnabled: true ou enableModal(true)) acessível via F2 para visualizar, editar, gerenciar dados e ver analytics.

Instalação

Para usar o Easy Storage Manager, siga os passos abaixo:

1. Inclua o Script

Adicione o script JavaScript no seu HTML, preferencialmente antes do fechamento da tag </body>:

<script src="https://cdn.alphasystem.dev/plugins/easy-storage-manager/latest/script-min.js"></script>

2. Inicialize a Biblioteca

O Easy Storage Manager não inicializa automaticamente. Você precisa criar uma instância da classe StorageManager, passando um objeto de opções.

Inicialização Básica:

// Inicializa o Easy Storage Manager
const storage = new StorageManager({
  namespace: 'myApp', // Prefixo para as chaves (recomendado)
  storageType: 'localStorage' // 'localStorage', 'sessionStorage', 'indexedDB', 'cookies'
});

// Exemplo de uso após inicialização
async function saveData() {
  try {
    await storage.set('user', { id: 1, name: 'Anderson' });
    console.log('Data saved!');
    const user = await storage.get('user');
    console.log('Retrieved user:', user);
  } catch (error) {
    console.error('Storage error:', error);
  }
}

saveData();

Configuração Avançada (Exemplo):

const storage = new StorageManager({
  namespace: 'secureApp',
  storageType: 'indexedDB', // Usar IndexedDB
  encrypt: true, // Habilitar criptografia (só funciona com IndexedDB)
  cryptoPassword: 'uma_senha_muito_forte_e_secreta',
  indexedDBOptions: {
    dbName: 'SecureDatabase',
    storeName: 'encryptedData',
    dbVersion: 1
  },
  cookieOptions: { // Opções para quando storageType for 'cookies'
    path: '/',
    // domain: 'seusite.com', // Opcional
    secure: true, // Recomendado para HTTPS
    expires: 86400 // Expira em 1 dia (em segundos)
  },
  modalEnabled: true // Habilita a interface de gerenciamento (F2)
});

Nota sobre Compressão: A compressão não é uma opção global na inicialização. Ela é aplicada:

  • Automaticamente em IndexedDB quando a criptografia (encrypt: true) está habilitada.
  • Opcionalmente em IndexedDB (sem criptografia) passando { compress: true } nas opções do método setItem.
  • Opcionalmente em Cookies se compress: true for definido em cookieOptions na inicialização, ou passando { compress: true } nas opções do método setItem.
  • localStorage e sessionStorage não possuem compressão integrada pela biblioteca.

Configuração

O Easy Storage Manager é configurado através de um objeto de opções passado ao construtor new StorageManager(options). As principais opções são:

  • namespace: (String) Um prefixo para todas as chaves armazenadas, ajudando a evitar conflitos. Padrão: 'app'.
  • storageType: (String) O tipo de armazenamento padrão a ser usado. Opções: 'localStorage', 'sessionStorage', 'indexedDB', 'cookies'. Se o tipo escolhido não estiver disponível, ele tentará usar um fallback em memória. Padrão: 'localStorage'.
  • encrypt: (Boolean) Habilita a criptografia AES-GCM para os dados. Funciona apenas com storageType: 'indexedDB'. Se habilitado, a compressão também é aplicada automaticamente para IndexedDB. Padrão: false.
  • cryptoPassword: (String) A senha usada para derivar a chave de criptografia via PBKDF2. Necessária se encrypt: true. Padrão: 'default_password'.
  • cookieOptions: (Object) Opções específicas para quando storageType: 'cookies'. Contém sub-opções como:
    • namespace: (String) Usado como prefixo para nomes de cookies (sobrescreve o namespace global para cookies).
    • compress: (Boolean) Habilita compressão para cookies. Padrão: false.
    • encrypt: (Boolean) Não suportado para cookies. Definir como true causará um erro.
    • expires: (Number|Date) Tempo de expiração em segundos ou um objeto Date.
    • path: (String) Caminho do cookie. Padrão: '/'.
    • domain: (String) Domínio do cookie.
    • secure: (Boolean) Define o atributo Secure do cookie. Padrão: false.
  • indexedDBOptions: (Object) Opções específicas para quando storageType: 'indexedDB'. Contém sub-opções como:
    • dbName: (String) Nome do banco de dados IndexedDB. Padrão: 'StorageManagerDB'.
    • storeName: (String) Nome do Object Store dentro do banco. Padrão: 'keyval'.
    • dbVersion: (Number) Versão do banco de dados. Padrão: 1.
  • modalEnabled: (Boolean) Habilita a interface de gerenciamento visual (modal) acessível via tecla F2. Padrão: false.

Nota sobre Compressão (Reiterando): A compressão não é uma opção global. Veja a seção de Instalação para detalhes sobre como e quando ela é aplicada.

Exemplo de configuração personalizada:

const storage = new StorageManager({
  namespace: 'meuApp',
  storageType: 'indexedDB',
  encrypt: true, // Criptografia para IndexedDB
  cryptoPassword: 'senha_super_secreta',
  indexedDBOptions: {
    dbName: 'MeuBancoDeDados',
    storeName: 'MinhaStore',
    dbVersion: 2
  },
  cookieOptions: { // Configurações se usar 'cookies' futuramente
    path: '/app',
    secure: true,
    expires: 3600, // 1 hora
    compress: true // Habilitar compressão para cookies
  },
  modalEnabled: true // Habilitar modal de depuração (F2)
});

Uso e Integração

Após criar uma instância do StorageManager, você pode usar seus métodos assíncronos para interagir com o armazenamento.

Operações Básicas (CRUD)

async function manageData() {
  // Salvar um item (objeto)
  await storage.set('userProfile', { name: 'Alice', theme: 'dark' });

  // Salvar um item com expiração (10 minutos) e compressão (se aplicável)
  await storage.set('tempData', 'valor_temporario', {
    expire: 600000, // 10 minutos em milissegundos
    compress: true // Tenta comprimir (funciona em Cookies/IndexedDB)
  });

  // Recuperar um item
  const profile = await storage.get('userProfile');
  console.log('Profile:', profile);

  // Verificar se uma chave existe
  const hasTemp = await storage.has('tempData');
  console.log('Has tempData:', hasTemp);

  // Remover um item
  await storage.remove('tempData');

  // Limpar todos os itens do namespace atual
  // await storage.clear();
}

manageData();

Operações Numéricas e Listas

async function advancedOps() {
  // Incrementar um contador (inicia em 0 se não existir)
  const newCount = await storage.increment('pageViews', 1);
  console.log('New page view count:', newCount);

  // Decrementar
  // await storage.decrement('itemsInCart', 1);

  // Adicionar item a uma lista (cria a lista se não existir)
  await storage.push('logMessages', { timestamp: Date.now(), msg: 'User logged in' });

  // Remover e obter o último item da lista
  const lastLog = await storage.pop('logMessages');
  console.log('Last log message:', lastLog);
}

advancedOps();

Iteração, Exportação e Importação

async function dataMigration() {
  // Iterar sobre todos os itens
  await storage.each((key, value) => {
    console.log(`Iterating: ${key} =`, value);
  });

  // Exportar todos os dados do namespace para um objeto
  const allData = await storage.export();
  console.log('Exported data:', JSON.stringify(allData));

  // Importar dados de um objeto (sobrescreve existentes por padrão)
  const dataToImport = {
    settings: { lang: 'pt-BR' },
    lastVisit: new Date().toISOString()
  };
  await storage.import(dataToImport, true); // true para sobrescrever
  console.log('Data imported.');
}

dataMigration();

Eventos

// Escutar evento 'set'
storage.on('set', (key, value) => {
  console.log(`Event: Key '${key}' was set/updated.`);
});

// Escutar evento 'remove'
storage.on('remove', (key) => {
  console.log(`Event: Key '${key}' was removed.`);
});

// Escutar evento 'clear'
storage.on('clear', () => {
  console.log('Event: Storage was cleared.');
});

// Escutar evento 'storageTypeChange'
storage.on('storageTypeChange', (newType) => {
  console.log(`Event: Storage type changed to ${newType}.`);
});

// Remover um listener específico
// storage.removeListener('set', yourListenerFunction);

Outras Utilidades

async function utilities() {
  // Obter número de chaves no namespace
  const count = await storage.length();
  console.log('Number of keys:', count);

  // Obter uso de armazenamento (aproximado em bytes)
  const usageBytes = await storage.getUsage();
  console.log('Storage usage:', storage.formatBytes(usageBytes));

  // Mudar o tipo de armazenamento em tempo de execução
  // await storage.setStorageType('sessionStorage');

  // Habilitar/Desabilitar o modal de depuração programaticamente
  // storage.enableModal(true); // Habilita
  // storage.enableModal(false); // Desabilita
}

utilities();

Interface de Gerenciamento (Modal)

Se modalEnabled: true foi passado na configuração ou storage.enableModal(true) foi chamado, pressione a tecla F2 para abrir a interface. Pressione F2 ou Esc para fechar.

O modal permite:

  • Visualizar dados em localStorage, sessionStorage, cookies, e IndexedDB (selecionando DB/Store).
  • Filtrar chaves por nome.
  • Adicionar novas entradas chave-valor.
  • Editar valores existentes (incluindo JSON e booleanos).
  • Excluir entradas individuais.
  • Visualizar estatísticas de uso (Analytics), como número de operações, bytes usados, e última operação.

Referência da API

Construtor

  • new StorageManager(options?): Cria uma nova instância do gerenciador de armazenamento.
    Parâmetros:
    - options (Object, opcional): Objeto de configuração (veja a seção 'Configuração').
    Retorna: Instância de StorageManager.

Métodos Principais (Assíncronos)

  • set(key, value, options?): Salva um item.
    Parâmetros:
    - key (String): Chave.
    - value (Any): Valor (será JSON stringified internamente).
    - options (Object, opcional): Opções como expire (Number, ms), compress (Boolean, para Cookies/IndexedDB).
    Retorna: Promise<void>.
  • get(key): Recupera um item.
    Parâmetros:
    - key (String): Chave.
    Retorna: Promise<any | null> (valor parseado ou null se não encontrado/expirado).
  • remove(key): Remove um item.
    Parâmetros:
    - key (String): Chave.
    Retorna: Promise<void>.
  • clear(): Limpa todos os itens do namespace atual.
    Retorna: Promise<void>.
  • keys(): Lista todas as chaves no namespace.
    Retorna: Promise<string[]>.
  • has(key): Verifica se uma chave existe e não está expirada.
    Parâmetros:
    - key (String): Chave.
    Retorna: Promise<boolean>.
  • increment(key, by?): Incrementa um valor numérico.
    Parâmetros:
    - key (String): Chave.
    - by (Number, opcional): Valor a incrementar. Padrão: 1.
    Retorna: Promise<number> (novo valor).
  • decrement(key, by?): Decrementa um valor numérico.
    Parâmetros:
    - key (String): Chave.
    - by (Number, opcional): Valor a decrementar. Padrão: 1.
    Retorna: Promise<number> (novo valor).
  • push(key, value): Adiciona um valor ao final de uma lista (array).
    Parâmetros:
    - key (String): Chave da lista.
    - value (Any): Valor a adicionar.
    Retorna: Promise<void>.
  • pop(key): Remove e retorna o último valor de uma lista.
    Parâmetros:
    - key (String): Chave da lista.
    Retorna: Promise<any | null> (valor removido ou null se vazia/não for array).
  • each(callback): Itera sobre todos os pares chave-valor no namespace.
    Parâmetros:
    - callback (Function): Função (key, value) => void chamada para cada item.
    Retorna: Promise<void>.
  • export(): Exporta todos os dados do namespace como um objeto.
    Retorna: Promise<Object>.
  • import(data, overwrite?): Importa dados de um objeto.
    Parâmetros:
    - data (Object): Objeto com pares chave-valor.
    - overwrite (Boolean, opcional): Se true, sobrescreve chaves existentes. Padrão: true.
    Retorna: Promise<void>.
  • sync(otherStorageManager): Importa dados de outra instância StorageManager.
    Parâmetros:
    - otherStorageManager (StorageManager): A instância de origem.
    Retorna: Promise<void>.
  • length(): Obtém o número de itens no namespace.
    Retorna: Promise<number>.
  • setStorageType(type, options?): Altera o tipo de armazenamento em tempo de execução.
    Parâmetros:
    - type (String): Novo tipo ('localStorage', 'sessionStorage', 'indexedDB', 'cookies').
    - options (Object, opcional): Novas opções para o tipo (ex: cookieOptions, indexedDBOptions).
    Retorna: Promise<void>.
  • getUsage(): Obtém o uso aproximado de armazenamento em bytes.
    Retorna: Promise<number>.

Métodos Síncronos

  • formatBytes(bytes, decimals?): Formata bytes em string legível (KB, MB, etc.).
    Parâmetros:
    - bytes (Number): Número de bytes.
    - decimals (Number, opcional): Casas decimais. Padrão: 2.
    Retorna: string.
  • enableModal(enable): Habilita ou desabilita o modal de depuração.
    Parâmetros:
    - enable (Boolean): true para habilitar, false para desabilitar.
    Retorna: void.
  • on(event, listener): Adiciona um listener de evento.
    Parâmetros:
    - event (String): Nome do evento.
    - listener (Function): Callback.
    Retorna: void.
  • removeListener(event, listener): Remove um listener.
    Parâmetros:
    - event (String): Nome do evento.
    - listener (Function): Callback a remover.
    Retorna: void.
  • once(event, listener): Adiciona um listener que executa apenas uma vez.
    Parâmetros:
    - event (String): Nome do evento.
    - listener (Function): Callback.
    Retorna: void.
  • emit(event, ...args): Dispara um evento manualmente (uso interno principalmente).
    Retorna: void.

Eventos Disponíveis (via on, once)

  • 'set': Disparado após set. Callback recebe (key, value).
  • 'remove': Disparado após remove ou expiração no get. Callback recebe (key).
  • 'clear': Disparado após clear. Callback não recebe argumentos.
  • 'update': Disparado quando um valor é alterado por outra aba/janela (via evento storage nativo). Callback recebe (key, newValue).
  • 'storageTypeChange': Disparado após setStorageType. Callback recebe (newType).

Propriedades

  • namespace (String): O namespace atual.
  • storageType (String): O tipo de armazenamento atual.
  • analytics (Object): Contém estatísticas de uso (setOperations, getOperations, removeOperations, clearOperations, totalBytesUsed, lastOperation).

Resolução de Problemas

Enfrentando problemas com o Easy Storage Manager? Aqui estão algumas soluções comuns:

  • StorageManager is not defined: Verifique se o script foi incluído corretamente no HTML antes de tentar usar new StorageManager(...).
  • Métodos não funcionam / Erros de Promise: Certifique-se de estar usando await ou .then() com os métodos assíncronos (set, get, remove, etc.). A inicialização também é assíncrona; a instância está totalmente pronta após o initPromise interno resolver.
  • Erros de Criptografia (IndexedDB): Verifique se a senha (cryptoPassword) está correta e consistente. A Web Crypto API requer um contexto seguro (HTTPS, localhost). Verifique o console do navegador por erros relacionados a SubtleCrypto.
  • Erro CookieStorage does not support encryption: Você tentou usar encrypt: true ou passou { encrypt: true } para setItem com storageType: 'cookies'. Remova a opção de criptografia para cookies.
  • Dados Não São Salvos/Recuperados: Verifique se o namespace está correto. Verifique os limites de armazenamento do navegador (especialmente para localStorage e cookies). Verifique se há erros no console. Se usando expiração (expire), certifique-se de que o item não expirou.
  • Compressão Não Funciona: Lembre-se que a compressão só é aplicável a IndexedDB e Cookies e precisa ser habilitada corretamente (veja seções de Instalação/Configuração). Não se aplica a localStorage/sessionStorage.
  • Eventos Não São Disparados: Confirme que os listeners foram adicionados corretamente com storage.on(...) após a criação da instância. O evento update depende do evento storage nativo, que tem limitações (geralmente não dispara na mesma aba que fez a alteração).
  • Modal (F2) Não Abre: Verifique se modalEnabled: true foi passado na configuração ou se storage.enableModal(true) foi chamado. Verifique se há conflitos de teclas de atalho. Verifique o console por erros durante a inicialização do modal.
  • Problemas com IndexedDB: Erros podem ocorrer se a versão do banco (dbVersion) mudar ou se houver problemas ao abrir/criar o banco/store. Verifique o console por erros específicos de IndexedDB.

Se o problema persistir, verifique o console de desenvolvedor do navegador para mensagens de erro detalhadas e considere abrir uma issue no repositório do projeto (se disponível) ou contatar o suporte.

Exemplos de Código

Abaixo, exemplos práticos de uso do Easy Storage Manager:

Exemplo Básico (localStorage)

// 1. Inicialização
const storageLocal = new StorageManager({
  namespace: 'meuAppLocal',
  storageType: 'localStorage'
});

// 2. Uso
async function demoLocal() {
  await storageLocal.set('username', 'Alice');
  const user = await storageLocal.get('username');
  console.log(`Usuário (localStorage): ${user}`);
}
demoLocal();

Exemplo com IndexedDB e Criptografia

// 1. Inicialização
const storageSecure = new StorageManager({
  namespace: 'appSegura',
  storageType: 'indexedDB',
  encrypt: true,
  cryptoPassword: 'senha_ultra_secreta_123',
  indexedDBOptions: { dbName: 'DadosAppSeguro' }
});

// 2. Uso
async function demoSecure() {
  await storageSecure.set('apiKey', 'xyz789-abc123-def456');
  const key = await storageSecure.get('apiKey');
  console.log(`API Key (IndexedDB Criptografado): ${key}`);
}
demoSecure();

Exemplo com Cookies, Compressão e Expiração

// 1. Inicialização
const storageCookie = new StorageManager({
  namespace: 'cookieApp',
  storageType: 'cookies',
  cookieOptions: {
    compress: true, // Habilitar compressão padrão para cookies
    expires: 3600, // Expiração padrão de 1 hora
    secure: true
  }
});

// 2. Uso
async function demoCookie() {
  // Salva com compressão e expiração padrão (1h)
  await storageCookie.set('sessionData', { userId: 123, role: 'admin' });

  // Salva outro cookie com expiração diferente (1 dia), sem compressão
  await storageCookie.set('prefs', { theme: 'light' }, {
    expires: 86400, // Sobrescreve expiração para 1 dia
    compress: false // Sobrescreve compressão para false
  });

  const session = await storageCookie.get('sessionData');
  console.log('Session (Cookie Comprimido):', session);
}
demoCookie();

Manipulando Listas e Números

async function demoListsNumbers() {
  // Usando a instância 'storageLocal' do primeiro exemplo

  // Adicionar itens a um log
  await storageLocal.push('activityLog', 'Login');
  await storageLocal.push('activityLog', 'Viewed Dashboard');

  // Incrementar contador
  const visits = await storageLocal.increment('siteVisits');
  console.log(`Total de visitas: ${visits}`);

  // Obter o log (será um array)
  const log = await storageLocal.get('activityLog');
  console.log('Activity Log:', log);
}
demoListsNumbers();

Exportando e Importando Dados

async function demoExportImport() {
  // Usando a instância 'storageLocal'
  await storageLocal.set('config', { lang: 'en', notifications: true });

  // Exportar
  const exportedData = await storageLocal.export();
  console.log('Dados Exportados:', JSON.stringify(exportedData));

  // Limpar para simular importação em outro lugar/tempo
  // await storageLocal.clear();

  // Importar
  const dataToImport = { userPref: 'dark_mode', lastSync: '2023-10-27' };
  await storageLocal.import(dataToImport);
  console.log('Dados importados.');

  const pref = await storageLocal.get('userPref');
  console.log(`Preferência importada: ${pref}`);
}
demoExportImport();

Habilitando o Modal de Depuração

// Habilitar via configuração inicial:
const storageWithModal = new StorageManager({
  namespace: 'debugApp',
  modalEnabled: true
});

// Ou habilitar/desabilitar programaticamente:
// storageWithModal.enableModal(true); // Habilita
// Pressione F2 para abrir/fechar

// storageWithModal.enableModal(false); // Desabilita