# @djangocfg/api

Type-safe API client and auth system for DjangoCFG applications.

## Install

```bash
pnpm add @djangocfg/api
```

## Entry Points

| Entry | Import | Description |
|-------|--------|-------------|
| **Main** | `@djangocfg/api` | API classes, types, fetchers, schemas |
| **Auth** | `@djangocfg/api/auth` | Auth providers, hooks, utilities |
| **Auth Server** | `@djangocfg/api/auth/server` | Next.js proxy middleware |
| **Clients** | `@djangocfg/api/clients` | Pre-configured API instances |

## Generated API Classes

One class per OpenAPI tag. Import directly and call static methods:

```typescript
import {
  CfgAccounts,          // OTP login
  CfgAccountsProfile,   // Profile CRUD
  CfgAccountsOauth,     // GitHub OAuth
  CfgAccountsAuth,      // Token refresh
  CfgAccountsApiKey,    // API key management
  CfgTotp,              // TOTP devices / disable
  CfgTotpSetup,         // TOTP setup / confirm
  CfgTotpVerify,        // TOTP verify / backup
  CfgTotpBackupCodes,   // Backup codes
  CfgCentrifugo,        // Centrifugo token
} from '@djangocfg/api';

// OTP login
const result = await CfgAccounts.cfgAccountsOtpVerifyCreate({
  body: { identifier, otp },
});

// Profile
const profile = await CfgAccountsProfile.cfgAccountsProfileRetrieve();

// Token refresh
const tokens = await CfgAccountsAuth.cfgAccountsTokenRefreshCreate({
  body: { refresh },
});
```

## Auth Module

```tsx
import { AuthProvider, useAuth } from '@djangocfg/api/auth';

// Provider
<AuthProvider config={{ routes: { auth: '/auth', defaultCallback: '/dashboard' } }}>
  {children}
</AuthProvider>

// Hook
const { user, isAuthenticated, requestOTP, verifyOTP, logout } = useAuth();
```

### Auth Hooks

```typescript
import {
  useAuth,              // Main auth context
  useAuthGuard,         // Route protection
  useAuthForm,          // OTP form state machine
  useGithubAuth,        // GitHub OAuth
  useTwoFactor,         // 2FA verification
  useTwoFactorSetup,    // 2FA setup flow
  useTwoFactorStatus,   // 2FA status / disable
  useDeleteAccount,     // Account deletion
} from '@djangocfg/api/auth';
```

## Token storage & DPoP

The token lives in the shared `auth` store (localStorage by default, switchable
to cookie):

```typescript
import { auth } from '@djangocfg/api';

auth.getToken();              // current access token
auth.setStorageMode('cookie'); // SSR-readable cookie instead of localStorage
```

### DPoP (RFC 9449) — sender-constrained tokens

When enabled, the generated client holds a **non-extractable** P-256 key
(IndexedDB) and attaches a fresh `DPoP` proof to every request, so a stolen
token can't be replayed. No BFF/proxy required.

```typescript
import { dpopEnabled } from '@djangocfg/api';
// true when NEXT_PUBLIC_DPOP_ENABLED==='true'
// (set it via createBaseNextConfig({ dpop: true }) in @djangocfg/nextjs)
```

Backend pairing: `JWTConfig(dpop_enabled=True)`. Full guide:
`@djangocfg/nextjs/@docs/DPOP.md`. The token is still readable via
`auth.getToken()` — DPoP protects by *binding* to the key, not by hiding the token.

## Logging — role-aware verbosity

All `@djangocfg/*` consola loggers read one global runtime level so the console
is clean for end users and verbose for admins/devs — like big SaaS apps.

```typescript
import { applyRoleLogPolicy, setLogLevel } from '@djangocfg/api';

// Usually automatic: AuthProvider calls this on login/logout.
// admin (is_staff/is_superuser) or dev → debug; prod regular user → errors only.
applyRoleLogPolicy({ isAdmin: user?.is_staff || user?.is_superuser });

// Manual override (0 silent · 1 error · 2 warn · 3 info · 4 debug · 5 trace):
setLogLevel(0);
```

Errors still flow to `@djangocfg/devtools` regardless of console level, so prod
incidents stay diagnosable.

## Env flags

`@djangocfg/api` is the lowest shared package, so env flags live here (single
source of truth):

```typescript
import { isDev, isProd, isBrowser, isStaticBuild, dpopEnabled } from '@djangocfg/api';
```

## Type Namespaces

```typescript
import type { AccountsTypes, TotpTypes, CentrifugoTypes } from '@djangocfg/api';

type User = AccountsTypes.User;
type Device = TotpTypes.TotpDevice;
```

## Server Middleware

```typescript
// middleware.ts
import { proxyMiddleware } from '@djangocfg/api/auth/server';

export function middleware(request: NextRequest) {
  return proxyMiddleware(request);
}

export const config = {
  matcher: ['/media/:path*', '/api/:path*'],
};
```

## Environment

```bash
NEXT_PUBLIC_API_URL=http://localhost:8000
```

## Regenerate Client

```bash
# From django solution directory
make api
```
