# @andco/sdk-react

> Provider, hooks y el botón hospedado para React.


```bash
npm install @andco/sdk @andco/sdk-react
```

## AndcoProvider

```tsx
<AndcoProvider clientOptions={...} client={...} initialSession={...}>
```

| Prop | Qué es |
| --- | --- |
| `clientOptions` | opciones con las que el provider construye la instancia |
| `client` | una instancia que la aplicación ya tiene. Gana si están las dos |
| `initialSession` | una sesión que el servidor ya resolvió |

`initialSession` no es una optimización. Sin ella, un árbol renderizado en el servidor muestra un estado sin resolver, el cliente muestra lo mismo, y la pantalla salta cuando el almacén termina de cargar. Con ella ambos lados muestran la sesión real y no hay salto.

El provider usa un inicializador perezoso de `useState`. Es seguro precisamente porque construir es puro y el almacén carga en la primera suscripción: `StrictMode` lo invoca dos veces y Suspense puede descartar un render entero, y la instancia que React tira nunca se suscribió, así que nunca leyó el almacenamiento ni gastó un código de autorización.

## useAndcoSession

```ts
useAndcoSession(): AndcoSession | null | undefined
```

Tres estados: `undefined` mientras la carga no termina, `null` cuando no hay sesión, y la sesión. Renderizar los dos primeros igual hace parpadear un estado de «sin sesión» en cada carga, que es exactamente lo que la distinción existe para evitar.

Cambia de referencia en **cada** republicación, incluida una rotación silenciosa de token — a diferencia de `useAndco`, que deliberadamente no cambia en ese caso. Úsalo cuando necesites la credencial como dato, por ejemplo una expiración.

```tsx
const session = useAndcoSession();
if (session === undefined) return <Skeleton />;
return session ? <Account user={session.user} /> : <SignIn />;
```

## useAndcoUser

```ts
useAndcoUser(): AndcoUser | null | undefined
```

Derivado de la sesión, con los mismos tres estados, pero cambia de referencia solo cuando cambia la persona — identificador, nombre, correo o avatar — nunca por un Grant ampliado ni por una rotación de token.

## useAndco

```ts
useAndco(): AndcoClient | AndcoClientAuthed
```

La instancia completa: `auth`, `rest`, `intents`, `session`, `oauth`, `config`. Es lo que usas para todo lo que no sea leer la sesión.

Cambia de referencia exactamente cuando cambia la Identidad Autorizada — inicio de sesión, cierre de sesión, un Grant ampliado — y no cuando rota un token. Mientras no hay Identidad Autorizada devuelve la instancia sin autorizar, así que la referencia también es estable en la transición de sin-resolver a anónimo; para observar esa transición usa `useAndcoSession`.

## useAndcoAuthed

```ts
useAndcoAuthed(): AndcoClientAuthed | null
```

La misma regla de cambio que `useAndco`, pero tipada a `AndcoClientAuthed | null`: `null` mientras no hay Identidad Autorizada, para que un efecto o una consulta "hacer esto solo si hay sesión" no necesite una comprobación en tiempo de ejecución.

## AndcoButton

```tsx
<AndcoButton
  authorization={{ scopes: ["openid", "email"] }}
  onComplete={() => router.refresh()}
  onError={(error) => setMessage(error.message)}
/>
```

| Prop | Qué es |
| --- | --- |
| `authorization` | scopes y contribuciones de autorización |
| `flow` | `"authorization"` o `"intent"` |
| `busy`, `disabled` | estado visual |
| `themeMode`, `locale`, `release` | presentación |
| `onReady`, `onActivate`, `onComplete`, `onDismiss`, `onError` | ciclo de vida |

Acepta además los atributos de un `iframe`, salvo los que controla el SDK: `src`, `sandbox`, `referrerPolicy`, `srcDoc` y `children`.

Fíjate en lo que **no** acepta: endpoints, versiones, `clientId` ni tema. Eso viene de la instancia, porque un componente recibe lo que cambia mientras la aplicación corre y nada más. Pasarlos otra vez es como una aplicación termina con dos copias de un valor que pueden discrepar.

## AndcoIntentButton

```tsx
<AndcoIntentButton onComplete={reload} />
```

El mismo control en su flujo de Intent. Es un componente con otro `flow` y no una implementación paralela, porque dos implementaciones de una misma presentación es exactamente como los caminos directo y hospedado se separaron antes.
