zapo persiste tudo o que uma sessão precisa para sobreviver a um reinício: credenciais de pareamento, estado do protocolo Signal, coleções de app-state e, opcionalmente, seu arquivo de mensagens/threads/contatos. Você constrói uma com createStore e a passa para o client.
O modelo
OcreateStore separa backends (onde os dados ficam) de providers (qual backend cada domínio usa). Isso permite misturar backends — por exemplo, manter o estado quente do signal no Redis enquanto arquiva mensagens no Postgres.
Providers são obrigatórios quando você define backends
Assim que backends contém ao menos uma entrada, todo domínio de persistência precisa ser atribuído explicitamente em providers. Os domínios obrigatórios são auth, signal, preKey, session, identity, senderKey, appState, privacyToken, messages, threads e contacts. Tanto os tipos TypeScript quanto uma verificação em tempo de execução garantem isso — createStore lança um erro listando as chaves providers.* faltantes quando alguma é omitida.
Três valores são válidos para cada domínio:
- Um nome de backend de
backends(por exemplo'sqlite') — persiste esse domínio ali. 'memory'— mantém esse domínio no provider de memória embutido nesta execução.'none'— válido apenas para os domínios de arquivo opcionais (messages,threads,contacts); ignora o domínio por completo.
auth e deixa o estado do Signal, o app-state ou a caixa de mensagens recairem para a memória, o dispositivo pareia uma vez e depois perde o estado de protocolo a cada reinício. Escolha 'memory' de forma deliberada quando for esse o seu objetivo.
backends está vazio ou ausente, cada domínio recai para a memória (e os domínios de mailbox para 'none') — útil para testes, mas o dispositivo se re-pareia a cada reinício.
Domínios persistidos
Estes mantêm o estado necessário para manter uma sessão viva. Apoie-os com um backend durável em produção.Domínios de arquivo opcionais
Estes aceitam'none' para desabilitar a persistência por completo:
Domínios de cache
Configurados emcacheProviders e usam por padrão memória limitada com TTLs:
memory faz sweep in-process, Redis e MongoDB usam TTL nativo, SQLite filtra na leitura, e PostgreSQL/MySQL exigem um poller opt-in (result.startCleanup(sessionId)) ou as tabelas de cache crescem sem parar. Veja Expiração e limpeza de cache para a matriz por backend.
Camada de cache read-through
Quando um domínio quente do signal aponta para um backend persistente, cada ida e volta de envio/recebimento paga a latência do backend para buscar a sessão, identidade ou sender key do mesmo peer. A opçãocacheLayer envolve a store do backend com um L1 LRU limitado (o provider de memória nativo) para que leituras repetidas do mesmo peer pulem o backend, enquanto escritas continuam write-through e o backend permanece como fonte de verdade.
Quatro domínios quentes podem ser cacheados:
Todos os flags têm padrão
false. Um flag é no-op a menos que aquele domínio resolva para um backend real em providers — cachear 'memory' ou 'none' na frente de si mesmo não traz ganho e é ignorado.
limits define o limite de entradas por domínio; quando excedido, o L1 faz despejo LRU. Sem definir, cada domínio usa o limite padrão do provider de memória correspondente.
Quando habilitar
Habilite quando seu backend é uma chamada de rede (Redis, Postgres, MySQL, MongoDB) e você envia ou recebe a uma taxa em que os mesmos peers se repetem — típico de bots, fan-out em grupos e gateways multi-tenant. Com um backend SQLite local os ganhos são menores; meça antes de ativar.Premissa de escritor único
O L1 é por processo e não tem canal de invalidação entre processos. HabilitecacheLayer apenas quando um único processo é dono das linhas de backend de um dado sessionId — o modelo de conexão padrão da biblioteca. Sessões diferentes compartilhando um backend é OK; a mesma sessão aberta em dois processos não é.
Por que não todos os domínios?
signal, appState e preKey são deliberadamente excluídos:
signal— a leitura de registro por envio já é memoizada dentro do lock do signal; um segundo cache não adiciona nada.appState— o cliente de sync já cacheia o estado das coleções pela vida do contexto de sync, o único escopo em que as leituras se repetem e permanecem coerentes.preKey— pre-keys de uso único são lidas exatamente uma vez e consumidas. Servir uma chave já consumida a partir de um cache desatualizado a reutilizaria e quebraria a forward secrecy.
Backends
SQLite
@zapo-js/store-sqlite — local, processo único.PostgreSQL
@zapo-js/store-postgres — distribuído, relacional.MySQL
@zapo-js/store-mysql — distribuído, relacional.Redis
@zapo-js/store-redis — cache + persistência.MongoDB
@zapo-js/store-mongo — document store.Memory
Embutido. Ótimo para testes; não sobrevive a um reinício.
Apenas memória (testes)
Para experimentos rápidos ou testes, omitabackends por completo — cada domínio recorre à memória:
