O caminho mais rápido: o template oficial
O template react já vem com tudo desta página funcionando: login e cadastro, sessão que se renova sozinha e uma lista de tarefas protegida por RLS. Ele é compilado a cada mudança contra a versão publicada do SDK.
npx degit superdb-br/templates/react meu-app
cd meu-app
npm install
cp .env.example .env
npm run dev
Preencha o .env com os dados do painel (projeto → Conectar), rode o arquivo superdb/schema.sql do template no SQL Editor e abra http://localhost:5173. A tela inicial confere a conexão e diz exatamente o que falta.
Há templates para sete stacks: Next.js, React, Vue, SvelteKit, Nuxt, HTML puro e Expo. O mesmo app em todos.
Passo a passo (o que o template faz por você)
1Criar o app e instalar o SDK
O @superdb/client segue a API do supabase-js: .auth, .from(), .rpc() e .storage.
npm create vite@latest meu-app -- --template react-ts
cd meu-app
npm install @superdb/client
2Variáveis de ambiente
No Vite, o que o navegador enxerga precisa do prefixo VITE_. Os três dados vêm do painel: projeto → Conectar.
A chave anon é pública: vai no código do app. Quem protege os dados é o RLS. A service key nunca vai num app.
VITE_SUPERDB_URL=https://auth.superdb.com.br
VITE_SUPERDB_ANON_KEY=cole-a-chave-anon-aqui
VITE_SUPERDB_PROJECT=slug-do-projeto
3Criar a tabela com RLS
No SQL Editor do projeto. Toda tabela nova no SuperDB nasce fechada (RLS ligado, nenhuma policy): sem as últimas linhas, a lista volta sempre vazia. Elas abrem para cada pessoa só as próprias tarefas.
create table if not exists tarefas (
id uuid primary key default gen_random_uuid(),
titulo text not null check (char_length(btrim(titulo)) between 1 and 200),
feita boolean not null default false,
criada_em timestamptz not null default now(),
user_id uuid not null default auth.uid()
);
-- A lista do app sempre busca "as minhas, das mais novas para as mais antigas".
create index if not exists tarefas_por_dono on tarefas (user_id, criada_em desc);
alter table tarefas enable row level security;
-- Uma regra só, para ler, criar, alterar e apagar: a linha é sua ou não existe.
-- "using" filtra o que você vê; "with check" recusa gravar linha de outra pessoa.
drop policy if exists tarefas_do_dono on tarefas;
create policy tarefas_do_dono on tarefas
for all to authenticated
using (user_id = auth.uid())
with check (user_id = auth.uid());
revoke all on tarefas from anon;
grant select, insert, update, delete on tarefas to authenticated;
4O cliente, com a sessão que se renova
O token do login vale 1 hora. Desde a versão 0.3, o SDK renova sozinho antes de vencer e tem onAuthStateChange. O template usa o sessao.ts, que nasceu quando o SDK ainda não renovava. Ele continua funcionando e também avisa as outras abas de cada login e saída.
Copie do template os arquivos sessao.ts e erros.ts para src/lib/superdb/. O criarSuperDB renova o token antes de vencer, faz uma renovação só mesmo com várias abas abertas (o SuperDB derruba a sessão se o mesmo refresh token for usado duas vezes) e dá a você entrar, criarConta, sair, sessao e aoMudar.
import { criarSuperDB } from './lib/superdb/sessao'
export const app = criarSuperDB({
url: import.meta.env.VITE_SUPERDB_URL,
anonKey: import.meta.env.VITE_SUPERDB_ANON_KEY,
projeto: import.meta.env.VITE_SUPERDB_PROJECT, // obrigatório: é o schema do seu projeto
})
export const superdb = app.superdb
5Mostrar login ou app, e reagir à sessão
app.sessao() devolve a sessão guardada (já renovada, se estava vencendo). app.aoMudar() avisa a cada login, saída ou renovação, inclusive em outra aba.
import { useEffect, useState } from 'react'
import type { Session } from '@superdb/client'
import { app } from './superdb'
export default function App() {
const [sessao, setSessao] = useState<Session | null>(null)
useEffect(() => {
app.sessao().then(setSessao)
return app.aoMudar(setSessao) // devolve a função que cancela
}, [])
return sessao ? <Tarefas /> : <Entrar />
}
function Entrar() {
async function enviar(form: FormData) {
await app.entrar(String(form.get('email')), String(form.get('senha')))
}
return (
<form action={enviar}>
<input name="email" type="email" required />
<input name="senha" type="password" minLength={8} required />
<button>Entrar</button>
</form>
)
}
6Ler e gravar dados
Nenhum filtro por usuário e nenhum user_id: o RLS devolve só as linhas de quem está logado, e o banco preenche o dono no insert.
import { useEffect, useState } from 'react'
import { superdb } from './superdb'
type Tarefa = { id: string; titulo: string; feita: boolean }
export function Tarefas() {
const [tarefas, setTarefas] = useState<Tarefa[]>([])
useEffect(() => {
superdb
.from('tarefas')
.select('id,titulo,feita')
.order('criada_em', { ascending: false })
.then(({ data }) => setTarefas((data as Tarefa[]) ?? []))
}, [])
async function criar(titulo: string) {
const { data } = await superdb.from('tarefas').insert({ titulo }).select('id,titulo,feita').single()
if (data) setTarefas((t) => [data as Tarefa, ...t])
}
// ...
}
7Rodar
Crie uma conta e adicione tarefas. Abra o app em duas abas: sair numa tira as duas, e a renovação acontece uma vez só.
npm run dev
# → http://localhost:5173
Próximos passos
- O template completo, com o README explicando cada arquivo
- Row Level Security: policies para cada caso
- Precisa de SSR? Quickstart Next.js (sessão em cookies)
- Referência do SDK