Pular para o conteúdo
Nelcota
EN : Read in English

Contrato do cliente

7 min de leitura Editar no GitHub

@nelcota/client 0.1.x tem como alvo o protocolo HTTP do Nelcota implementado neste repositório. O pacote tem sua própria versão; a compatibilidade com o servidor é determinada pelos endpoints e recursos abaixo, sem depender de números de versão iguais.

Escopo de versão

Este é o contrato da fonte atual. O pacote publicado 0.1.2 é anterior ao registro transacional nativo no IndexedDB e à preservação numérica exata descritos abaixo; consulte a documentação incluída no pacote para essa versão. Comportamento não publicado do cliente exige novo build/pacote, independentemente de atualizar o servidor.

Interface

Módulo Métodos Contrato HTTP
REST from().select(), filtros, ordenação, limit, range, single, maybeSingle GET/HEAD /rest/v1/{table}; consulta codificada; Prefer: count=exact opcional; Content-Range
Escritas REST insert, update, delete, upsert, select opcional POST/PATCH/DELETE /rest/v1/{table}; corpo JSON; Prefer: return=minimal/representation; resolução de upsert e on_conflict
RPC rpc(name, args) POST /rest/v1/rpc/{name}; argumentos JSON nomeados; papel do chamador
Autenticação signUp POST /auth/v1/signup; sessão ou {user} aguardando confirmação
Autenticação login por senha, renovação, exchangeCode POST /auth/v1/token?grant_type=password/refresh_token/pkce
Autenticação getUser, signOut GET /auth/v1/user, POST /auth/v1/logout
Links de autenticação recuperação, link mágico, reenvio, verificação/redefinição POST /auth/v1/recover, /magiclink, /resend, /verify
OAuth signInWithOAuth, handleRedirect GET /auth/v1/authorize; PKCE S256; callback ?code= trocado uma única vez
Armazenamento upload, replace, open/download, remove POST/PUT/GET/DELETE /storage/v1/object/{bucket}/{path}; bytes brutos
Armazenamento listagem, URL assinada, URL pública POST /storage/v1/object/list/{bucket}, /object/sign/{bucket}/{path}; /object/public/{bucket}/{path}
Buckets list, get, create, update, delete /storage/v1/bucket e /storage/v1/bucket/{id}

schema seleciona o esquema TypeScript gerado; o esquema exposto configurado no servidor determina o recurso HTTP. Isso não troca esquemas do banco em tempo de execução. RLS e GRANTs continuam sendo decisões do servidor/Postgres.

Resultados e falhas

  • Autenticação e armazenamento retornam {data,error}. REST adiciona status e count; RPC adiciona status. Escritas sem .select() e respostas HEAD retornam null. HEAD tem o tipo null, incluindo selects encadeados. single/maybeSingle exigem uma representação de linhas e rejeitam escritas mínimas ou HEAD antes do HTTP. Uma representação de linhas solicitada que esteja vazia ou não seja um array JSON retorna invalid_response; nunca é considerada bem-sucedida com null ou outro formato.
  • Falhas HTTP preservam code, message e status do servidor. Rede, cancelamento, timeout e corpos interrompidos durante a leitura em memória retornam status 0 e códigos do cliente.
  • Corpos de erro HTTP maiores que 64 KiB são descartados; o status, um código genérico e Retry-After continuam disponíveis.
  • JSON inválido retorna invalid_response com o status HTTP da resposta.
  • Números JSON continuam numéricos quando seus dígitos decimais são preservados pela conversão em JavaScript. Inteiros fora da faixa segura e decimais que perderiam dígitos viram strings, inclusive em valores JSON aninhados e resultados de RPC. Campos gerados de tipos bigint, numeric, real e double precision usam number | string; gere novamente os tipos do esquema após atualizar. Passe valores exatos como strings em filtros e escritas. Elementos de arrays PostgreSQL podem ser nulos independentemente de a coluna aceitar nulos; por isso os arrays gerados usam (T | null)[].
  • Conjuntos de resultados escalares de RPC também permitem elementos nulos e agrupam uniões numéricas como (number | string | null)[]. Funções que retornam linhas de views referenciam a seção Views gerada, enquanto linhas de tabelas referenciam Tables.
  • Valores JSON não finitos (NaN e infinitos) lançam NelcotaUsageError antes da autenticação ou do HTTP, em vez de virarem null silenciosamente. Valores null explícitos continuam válidos. Sessões exigem o formato completo de sessão e usuário, com expires_at e expires_in como inteiros seguros e não negativos; refreshMargin deve ser finito e não negativo.
  • Configurações inválidas do desenvolvedor e identificadores/caminhos inseguros lançam NelcotaUsageError. Erros lançados por configurações de token/armazenamento/fetch fornecidas pelo usuário fora da operação HTTP continuam sendo responsabilidade do chamador.
  • GET e HEAD repetem tentativas após falhas de rede, leitura do corpo, 429 e 503; mutações, troca de tokens de autenticação, listagem de armazenamento e RPC não são repetidos automaticamente.
  • O timeout cobre cada tentativa e seu corpo carregado em memória, excluindo a renovação de sessão e a espera entre tentativas. Retry-After de até 30 segundos é respeitado; atrasos maiores retornam o erro imediatamente com retryAfter para o chamador.
  • storage.open() entrega a resposta bruta ao chamador. Erros posteriores no stream devem ser tratados pelo chamador; download() carrega o corpo em um Blob e retorna falhas de leitura no resultado.

Sessões e ciclo de vida

