Pular para o conteúdo
⚛ QUICKSTART

React + Vite + SuperDB.

SPA com sessão no localStorage que se renova sozinha, login e dados protegidos por RLS. Comece pelo template oficial, ou siga o passo a passo.

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.

terminal
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.

terminal
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.

.env
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.

superdb/schema.sql
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.

src/superdb.ts
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.

src/App.tsx
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.

src/Tarefas.tsx
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ó.

terminal
npm run dev
# → http://localhost:5173

Próximos passos

Essa página ajudou?