Pular para o conteúdo
📱 QUICKSTART

Expo + SuperDB.

App de celular com sessão que sobrevive a fechar o app, se renova sozinha, 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 expo 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/expo meu-app
cd meu-app
npm install
cp .env.example .env
npx expo start

Preencha o .env com os dados do painel (projeto → Conectar), rode o arquivo superdb/schema.sql do template no SQL Editor e abra o app no Expo Go ou no simulador. 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 @superdb/client segue a API do supabase-js. O AsyncStorage guarda a sessão entre uma abertura do app e outra.

terminal
npx create-expo-app@latest meu-app --template blank-typescript
cd meu-app
npx expo install @react-native-async-storage/async-storage
npm install @superdb/client

2Variáveis de ambiente

No Expo, o que vai para dentro do app precisa do prefixo EXPO_PUBLIC_. Depois de mudar o .env, reinicie o npx expo start.

⚠️

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
EXPO_PUBLIC_SUPERDB_URL=https://auth.superdb.com.br
EXPO_PUBLIC_SUPERDB_ANON_KEY=cole-a-chave-anon-aqui
EXPO_PUBLIC_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 AsyncStorage from '@react-native-async-storage/async-storage'
import { criarSuperDB } from './lib/superdb/sessao'

export const app = criarSuperDB({
  url: process.env.EXPO_PUBLIC_SUPERDB_URL!,
  anonKey: process.env.EXPO_PUBLIC_SUPERDB_ANON_KEY!,
  projeto: process.env.EXPO_PUBLIC_SUPERDB_PROJECT!, // obrigatório
  armazenamento: AsyncStorage, // no celular não existe localStorage
})

export const superdb = app.superdb
ℹ️

Por que AsyncStorage e não SecureStore? A sessão tem três tokens e passa de 2 KB, o limite do SecureStore em algumas plataformas. Os tokens duram pouco (1 hora) e a renovação troca o refresh token a cada uso.

5Login, sessão e dados

app.sessao() devolve a sessão guardada (já renovada, se estava vencendo); app.aoMudar() avisa a cada login e saída. Nos campos de e-mail, desligue a correção automática: o iOS troca palavras do e-mail.

src/App.tsx
import { useEffect, useState } from 'react'
import { Text, TextInput, Pressable, View } from 'react-native'
import type { Session } from '@superdb/client'
import { app, superdb } from './superdb'

export default function App() {
  const [sessao, setSessao] = useState<Session | null>(null)
  useEffect(() => {
    app.sessao().then(setSessao)
    return app.aoMudar(setSessao)
  }, [])
  return sessao ? <Tarefas /> : <Entrar />
}

function Entrar() {
  const [email, setEmail] = useState('')
  const [senha, setSenha] = useState('')
  return (
    <View>
      <TextInput value={email} onChangeText={setEmail} autoCapitalize="none"
        autoCorrect={false} keyboardType="email-address" />
      <TextInput value={senha} onChangeText={setSenha} secureTextEntry />
      <Pressable onPress={() => app.entrar(email, senha)}><Text>Entrar</Text></Pressable>
    </View>
  )
}

function Tarefas() {
  const [tarefas, setTarefas] = useState<{ id: string; titulo: string }[]>([])
  useEffect(() => {
    superdb.from('tarefas').select('id,titulo').then(({ data }) => setTarefas(data ?? []))
  }, [])
  return <View>{tarefas.map((t) => <Text key={t.id}>{t.titulo}</Text>)}</View>
}

6Rodar

Escaneie o QR code com o Expo Go (celular e computador na mesma rede) ou tecle i/a para abrir no simulador.

terminal
npx expo start

Próximos passos

Essa página ajudou?