Cada cliente possui seu adaptador de sessão. O localStorage nativo usa um registro transacional no IndexedDB como estado oficial da sessão, com localStorage como espelho de compatibilidade. Nos demais ambientes, o padrão é um adaptador separado em memória. Um adaptador personalizado pode ser síncrono ou assíncrono. Instancie um cliente de servidor por requisição ou forneça um token por requisição. A chave padrão de armazenamento inclui o host e o caminho-base, para que projetos em caminhos diferentes não sobrescrevam as sessões uns dos outros em um adaptador compartilhado.

Clientes de servidor com o armazenamento padrão em memória usam filas de coordenação independentes. Um login pendente em outro cliente não atrasa a leitura da sessão de uma requisição independente.

Chamadas de renovação em um cliente de autenticação compartilham uma promise. Clientes que compartilham um adaptador e uma chave de armazenamento são serializados com Web Locks, com uma fila local ao módulo como alternativa. Sessões nativas do navegador também confirmam uma reserva de renovação antes do HTTP e leem a sessão substituta somente após a confirmação da transação do IndexedDB. Web Locks sozinhos não ordenam a visibilidade do localStorage em outra aba. Sem Web Locks, o registro rejeita proprietários concorrentes em vez de aguardar a sessão substituta. Adaptadores compartilhados personalizados exigem Web Locks ou coordenação externa; caso contrário, use sessionStorage por aba. A fila local ao módulo não coordena abas separadas.

A persistência nativa exige IndexedDB e limita cada abertura do banco e transação a cinco segundos. As conexões fecham após cada operação. Uma reserva não concluída de outro proprietário exige um novo login, uma nova tentativa pelo cliente proprietário ou signOut; ela nunca recorre ao token possivelmente já usado do localStorage. Um logout confirmado substitui o estado não persistido em outros clientes, e respostas atrasadas de renovação não podem sobrescrevê-lo. As transmissões entre abas levam notificações de alteração, sem tokens.

Cada publicação nativa possui uma revisão única. O login explícito captura o registro anterior antes do HTTP; falhas na publicação preservam a sessão substituta local ou o logout enquanto esse registro exato permanece atual, mesmo com outro proprietário. Uma revisão confirmada posterior a substitui mesmo quando o valor é idêntico.

O registro importa o estado existente do localStorage uma vez por chave de armazenamento. Recarregue todas as abas ao atualizar para evitar misturar protocolos de coordenação do SDK. Use signOut() ou limpe todos os dados do site para remover sessões; editar apenas localStorage não altera mais a sessão oficial. Adaptadores personalizados preservam seu comportamento existente.

A margem de renovação fica limitada à metade da validade do token, para que tokens de curta duração e margens configuradas altas não renovem sessões recém-criadas repetidamente. A variação aleatória em segundo plano permanece dentro do atraso programado. Um token já expirado espera dez segundos antes de uma tentativa em segundo plano; leituras explícitas da sessão ainda o renovam imediatamente.

Métodos de autenticação que fazem HTTP aceitam {signal,timeout} como último argumento. Chamadores de renovação concorrentes compartilham o timeout do primeiro chamador. Signals cancelam a espera de cada chamador de forma independente; a rotação continua e persiste seu resultado mesmo quando alguém cancela a espera. Um chamador já cancelado não inicia a rotação. Signals de REST/armazenamento também cobrem a espera pela fonte de tokens ou pela renovação de sessão, sem interromper uma operação compartilhada por outros chamadores. signOut() aguarda uma renovação pendente e limpa a sessão local mesmo quando a revogação no servidor falha. dispose() para timers, fecha canais e limpa listeners; não revoga a sessão nem interrompe requisições já em andamento.

Verificadores PKCE nativos usam o mesmo registro com uma chave separada. O consumo confirma atomicamente uma marca de remoção, impedindo que visões nativas desatualizadas façam trocas com um verificador antigo ou já consumido. O cancelamento antes do consumo preserva o verificador; após o início do consumo, o cancelamento encerra a espera do chamador enquanto a troca com prazo limitado termina e persiste uma sessão aceita. Adaptadores personalizados preservam a API de armazenamento existente e a coordenação por locks de chave.

Falhas ao salvar a sessão preservam o estado mais recente na memória: este cliente nunca relê um token de renovação já usado nem restaura uma sessão encerrada a partir de dados antigos. Erros de armazenamento continuam rejeitando os métodos explícitos de autenticação. Erros inesperados dos adaptadores em segundo plano são observados pelo callback opcional auth.onBackgroundError; a renovação automática pausa até que uma sessão seja salva com sucesso. Exceções do callback ficam isoladas. Erros de rede retornados nos resultados mantêm as tentativas limitadas de renovação. Clientes nativos bloqueiam ao encontrar uma reserva não concluída de outro proprietário; uma sessão substituta aceita permanece com seu proprietário até ser persistida ou substituída por uma sessão ou logout confirmado mais recente. Adaptadores personalizados exigem correção antes de compartilhar estado que não foi persistido.

Um accessToken explícito controla requisições REST/armazenamento e desativa a renovação automática de sessão no cliente combinado. Métodos de autenticação continuam disponíveis e podem armazenar uma sessão quando chamados explicitamente.

Configurações de buckets

A criação aceita BucketSettings com campos opcionais. A atualização usa BucketUpdateSettings, exige public, file_size_limit e allowed_mime_types e substitui todo o objeto de configurações com PUT. Use null explícito para remover um limite. Campos ausentes lançam NelcotaUsageError antes de qualquer requisição HTTP, inclusive em consumidores JavaScript.

Aceitação da publicação

Execute check, testes unitários/de tipos, build, size, test:package, testes básicos de ambientes de execução e test:contract -- --browser. A CI testa Node 22/24/26, Bun, Deno e Chromium/Firefox/WebKit. Hosts de borda podem consumir a implementação baseada em Web APIs, mas não fazem parte desta garantia de compatibilidade até serem testados nesse host.