Pular para o conteúdo
🔌 GUIA UNIVERSAL

SuperDB com qualquer framework.

Um cliente só para todos: o que muda é onde a sessão fica guardada. No navegador para SPA, em cookies httpOnly para renderização no servidor.

O princípio: um cliente, um lugar para guardar a sessão

O @superdb/client roda em qualquer lugar com JavaScript e fetch: navegador, Node, Bun, Deno, edge, React Native. Ele não tem versões por framework. O que muda de um framework para outro é só onde a sessão fica guardada, e isso é um parâmetro do cliente:

qualquer framework
import { createClient } from '@superdb/client'

const superdb = createClient(URL_DE_AUTH, ANON_KEY, {
  project: 'slug-do-projeto',  // obrigatório: é o schema dos seus dados
  storage: armazenamento,      // opcional: { getItem, setItem, removeItem }
})
  • Sem storage, a sessão vai para o localStorage no navegador e para a memória no servidor.
  • App que roda só no navegador (SPA): o padrão serve. Use o sessao.ts dos templates para a renovação.
  • App com renderização no servidor: passe um armazenamento feito de cookies, e crie um cliente por requisição.
💡

Há templates prontos para SvelteKit, Nuxt e HTML puro, além de Next.js, React, Vue e Expo. Todos em github.com/superdb-br/templates.

SPA: a sessão no navegador

O SDK guarda a sessão e, desde a versão 0.3, renova sozinho antes de o token (1 hora) vencer. Para reagir a login e saída, use db.auth.onAuthStateChange. O sessao.ts dos templates, o mesmo arquivo em todos e sem dependência de framework, também avisa as outras abas.

src/superdb.ts (Solid, Qwik no modo SPA, Astro com ilhas client:only, Preact...)
import { criarSuperDB } from './lib/superdb/sessao'

export const app = criarSuperDB({ url: URL_DE_AUTH, anonKey: ANON_KEY, projeto: 'slug-do-projeto' })
export const superdb = app.superdb

// app.entrar(email, senha) · app.criarConta(email, senha) · app.sair()
// app.sessao()   → a sessão atual, renovada se estiver vencendo
// app.aoMudar(fn) → avisa a cada login, saída ou renovação (também de outras abas)

Com renderização no servidor: a sessão em cookies

No servidor não há localStorage, mas os cookies chegam em toda requisição. O armazenamento abaixo guarda a sessão em quatro cookies httpOnly (a sessão inteira em um cookie passaria de 4 KB). É o mesmo do template Next.js, onde está testado; aqui ele recebe três funções, para servir a qualquer framework.

lib/superdb-cookies.ts
type Pote = {
  ler(nome: string): string | undefined
  gravar(nome: string, valor: string): void
  apagar(nome: string): void
}

const COOKIES = { acesso: 'sdb-acesso', renovacao: 'sdb-renovacao', dados: 'sdb-dados', vence: 'sdb-vence' }

export function armazenamentoEmCookies(pote: Pote) {
  return {
    getItem(chave: string) {
      if (chave !== 'superdb.auth.session') return null
      const acesso = pote.ler(COOKIES.acesso), renovacao = pote.ler(COOKIES.renovacao)
      if (!acesso || !renovacao) return null
      const vence = Number(pote.ler(COOKIES.vence)) || 0
      return JSON.stringify({
        access_token: acesso, refresh_token: renovacao,
        data_plane_token: pote.ler(COOKIES.dados) || null,
        expires_at: vence, expires_in: Math.max(0, Math.round((vence - Date.now()) / 1000)),
        token_type: 'bearer', user: null,
      })
    },
    setItem(chave: string, valor: string) {
      if (chave !== 'superdb.auth.session') return
      const s = JSON.parse(valor)
      pote.gravar(COOKIES.acesso, s.access_token)
      pote.gravar(COOKIES.renovacao, s.refresh_token)
      pote.gravar(COOKIES.dados, s.data_plane_token ?? '')
      pote.gravar(COOKIES.vence, String(s.expires_at))
    },
    removeItem(chave: string) {
      if (chave === 'superdb.auth.session') Object.values(COOKIES).forEach((n) => pote.apagar(n))
    },
  }
}

Em cada framework, o pote é a API de cookies da requisição. Use sempre httpOnly, sameSite: 'lax', path: '/' e secure em produção:

FrameworkOnde criar o clienteler / gravar / apagar
Astromiddleware (onRequest) e páginascontext.cookies.get(n)?.value · .set(n, v, opções) · .delete(n, { path: '/' })
SvelteKithooks.server.ts (handle), +page.server.tsevent.cookies.get(n) · .set(n, v, { path: '/', ...opções }) · .delete(n, { path: '/' })
Nuxt (servidor)server/middleware, server/apigetCookie(event, n) · setCookie(event, n, v, opções) · deleteCookie(event, n)
Qwik CityrouteLoader$, routeAction$, onRequestrequestEv.cookie.get(n)?.value · .set(n, v, opções) · .delete(n, { path: '/' })
Solid Startfunções "use server"getCookie(n) · setCookie(n, v, opções) · deleteCookie(n) (de vinxi/http)
⚠️

Crie o cliente dentro da requisição (no hook, na action, no loader). Um cliente numa variável de módulo seria compartilhado entre visitantes no servidor.

Renovar a sessão sem derrubá-la

O token vale 1 hora. Renove no ponto por onde toda requisição passa (o middleware ou hook do framework) quando faltar menos de 1 minuto, chamando superdb.auth.refreshSession() com o cliente de cookies: o SDK grava os tokens novos pelo armazenamento.

O cuidado: o SuperDB troca o refresh token a cada renovação e trata o uso de um token já trocado como roubo, derrubando a sessão. Várias requisições simultâneas do mesmo navegador chegam com o mesmo cookie. Faça uma renovação por refresh token, e entregue a sessão já renovada a quem chegar logo depois com o token antigo. O renovar.ts do template Next faz exatamente isso em 60 linhas, e serve de modelo para qualquer middleware.

Dados: igual em todo lugar

qualquer framework
const { data, error } = await superdb
  .from('tarefas')
  .select('id,titulo,feita')
  .order('criada_em', { ascending: false })

Com a tabela protegida por RLS (veja o schema.sql dos templates), a consulta devolve só as linhas de quem está logado, sem filtro nenhum no código.

Próximos passos

Essa página ajudou?