npm package: @superfasttt/sdk
Description: SDK TypeScript pour interagir avec l'API SUPERFASTTT
Latest version: 1.0.0

# @superfasttt/sdk

SDK TypeScript pour la plateforme SUPERFASTTT. Fournit un client API type, l'authentification OAuth2, et des hooks React.

## Installation

```bash
pnpm add @superfasttt/sdk
```

Peer dependency optionnelle :

```bash
pnpm add react   # uniquement si vous utilisez les hooks React
```

---

## Quick Start

### React

```tsx
import { SuperfastttProvider, useAuth, useApi } from "@superfasttt/sdk/react"

function App({ children }: { children: React.ReactNode }) {
  return (
    <SuperfastttProvider
      appId="my-app"
      apiUrl={process.env.NEXT_PUBLIC_API_URL!}
      authUrl={process.env.NEXT_PUBLIC_AUTH_URL!}
      publicRoutes={["/auth/callback"]}
    >
      {children}
    </SuperfastttProvider>
  )
}

function Dashboard() {
  const { user, logout } = useAuth()
  const api = useApi()

  const loadModels = async () => {
    const models = await api.llm.listModels({ mode: "chat" })
  }

  return (
    <div>
      <p>Bonjour {user?.full_name}</p>
      <button onClick={logout}>Deconnexion</button>
      <button onClick={loadModels}>Charger les modeles</button>
    </div>
  )
}
```

### Standalone (sans React)

```typescript
import { createAuthClient } from "@superfasttt/sdk/auth"
import { createSuperfastttApi } from "@superfasttt/sdk/api"

const auth = createAuthClient({
  apiUrl: "http://localhost:8001",
  authUrl: "http://localhost:3004",
  clientId: "my-app",
})

const api = createSuperfastttApi(auth.fetch.bind(auth), "http://localhost:8001")

const models = await api.llm.listModels({ mode: "chat" })
const memories = await api.memories.list()
```

### Server-to-Server (API Key)

```typescript
import { createApiKeyClient } from "@superfasttt/sdk/api"

const sf = createApiKeyClient({
  apiUrl: "https://api.superfasttt.ai",
  apiKey: "sk-xxxxx",
})

const answer = await sf.ragChat.query({
  question: "Quelle est la politique de conges ?",
  memory_ids: ["mem-123"],
})

const models = await sf.llm.listModels({ mode: "chat" })
```

---

## Entry Points

Le SDK expose 4 entry points, chacun disponible en CJS, ESM et avec les types :

| Import | Contenu |
|--------|---------|
| `@superfasttt/sdk` | Re-export global (auth + apps + react + factory API) |
| `@superfasttt/sdk/auth` | `createAuthClient`, types auth, utilitaires token |
| `@superfasttt/sdk/react` | Provider, hooks React, guards |
| `@superfasttt/sdk/api` | `createSuperfastttApi`, modules API, erreurs, types |

---

## Authentification

### createAuthClient

```typescript
import { createAuthClient } from "@superfasttt/sdk/auth"

const auth = createAuthClient({
  apiUrl: "https://api.superfasttt.ai",
  authUrl: "https://auth.superfasttt.ai",
  clientId: "my-app",
  // Optionnel :
  storagePrefix: "superfasttt",       // prefix localStorage (defaut: "superfasttt")
  refreshThreshold: 300,               // secondes avant expiration pour refresh (defaut: 300)
  callbackPath: "/auth/callback",      // path OAuth2 callback (defaut: "/auth/callback")
})
```

### Methodes AuthClient

| Methode | Description |
|---------|-------------|
| `isAuthenticated()` | Verifie si le token est valide et non expire |
| `getToken()` | Retourne le token d'acces courant |
| `getUser()` | Retourne l'utilisateur decode du token (`AuthUser`) |
| `setTokens(tokens)` | Stocke les tokens (avec validation tenant) |
| `clearTokens()` | Supprime tous les tokens du localStorage |
| `redirectToLogin(returnPath?)` | Redirige vers la page de login OAuth2 |
| `authenticate(returnPath?)` | Tente SSO silencieux, sinon redirige vers login |
| `trySilentAuth(returnPath?)` | Tente le SSO silencieux avec un refresh token existant |
| `exchangeCode(code, redirectUri)` | Echange un code d'autorisation contre des tokens |
| `refreshAccessToken()` | Rafraichit le token d'acces |
| `getValidToken()` | Retourne un token valide, en rafraichissant si necessaire |
| `fetch(url, options?)` | Fetch authentifie avec retry auto sur 401 |
| `logout()` | Supprime les tokens et redirige vers le endpoint de logout |

### Flow OAuth2

```
1. User accede a l'app
2. AuthProvider detecte l'absence de token
3. Tentative de SSO silencieux (trySilentAuth)
4. Si echec → redirection vers auth.superfasttt.ai/login
5. Login reussi → redirection vers /auth/callback?code=xxx&state=yyy
6. exchangeCode(code, redirectUri) → TokenPair stocke en localStorage
7. Refresh automatique quand le token expire bientot
```

### Types Auth

```typescript
interface AuthUser {
  user_id: string
  email: string
  full_name?: string
  tenant_id: string
  role: string
}

interface TokenPair {
  access_token: string
  refresh_token: string
  token_type: string
  expires_in: number
}

interface AuthConfig {
  apiUrl: string
  authUrl: string
  clientId: string
  storagePrefix?: string
  refreshThreshold?: number
  callbackPath?: string
}
```

---

## Client API

### createSuperfastttApi

Factory qui cree un client API type avec tous les modules :

```typescript
import { createSuperfastttApi } from "@superfasttt/sdk/api"

const api = createSuperfastttApi(authFetch, apiUrl)
```

`authFetch` est une fonction `(url: string, options?: RequestInit) => Promise<Response>` — fournie par `useAuth().authFetch` ou `auth.fetch.bind(auth)`.

### Les 16 modules

| Module | Propriete | Description |
|--------|-----------|-------------|
| LLM | `api.llm` | Modeles, chat, images, audio, providers |
| Conversations | `api.conversations` | CRUD conversations et messages |
| Memories | `api.memories` | Bases de connaissances (CRUD) |
| Documents | `api.documents` | Upload, indexation, recherche de documents |
| RAG Chat | `api.ragChat` | Requetes RAG et Multi-RAG |
| Recordings | `api.recordings` | Enregistrements audio et workflows CR |
| Workflows | `api.workflows` | CRUD workflows, execution, versions, partage |
| Projects | `api.projects` | CRUD projets |
| Meetings | `api.meetings` | CRUD reunions et audio |
| Users | `api.users` | Gestion des utilisateurs |
| Budgets | `api.budgets` | Statut budget et gestion des limites |
| Tenant Keys | `api.tenantKeys` | Credentials des providers LLM |
| Webhooks | `api.webhooks` | Gestion des secrets webhook |
| Settings | `api.settings` | Parametres tenant et modeles par defaut |
| Providers | `api.providers` | Health checks des providers LLM |
| Apps | `api.apps` | Gestion des apps tierces |

### Exemples par module

#### LLM — Chat et modeles

```typescript
// Lister les modeles de chat disponibles
const models = await api.llm.listModels({ mode: "chat" })

// Lister tous les providers
const providers = await api.llm.listProviders()

// Chat completion
const response = await api.llm.chat({
  model: "gpt-4o",
  messages: [
    { role: "system", content: "Tu es un assistant utile." },
    { role: "user", content: "Bonjour !" },
  ],
  temperature: 0.7,
})

// Generation d'images
const images = await api.llm.generateImage({
  model: "dall-e-3",
  prompt: "Un paysage de montagne au coucher du soleil",
  size: "1024x1024",
})

// Transcription audio
const transcription = await api.llm.transcribeAudio({
  model: "whisper-1",
  audio_url: "https://example.com/audio.mp3",
})
```

#### Documents — Upload et recherche

```typescript
// Upload un document dans une base de connaissances
const doc = await api.documents.upload(file, memoryId)

// Lister les documents d'une base
const docs = await api.documents.list({ memory_id: memoryId })

// Recherche semantique
const results = await api.documents.query({
  query: "politique de remboursement",
  memory_ids: [memoryId],
  top_k: 5,
})
```

#### RAG Chat — Questions sur des documents

