npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chrono-os/auth-better

v0.6.1

Published

BetterAuth + Prisma adapter pré-configurado para apps Chrono — User/Session/Account/Verification + enum Role (MEMBER|ADMIN), helpers servidor (buildAuth) e cliente (createAuthClient). Promoção do @svadulto/auth-config

Readme

@chrono-os/auth-better

O módulo de login da casa: BetterAuth + Prisma configurado com os defaults da casa no servidor, client React tipado e as telas prontas (login, cadastro, 2FA, recuperação de senha, dispositivos conectados).

Install

yarn add @chrono-os/auth-better better-auth

Models Prisma necessários no schema do app: User, Session, Account, Verification. Com 2FA, também TwoFactor e User.twoFactorEnabled. O default do buildAuth grava User.role ('MEMBER'): app sem essa coluna passa userAdditionalFields: {}.

Entradas

| Import | O que tem | Quem usa | |---|---|---| | @chrono-os/auth-better | = /core (servidor, sem framework) | backend com moduleResolution: "node" | | @chrono-os/auth-better/core | buildAuth, buildAuthOptions, readSession, toWebHeaders | backend Nest/Express/Next | | @chrono-os/auth-better/server | core + adaptador Fastify (fastifyAuthPlugin, getSessionFromRequest) | backend Fastify | | @chrono-os/auth-better/client | createAuthClient (React), genérico nos plugins | frontend | | @chrono-os/auth-better/ui + /ui.css | as telas prontas | frontend |

Servidor

import { buildAuth, readSession } from '@chrono-os/auth-better/core'

export const auth = buildAuth({
  prisma,
  secret: env.BETTER_AUTH_SECRET,
  baseURL: `${env.API_URL}/api/v1/auth`,
  trustedOrigins: [env.FRONTEND_URL],
  google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, prompt: 'select_account' },

  // Atalhos de login confiável — cada um liga um plugin do próprio better-auth
  twoFactor: { issuer: 'Meu App' },       // TOTP + 10 códigos de backup + confiar no dispositivo (30d)
  checkBreachedPasswords: true,           // recusa senha vazada (Have I Been Pwned, k-anonimato)

  // Sobreposições são MESCLADAS no default, não substituem
  emailAndPassword: { sendResetPassword: async ({ user, url }) => mandarEmail(user.email, url) },
  session: { expiresIn: 60 * 60 * 24 * 30 },
})

const sessao = await readSession(auth, req.headers) // null em cookie inválido, nunca lança

Defaults: e-mail+senha (mínimo 8, entra direto após cadastro), sessão de 7 dias renovada a cada dia com cache de cookie de 5 min, sameSite: 'lax', bearer() para mobile, campo role. Rate limit é o do better-auth, ligado em produção: 3 tentativas a cada 10 s no login e 3 por minuto no reset. extend(options) recebe a config final para qualquer opção que o pacote não previu.

Frontend

import { createAuthClient } from '@chrono-os/auth-better/client'
import { twoFactorClient } from 'better-auth/client/plugins'

export const authClient = createAuthClient({ baseURL: `${API_URL}/api/v1/auth`, plugins: [twoFactorClient()] })

Telas prontas (/ui)

import { LoginForm } from '@chrono-os/auth-better/ui'
import '@chrono-os/auth-better/ui.css'

<LoginForm
  client={authClient}
  onSuccess={() => router.push(destinoSeguro(params.get('from'), '/painel'))}
  google={{ callbackURL: `${location.origin}/painel` }}
  forgotPasswordHref="/esqueci-senha"
  signUpHref="/cadastro"
  renderLink={(href, children, className) => <Link href={href} className={className}>{children}</Link>}
/>

| Componente | O que faz | |---|---| | LoginForm | e-mail e senha, olho, aviso de Caps Lock, manter conectado, Google, esqueci a senha, reenvio de confirmação de e-mail, desafio 2FA no lugar (ou onTwoFactorRequired para outra rota), selo "último usado" | | TwoFactorChallenge | código do app ou de backup + confiar neste dispositivo por 30 dias | | SignUpForm | nome, e-mail, senha com medidor de força, aceite opcional (obrigatório quando passado), honeypot anti-robô, "confirme seu e-mail" quando o servidor exige verificação | | ForgotPasswordForm | mesma resposta exista ou não a conta | | ResetPasswordForm | senha nova + confirmação; token inválido ou vencido leva a "pedir link novo" | | ChangePasswordForm | senha atual + nova, "sair dos outros dispositivos" marcado | | TwoFactorSettings | ativar (QR gerado no navegador + chave manual + confirmação), desativar, novos códigos de backup | | SessionsList | dispositivos conectados, encerrar um, sair de todos os outros | | PasswordInput, PasswordStrength, QrCode, destinoSeguro | peças soltas |

Regras que os componentes seguem: erro de login sempre genérico ("e-mail ou senha incorretos"); rede fora não trava o botão; 429 aparece como "muitas tentativas"; autocomplete certo em todo campo (username, current-password, new-password, one-time-code); rótulo, aria-invalid, aria-describedby e role="alert" em todo formulário; alvo de toque de 44px; input com 16px (sem zoom no iOS). O QR do 2FA é montado localmente: o otpauth:// carrega o segredo TOTP e não pode ir para serviço de QR de terceiros.

Estilo. CSS real, sem Tailwind: funciona em app Tailwind 3 ou 4 sem mexer em content/@source. Para a cara da marca, aponte os tokens para os do app no :root — o tema do app passa a valer aqui também:

:root { --ab-primary: var(--brand-600); --ab-bg: var(--surface); --ab-fg: var(--text); --ab-radius: 12px; }

Tokens: --ab-bg --ab-fg --ab-muted --ab-border --ab-input-bg --ab-primary --ab-primary-fg --ab-danger --ab-danger-bg --ab-success --ab-success-bg --ab-focus --ab-radius --ab-font. Os fallbacks cobrem claro, escuro (.dark, data-theme="dark" ou data-mode="dark") e black OLED (.oled) num ancestral. prefers-color-scheme não é seguido sozinho, de propósito: num app sem tema escuro o formulário ficaria escuro numa página clara.

Textos. pt-BR em tom neutro. Cada componente aceita textos={{ entrar: 'Bora' }} para trocar só o que precisar (TEXTOS_PADRAO tem a lista).

peerDeps

  • better-auth ^1.0.0
  • @prisma/client ^5 || ^6 || ^7
  • react ^18 || ^19 (opcional — só para /client e /ui)
  • fastify ^5 (opcional — só para /server)

Versionamento

SemVer. Tag v* → npmjs.org. Em 0.x, minor pode quebrar: veja o CHANGELOG antes de subir.