getEntitlements() responde a primeira, para o time dentro do
qual a sessão atual está agindo.
kind é uma string simples e não uma união justamente por isso: um kind que você
criar não pode depender de uma nova versão do SDK para ser lido por um cliente.
limit é um teto para comparar com o uso; included é uma concessão por período
para somar a um saldo, e só existe para o kind credit. São dois campos porque
são duas perguntas.
“Sem teto” viaja como unlimited: true, nunca como um limit ausente. Uma
feature com limit: null e unlimited: false não tem teto registrado, o que é
um teto de zero e não permissão para um teto infinito — um número mágico no fio é
um número que todo cliente precisa aprender, e um null solto é um que todo
cliente interpreta do seu jeito. Toda feature do seu catálogo aparece aqui,
inclusive as que o plano atual não carrega: elas chegam com enabled: false, que
é a resposta e não uma lacuna.
No React
@userkit/nextjs — é o mesmo hook, e em
modo proxy a leitura é encaminhada pelos
handlers, com a sessão num cookie httpOnly da sua própria origem. O time continua
sendo resolvido e nunca nomeado: o X-Customer-Id atravessa os handlers e identifica
sem nunca autorizar.
Ele segue a sessão: sair da conta limpa o valor, e trocar de time refaz a leitura
para o time dentro do qual a próxima requisição vai agir.
O time é resolvido, nunca nomeado
A concessão pertence ao cliente que a sessão resolveu — o quesetActiveCustomer() nomeou, ou a associação mais antiga do contato quando
nenhum foi nomeado. Não existe parâmetro que nomeie um cliente, e é isso que faz
um id colado responder 404 em vez do plano de outra pessoa.
Três respostas que valem um branch
- 404 — a sessão não pertence a time nenhum. Um visitante anônimo recebe isso, e é a resposta verdadeira em vez de uma recusa: é o que diz à interface para oferecer a criação de um time.
- 403
unverified_session— uma sessão identificada mas não verificada. O que uma conta paga inclui não se entrega a uma afirmação que qualquer um que saiba umexternal_idpoderia fazer de um navegador. - 503
entitlements_unavailable— nada está sendo recusado. A concessão não pôde ser resolvida agora, então pergunte de novo. A API não responde corpo nenhum, em vez de responder um cheio defalse, porque uma tela cheia defalsetomaria a decisão por você, em silêncio, na direção que fecha o seu produto durante uma queda nossa.
useEntitlements() renderiza as três como null, que é a mesma renderização de
“ainda carregando”, de propósito: as duas significam ainda não há nada para
barrar. Nunca trate null como uma concessão de nada — barre em
grant?.features[key].enabled e deixe null significar “ainda não”.
Isto é o portão da interface, não a aplicação da regra
Um navegador pode ouvir qualquer coisa. Leia a mesma concessão no seu backend — com uma chave de servidor,GET /v1/customers/{id}/entitlements, ao lado do
token de sessão que prova quem está
perguntando — e aplique a regra lá. O que getEntitlements() compra é uma tela que
não oferece um botão que o plano vai recusar.