```typescript
// Question simple sur une base de connaissances
const answer = await api.ragChat.query({
  question: "Quelle est la politique de conges ?",
  memory_ids: [memoryId],
  model_id: "gpt-4o",
})

// Multi-RAG (recherche sur plusieurs bases avec @mentions)
const multiAnswer = await api.ragChat.multiRagQuery({
  message: "Compare les politiques de @RH et @Finance",
  model_id: "gpt-4o",
})
```

#### Workflows — Automatisation

```typescript
// Creer un workflow
const workflow = await api.workflows.create({
  name: "Mon workflow",
  description: "Traitement automatique des documents",
})

// Executer un workflow
const execution = await api.workflows.execute(workflow.id, {
  input_data: { document_id: "abc-123" },
})

// Suivre l'execution
const status = await api.workflows.getExecutionStatus(execution.execution_id)
const logs = await api.workflows.getExecutionLogs(execution.execution_id)
```

---

## API Keys (Server-to-Server)

`createApiKeyClient` permet aux entreprises clientes d'appeler l'API SUPERFASTTT depuis leur propre backend sans authentification OAuth2.

### Obtenir une API Key

Les API Keys se creent depuis le dashboard SUPERFASTTT : **Parametres > API Keys > Creer une cle**.

Chaque cle est liee a un utilisateur. Les depenses LLM sont imputees au budget de cet utilisateur.

Chaque cle donne acces a tous les endpoints disponibles via API Key (LLM, RAG, documents, memories). La securite est assuree par l'isolation tenant : chaque cle ne peut acceder qu'aux donnees de son propre tenant.

### Rate Limiting

| Type | Limite |
|------|--------|
| Lecture | 120 requetes/min |
| Ecriture | 60 requetes/min |
| AI (LLM, RAG) | 30 requetes/min |

### Usage

```typescript
import { createApiKeyClient } from "@superfasttt/sdk/api"

const sf = createApiKeyClient({
  apiUrl: "https://api.superfasttt.ai",
  apiKey: process.env.SUPERFASTTT_API_KEY!,
})

// RAG — poser une question sur une base de connaissances
const answer = await sf.ragChat.query({
  question: "Quelle est la politique de conges ?",
  memory_ids: ["mem-123"],
  model_id: "gpt-4o-mini",
})

// LLM — lister les modeles disponibles
const models = await sf.llm.listModels({ mode: "chat" })

// Documents — lister les documents d'une base
const docs = await sf.documents.list({ memory_id: "mem-123" })
```

---

## Modeles LLM multi-provider

Le SDK interagit avec tous les providers LLM via le proxy LiteLLM. Utilisez `listModels` pour decouvrir dynamiquement les modeles disponibles sur votre instance :

```typescript
// Tous les modeles de chat
const chatModels = await api.llm.listModels({ mode: "chat" })

// Filtrer par provider
const openaiModels = await api.llm.listModels({ provider: "openai" })

// Modeles d'embedding
const embeddingModels = await api.llm.listModels({ mode: "embedding" })

// Modeles de generation d'images
const imageModels = await api.llm.listModels({ mode: "image_generation" })
```

Providers supportes : **OpenAI**, **Anthropic**, **Mistral**, **Google (Gemini)**, **Ollama**, **Cohere**, **Azure OpenAI**, et tout provider compatible LiteLLM.

---

## Streaming SSE

Les modules `llm` et `ragChat` supportent le streaming via Server-Sent Events :

```typescript
// Chat streaming
for await (const event of api.llm.chatStream({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Raconte une histoire" }],
})) {
  const chunk = JSON.parse(event.data)
  process.stdout.write(chunk.choices[0]?.delta?.content || "")
}

// RAG streaming
for await (const event of api.ragChat.queryStream({
  question: "Resume ce document",
  memory_ids: [memoryId],
})) {
  const chunk = JSON.parse(event.data)
  // Traiter le chunk
}
```

### Annulation avec AbortController

```typescript
const controller = new AbortController()

// Annuler apres 10 secondes
setTimeout(() => controller.abort(), 10_000)

try {
  for await (const event of api.llm.chatStream(request, {
    signal: controller.signal,
  })) {
    // ...
  }
} catch (err) {
  if (err instanceof DOMException && err.name === "AbortError") {
    // Stream annule
  }
}
```

---

## React Hooks

Tous les hooks sont importes depuis `@superfasttt/sdk/react`.

### useApi

