first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
# `better-auth-adapter`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`better-auth-adapter.ts` provides the response-narrowing bridge between `better-auth/client` (which returns a `BetterAuthError | BetterAuthData<T>` union with native `Date` timestamps) and the package's internal `User` / `Session` / `AuthResponse` shapes (which carry ISO-string timestamps for serialisation safety). The module exposes two structural type guards (`isBetterAuthError`, `hasBetterAuthData`) that narrow `unknown` to the appropriate branch without `any`, plus four `transform*` functions that map a successful payload onto an internal shape and surface the error branch's message when the call failed. No `any` types appear anywhere — every guard accepts `unknown` and narrows through explicit field checks.
## Features
- Two type guards: `isBetterAuthError(unknown)`, `hasBetterAuthData<T>(unknown)`.
- Four transforms: `transformSessionResponse`, `transformAuthResponse`, `transformGenericResponse`, `transformUpdateProfileResponse`.
- ISO-string normalisation for every `Date` field on the way out.
- Robust to `null` / `undefined` / malformed payloads — returns a default with a `message` string when the shape doesn't match.
## Usage: Basic
```ts
import { transformSessionResponse } from "@suaveplan/react-auth";
const raw = await client.getSession();
const { user, session, error } = transformSessionResponse(raw);
```
## Usage: Advanced
Chain the guards directly when you need to act differently on each branch:
```ts
import {
hasBetterAuthData,
isBetterAuthError,
transformAuthResponse,
} from "@suaveplan/react-auth";
const raw = await client.signIn({ email, password });
if (isBetterAuthError(raw)) {
logger.warn({ code: raw.error, message: raw.message }, "sign-in rejected");
return;
}
if (hasBetterAuthData<{ user: unknown }>(raw)) {
const out = transformAuthResponse(raw);
if (out.user) await persistSession(out.user);
}
```
## API Reference
- `function isBetterAuthError(response: unknown): response is { error: string; message: string }`
- `function hasBetterAuthData<T = unknown>(response: unknown): response is { data: T }`
- `function transformSessionResponse(response: unknown): { session: Session | null; user: User | null; error?: string }`
- `function transformAuthResponse(response: unknown): AuthResponse`
- `function transformGenericResponse(response: unknown): AuthResponse`
- `function transformUpdateProfileResponse(response: unknown): AuthResponse`
## Implementation Notes
The two top-level guards use `typeof value === "object" && value !== null` plus structural field checks. They do not use `instanceof` because the underlying client may return plain objects parsed from JSON. The user-shape guard checks `id`, `email`, `emailVerified`, `name`, `createdAt`, and `updatedAt` are present and of the expected primitive class (`Date | string`); the session-shape guard checks `id`, `userId`, and `expiresAt`. When the payload includes a `Date` instance for any timestamp, the transform calls `.toISOString()`; when it's already a string, it is passed through. The `transformUser` helper hard-codes `roles: 0` and `status: 0` because those fields belong to the internal `User` type but are not modelled by better-auth's session payload — call sites that need richer role data must read them from the `Session` row directly (Wave 2 wires this through the form components).