Client API type et memoize. C'est le hook principal pour interagir avec l'API.

```tsx
import { useApi } from "@superfasttt/sdk/react"

function MyComponent() {
  const api = useApi()

  const loadData = async () => {
    const models = await api.llm.listModels({ mode: "chat" })
    const memories = await api.memories.list()
    const docs = await api.documents.list({ memory_id: "xxx" })
  }
}
```

### useAuth

Acces a l'etat d'authentification et aux actions.

```tsx
import { useAuth } from "@superfasttt/sdk/react"

function UserMenu() {
  const { user, isAuthenticated, isLoading, logout, authFetch, login } = useAuth()

  if (isLoading) return <p>Chargement...</p>
  if (!isAuthenticated) return <button onClick={() => login()}>Connexion</button>

  return (
    <div>
      <p>{user!.email} ({user!.role})</p>
      <button onClick={logout}>Deconnexion</button>
    </div>
  )
}
```

### useSuperfasttt

Client SDK bas niveau avec `fetch` et `fetchJson` authentifies.

```tsx
import { useSuperfasttt } from "@superfasttt/sdk/react"

function MyComponent() {
  const { apiUrl, appId, fetch, fetchJson } = useSuperfasttt()

  const loadData = async () => {
    // fetchJson gere Content-Type et parsing JSON
    const data = await fetchJson<MyType>("/api/v1/my-endpoint")
  }
}
```

### useProviderHealth

Monitoring de la sante des providers LLM.

```tsx
import { useProviderHealth } from "@superfasttt/sdk/react"

function ModelSelector() {
  const {
    hasProviderIssue,
    getProviderWarning,
    providersWithIssues,
    hasAnyIssue,
    refresh,
  } = useProviderHealth({
    refreshInterval: 60000, // 1 minute
  })

  return (
    <div>
      {hasProviderIssue("openai") && (
        <span className="text-amber-500">{getProviderWarning("openai")}</span>
      )}
    </div>
  )
}
```

### useBudgetStatus

Polling du statut budget de l'utilisateur.

```tsx
import { useBudgetStatus } from "@superfasttt/sdk/react"

function ChatInput() {
  const { canUse, isExceeded, isWarning, usagePercent, message } = useBudgetStatus({
    pollingInterval: 10000, // 10 secondes
  })

  if (isExceeded) return <p>{message}</p>

  return <input disabled={!canUse} placeholder="Votre message..." />
}
```

### BudgetStatusGuard

Wrapper global qui affiche automatiquement une modale quand le budget est depasse et une banniere d'avertissement.

```tsx
import { BudgetStatusGuard } from "@superfasttt/sdk/react"

function Layout({ children }: { children: React.ReactNode }) {
  return (
    <SuperfastttProvider appId="my-app" apiUrl={apiUrl} authUrl={authUrl}>
      <BudgetStatusGuard pollingInterval={10000}>
        {children}
      </BudgetStatusGuard>
    </SuperfastttProvider>
  )
}
```

Personnalisable via les props `exceededModal` et `warningBanner`.

### useAppAccess

Verification de l'acces a une app tierce.

```tsx
import { useAppAccess } from "@superfasttt/sdk/react"

function MyComponent() {
  const { hasAccess, permissions, isLoading, isAdmin } = useAppAccess()

  if (isLoading) return <p>Verification...</p>
  if (!hasAccess) return <p>Acces refuse</p>

  return <div>Permissions : {permissions.join(", ")}</div>
}
```

---

## Apps Tierces

Les apps tierces sont des applications installees sur un tenant avec un systeme de permissions granulaire.

### AppAccessGuard

Composant qui affiche son contenu uniquement si l'utilisateur a acces a l'app :

```tsx
import { SuperfastttProvider, AppAccessGuard } from "@superfasttt/sdk/react"

function App({ children }: { children: React.ReactNode }) {
  return (
    <SuperfastttProvider appId="my-third-party-app" apiUrl={apiUrl} authUrl={authUrl}>
      <AppAccessGuard
        requiredPermissions={["documents:read"]}
        permissionMode="all"
        loadingComponent={<MyLoader />}
        accessDeniedComponent={<My403Page />}
      >
        {children}
      </AppAccessGuard>
    </SuperfastttProvider>
  )
}
```

### withAppAccess HOC

```tsx
import { withAppAccess } from "@superfasttt/sdk/react"

function MyProtectedPage() {
  return <div>Contenu protege</div>
}

export default withAppAccess(MyProtectedPage, {
  requiredPermissions: ["documents:write"],
})
```

### Hooks de permissions

```tsx
import {
  useHasPermission,
  useHasAllPermissions,
  useHasAnyPermission,
} from "@superfasttt/sdk/react"

function AdminPanel() {
  const canEdit = useHasPermission("documents:write")
  const canAdmin = useHasAllPermissions(["admin:read", "admin:write"])
  const canView = useHasAnyPermission(["documents:read", "projects:read"])

  if (!canEdit) return null
  return <button>Modifier</button>
}
```

Les admins (`super_admin`, `tenant_admin`) ont automatiquement toutes les permissions.

---

## Gestion d'erreurs

### ApiError

```typescript
import { ApiError, ApiValidationError } from "@superfasttt/sdk/api"

try {
  await api.documents.get("invalid-id")
} catch (err) {
  if (err instanceof ApiValidationError) {
    // Erreur 422 avec details par champ
    for (const detail of err.validationErrors) {
      // detail.field, detail.message, detail.type
    }
  } else if (err instanceof ApiError) {
    err.status         // Code HTTP
    err.message        // Message d'erreur
    err.code           // Code erreur (optionnel)
    err.isUnauthorized // 401
    err.isForbidden    // 403
    err.isNotFound     // 404
    err.isRateLimited  // 429
    err.isServerError  // 5xx
  }
}
```

---

## Types exportes

Tous les types sont disponibles via `@superfasttt/sdk/api` :

| Module | Types principaux |
|--------|-----------------|
| LLM | `LLMModel`, `LLMProvider`, `ChatRequest`, `ChatResponse`, `ChatMessage`, `ImageGenerationRequest`, `AudioTranscriptionRequest` |
| Conversations | `Conversation`, `ConversationDetail`, `Message`, `CreateConversationRequest` |
| Memories | `Memory`, `MemoryStats`, `CreateMemoryRequest` |
| Documents | `Document`, `DocumentUploadResponse`, `DocumentQueryRequest`, `DocumentChunk` |
| RAG Chat | `RAGQueryRequest`, `RAGQueryResponse`, `RAGSource`, `MultiRAGRequest`, `MultiRAGResponse` |
| Recordings | `Recording`, `RecordingUploadResponse`, `CRType` |
| Workflows | `Workflow`, `WorkflowExecution`, `WorkflowExecutionLogs`, `NodeLog`, `WorkflowVersion` |
| Projects | `Project`, `CreateProjectRequest` |
| Meetings | `Meeting`, `MeetingDocument`, `CreateMeetingRequest` |
| Users | `User`, `CreateUserRequest`, `UserTeam` |
| Budgets | `BudgetStatus`, `Budget`, `UserBudgetLiteLLM` |
| Tenant Keys | `TenantCredentials`, `TenantCredentialsStatus` |
| Webhooks | `WebhookSecret`, `WebhookLog` |
| Settings | `DefaultModelsResponse`, `AppSettingsResponse` |
| Providers | `ProviderHealthStatus`, `ProvidersHealthResponse` |
| Apps | `AppConfig`, `AppManifest`, `AppInstallation`, `SystemPermission` |
| Auth | `AuthUser`, `AuthConfig`, `TokenPair`, `AuthState` |
| Erreurs | `ApiError`, `ApiValidationError`, `ValidationErrorDetail` |
| Base | `AuthFetch`, `SSEEvent`, `QueryParams`, `PaginatedResponse`, `SuccessResponse` |

---

## Build

```bash
cd packages/sdk

pnpm build       # Build CJS + ESM + DTS pour les 4 entry points
pnpm typecheck   # Verification des types sans build
pnpm dev         # Build en mode watch
```

Le build produit via `tsup` :

```
dist/
├── index.js / index.mjs / index.d.ts           # @superfasttt/sdk
├── auth/index.js / index.mjs / index.d.ts       # @superfasttt/sdk/auth
├── react/index.js / index.mjs / index.d.ts      # @superfasttt/sdk/react
└── api/index.js / index.mjs / index.d.ts        # @superfasttt/sdk/api
```