npm package: @200systems/mf-sveltekit-adapter
Description: SvelteKit integration adapter with API client, stores, and hooks
Author: Cleiton Marques
Latest version: 1.1.6

# @200systems/mf-sveltekit-adapter

SvelteKit integration adapter para o microframework TypeScript - fornece integração client-side com APIs Express, gerenciamento de estado reativo, autenticação JWT e hooks.

## Features Implementadas

- **🔧 ApiClient** - Cliente HTTP com autenticação, retry, timeout e gerenciamento de token
- **🔐 Gerenciamento de Token** - Persistência automática de JWT token no localStorage
- **📊 Stores Reativas** - Stores Svelte para estado de auth e API com suporte a runes
- **🛡️ Error Handling** - Hooks abrangentes de tratamento de erros
- **📝 Request Logging** - Log automático de request/response com timing
- **🎣 SvelteKit Hooks** - Hooks pré-construídos para autenticação e logging
- **🔄 Retry Logic** - Lógica de retry automática com exponential backoff
- **⏱️ Timeout Handling** - Controle de timeout configurável para requests

## Instalação

```bash
npm install @200systems/mf-sveltekit-adapter
```

### Peer Dependencies

```bash
npm install @sveltejs/kit svelte
```

## Quick Start

### 1. Configuração de Hooks

```typescript
// src/hooks.server.ts
import { sequence } from '@sveltejs/kit/hooks';
import { createSvelteKitHooks } from '@200systems/mf-sveltekit-adapter';

const { hooks, handleError } = createSvelteKitHooks({
  logger: {
    logRequests: true,
    logResponses: true,
    includeHeaders: false,
    excludePaths: ['/favicon.ico', '/robots.txt', '/health'],
    context: 'my-app'
  },
  auth: {
    tokenKey: 'auth_token',
    publicPaths: ['/login', '/register', '/', '/api/public/*'],
    redirectPath: '/login',
    onAuthRequired: () => {
      console.log('Authentication required');
    }
  },
  errorHandler: {
    logErrors: true,
    context: 'my-app',
    onError: (error, context) => {
      // Custom error handling
      console.error('App error:', error, context);
    }
  }
});

export const handle = sequence(...hooks);
export { handleError };
```

### 2. Configuração do API Client

```typescript
// src/lib/api.ts
import { createApiClient } from '@200systems/mf-sveltekit-adapter';

export const apiClient = createApiClient({
  baseUrl: 'http://localhost:3000/api',
  timeout: 10000,
  retries: 3,
  defaultHeaders: {
    'X-App-Version': '1.0.0',
    'X-Client': 'sveltekit'
  }
});
```

### 3. Inicialização de Stores

```typescript
// src/routes/+layout.svelte
<script lang="ts">
  import { onMount } from 'svelte';
  import { initializeStores, authStore, isAuthenticated } from '@200systems/mf-sveltekit-adapter/client';
  import { apiClient } from '$lib/api.js';

  onMount(() => {
    // Inicializar stores (carrega token do localStorage)
    initializeStores();
    
    // Configurar token no API client se disponível
    const currentAuth = $authStore;
    if (currentAuth.token) {
      apiClient.setToken(currentAuth.token);
    }
  });

  function handleLogout() {
    authStore.logout();
    apiClient.clearToken();
  }
</script>

{#if $isAuthenticated}
  <nav>
    <a href="/dashboard">Dashboard</a>
    <a href="/users">Users</a>
    <button onclick={handleLogout}>Logout</button>
  </nav>
{/if}

<main>
  <slot />
</main>
```

### 4. Uso em Componentes

```svelte
<!-- src/routes/login/+page.svelte -->
<script lang="ts">
  import { authStore, isLoading, currentError, clearErrors } from '@200systems/mf-sveltekit-adapter/client';
  import { apiClient } from '$lib/api.js';
  import { goto } from '$app/navigation';

  let email = $state('');
  let password = $state('');

  async function handleLogin() {
    try {
      clearErrors();
      authStore.setLoading(true);
      
      const result = await apiClient.post('/auth/login', { email, password });
      
      authStore.login(result.user, result.token);
      apiClient.setToken(result.token);
      goto('/dashboard');
    } catch (error) {
      authStore.setError((error as Error).message);
    }
  }
</script>

<form onsubmit={handleLogin}>
  <input bind:value={email} type="email" placeholder="Email" required />
  <input bind:value={password} type="password" placeholder="Password" required />
  
  {#if $currentError}
    <div class="error">{$currentError}</div>
  {/if}
  
  <button type="submit" disabled={$isLoading}>
    {$isLoading ? 'Fazendo login...' : 'Login'}
  </button>
</form>
```

## API Reference

### ApiClient

```typescript
interface ApiClientConfig {
  baseUrl: string;
  timeout?: number;
  retries?: number;
  defaultHeaders?: Record<string, string>;
}

class ApiClient {
  constructor(config: ApiClientConfig);
  
  // Token management
  setToken(token: string): void;
  clearToken(): void;
  getToken(): string | null;
  isAuthenticated(): boolean;
  
  // HTTP methods
  get<T>(endpoint: string, options?: RequestOptions): Promise<T>;
  post<T>(endpoint: string, data?: unknown, options?: RequestOptions): Promise<T>;
  put<T>(endpoint: string, data?: unknown, options?: RequestOptions): Promise<T>;
  patch<T>(endpoint: string, data?: unknown, options?: RequestOptions): Promise<T>;
  delete<T>(endpoint: string, options?: RequestOptions): Promise<T>;
  
  // Retry mechanism
  requestWithRetry<T>(endpoint: string, options?: RequestOptions, retries?: number): Promise<T>;
}

// Factory function
const client = createApiClient(config);
```

### Request Options

```typescript
interface RequestOptions extends RequestInit {
  skipAuth?: boolean;    // Skip automatic token inclusion
  timeout?: number;      // Override default timeout
}

// Exemplos de uso
await client.get('/users');
await client.post('/users', userData);
await client.put('/users/123', updateData);
await client.delete('/users/123');

// Com opções customizadas
await client.get('/public-data', { skipAuth: true });
await client.get('/slow-endpoint', { timeout: 30000 });

// Com retry customizado
await client.requestWithRetry('/flaky-endpoint', {}, 5);
```

### Stores Reativas

```typescript
// Auth Store
interface AuthStore {
  isAuthenticated: boolean;
  user: Record<string, unknown> | null;
  token: string | null;
  loading: boolean;
  error: string | null;
}

// API Store
interface ApiStore {
  loading: boolean;
  error: string | null;
  lastRequest: string | null;
}

// Stores disponíveis
import { 
  authStore, 
  apiStore, 
  isAuthenticated, 
  currentUser, 
  isLoading, 
  currentError,
  initializeStores,
  clearErrors 
} from '@200systems/mf-sveltekit-adapter/client';

// Valores reativos (para usar com $ em Svelte)
$isAuthenticated  // boolean
$currentUser      // Record<string, unknown> | null
$isLoading        // boolean (auth.loading || api.loading)
$currentError     // string | null (auth.error || api.error)

// Ações do authStore
authStore.login(user, token);
authStore.logout();
authStore.setLoading(true);
authStore.setError('Error message');
authStore.initialize(); // Carrega do localStorage

// Ações do apiStore
apiStore.setLoading(true);
apiStore.setError('API error');
apiStore.setLastRequest('/api/endpoint');

// Funções utilitárias
initializeStores();  // Inicializa todos os stores
clearErrors();       // Limpa todos os erros
```

### Hooks do SvelteKit

```typescript
// Hook individual de logging
const loggerHook = createLoggerHook({
  logRequests: true,
  logResponses: true,
  includeHeaders: false,
  excludePaths: ['/health', '/favicon.ico'],
  context: 'request-logger'
});

// Hook individual de autenticação
const authHook = createAuthHook({
  tokenKey: 'auth_token',
  redirectPath: '/login',
  publicPaths: ['/login', '/register', '/', '/api/public/*'],
  onAuthRequired: () => {
    console.log('Authentication required');
  }
});

// Handler de erro
const errorHandler = createErrorHandler({
  logErrors: true,
  context: 'error-handler',
  onError: (error, context) => {
    // Custom error handling
    sendToAnalytics(error, context);
  }
});

// Hook combinado (recomendado)
const { hooks, handleError } = createSvelteKitHooks({
  logger: { /* config */ },
  auth: { /* config */ },
  errorHandler: { /* config */ }
});

export const handle = sequence(...hooks);
export { handleError };
```

## Exemplos Práticos

### Gerenciamento de Usuários

```svelte
<!-- src/routes/users/+page.svelte -->
<script lang="ts">
  import { onMount } from 'svelte';
  import { apiClient } from '$lib/api.js';
  import { apiStore, isLoading, currentError } from '@200systems/mf-sveltekit-adapter/client';

  let users = $state([]);

  onMount(async () => {
    await loadUsers();
  });

  async function loadUsers() {
    try {
      apiStore.setLoading(true);
      const response = await apiClient.get('/users');
      users = response.data || response;
    } catch (error) {
      apiStore.setError((error as Error).message);
    }
  }

  async function deleteUser(id: number) {
    if (!confirm('Tem certeza?')) return;
    
    try {
      await apiClient.delete(`/users/${id}`);
      users = users.filter(u => u.id !== id);
    } catch (error) {
      apiStore.setError((error as Error).message);
    }
  }
</script>

{#if $isLoading}
  <div class="loading">Carregando...</div>
{/if}

{#if $currentError}
  <div class="error">{$currentError}</div>
{/if}

<div class="users">
  {#each users as user}
    <div class="user-card">
      <h3>{user.name}</h3>
      <p>{user.email}</p>
      <button onclick={() => deleteUser(user.id)}>Deletar</button>
    </div>
  {/each}
</div>
```

### Formulário com Validação

```svelte
<!-- src/routes/users/create/+page.svelte -->
<script lang="ts">
  import { apiClient } from '$lib/api.js';
  import { apiStore, isLoading, currentError, clearErrors } from '@200systems/mf-sveltekit-adapter/client';
  import { goto } from '$app/navigation';

  let form = $state({
    name: '',
    email: '',
    password: ''
  });

  async function handleSubmit() {
    try {
      clearErrors();
      apiStore.setLoading(true);
      
      const user = await apiClient.post('/users', form);
      goto('/users');
    } catch (error) {
      apiStore.setError((error as Error).message);
    }
  }
</script>

<form onsubmit|preventDefault={handleSubmit}>
  <input bind:value={form.name} placeholder="Nome" required />
  <input bind:value={form.email} type="email" placeholder="Email" required />
  <input bind:value={form.password} type="password" placeholder="Senha" required />
  
  {#if $currentError}
    <div class="error">{$currentError}</div>
  {/if}
  
  <button type="submit" disabled={$isLoading}>
    {$isLoading ? 'Criando...' : 'Criar Usuário'}
  </button>
</form>
```

### Proteção de Rotas

```typescript
// src/routes/dashboard/+layout.server.ts
import { redirect } from '@sveltejs/kit';

export async function load({ locals }) {
  // O hook de auth já validou o token
  // Se chegou aqui, o usuário está autenticado
  
  if (!locals.authToken) {
    throw redirect(302, '/login');
  }
  
  return {
    authToken: locals.authToken
  };
}
```

## Integração com Express API

Este adapter foi projetado para funcionar perfeitamente com `@200systems/mf-express-adapter`:

```typescript
// O ApiClient automaticamente lida com:
// - Tokens JWT no formato Bearer
// - Respostas padronizadas da API Express
// - Error handling consistente
// - Retry logic para falhas de rede
// - Timeout handling

// Exemplo de resposta esperada da API Express:
interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: string;
  message?: string;
}
```

## Suporte a TypeScript

Suporte completo ao TypeScript com tipagem estrita:

```typescript
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

// Chamadas de API tipadas
const users = await apiClient.get<User[]>('/users');
const user = await apiClient.post<User>('/users', userData);

// Stores tipados
const currentUser: Readable<User | null> = derived(
  authStore,
  $auth => $auth.user as User
);
```

## Características Específicas

### Gerenciamento de Token Automático

- **Persistência**: Tokens são automaticamente salvos no `localStorage`
```typescript
// Automático quando você faz login
authStore.login(user, token); // Token é salvo no localStorage
apiClient.setToken(token);    // Cliente configurado automaticamente
```

- **Restauração**: Tokens são restaurados na inicialização da aplicação
```typescript
// No +layout.svelte
onMount(() => {
  initializeStores(); // Carrega token do localStorage automaticamente
  
  const auth = $authStore;
  if (auth.token) {
    apiClient.setToken(auth.token); // Cliente pronto para usar
  }
});
```

- **Limpeza**: Tokens são removidos no logout ou erro 401
```typescript
// Logout manual
authStore.logout(); // Remove do localStorage + limpa store

// Logout automático em 401
await apiClient.get('/protected'); // Se retornar 401, token é limpo automaticamente
```

- **Sincronização**: ApiClient e stores sincronizam automaticamente
```typescript
// Sincronização bidirecional
authStore.login(user, token);  // ✅ Store + localStorage atualizados
apiClient.setToken(token);     // ✅ Cliente configurado

apiClient.clearToken();        // ✅ Cliente limpo
authStore.logout();            // ✅ Store + localStorage limpos
```

### Error Handling Inteligente

- **Retry automático**: Para erros de rede (não para 4xx)
```typescript
// Retry automático para erros de rede
await apiClient.get('/flaky-endpoint'); // Retry 3x automaticamente

// Retry customizado
await apiClient.requestWithRetry('/critical-data', {}, 5); // Retry 5x
```

- **Exponential backoff**: Delay crescente entre tentativas
```typescript
// Delays automáticos: 1s, 2s, 4s, 8s...
try {
  await apiClient.get('/unstable-api');
} catch (error) {
  // Só falha após todas as tentativas com delays crescentes
}
```

- **401 handling**: Logout automático em tokens expirados
```typescript
try {
  await apiClient.get('/protected');
} catch (error) {
  // Se 401: token é limpo automaticamente + store atualizado
  if (error.message === 'Authentication required') {
    // Usuário já foi deslogado automaticamente
    goto('/login');
  }
}
```

- **Error stores**: Centralização de erros em stores reativos
```typescript
// Qualquer erro fica disponível reativamentenos stores
apiStore.setError('API failed');
authStore.setError('Login failed');

// Em qualquer componente
{#if $currentError}
  <div class="error">{$currentError}</div>
{/if}
```

### Logging Estruturado

- **Request/Response**: Log automático com timing
```typescript
// Configuração no hooks.server.ts
const loggerHook = createLoggerHook({
  logRequests: true,   // GET /api/users [timing: 245ms]
  logResponses: true   // GET /api/users 200 OK [duration: 245ms]
});

// Logs automáticos no console/arquivo
// INFO: Incoming request { method: 'GET', url: '/api/users', duration: 245 }
```

- **Context preservation**: Mantém contexto através da aplicação
```typescript
// Contexto propagado automaticamente
const logger = createLogger().child('user-service');
// user-service: Processing user creation
// user-service: Database query completed
// user-service: User created successfully
```

- **Structured data**: Logs estruturados com metadados
```typescript
// Metadados automáticos em cada log
logger.info('User login', {
  userId: 123,
  ip: '192.168.1.1',
  userAgent: 'Chrome/120.0',
  timestamp: '2024-01-15T10:30:00Z',
  requestId: 'req_abc123'
});
```

- **Performance tracking**: Tracking de performance automático
```typescript
// Timing automático de requests
const startTime = Date.now();
await apiClient.get('/heavy-endpoint');
// Log: Request completed { duration: 1247ms, status: 200 }

// Timing de hooks
// Log: Request processed { url: '/dashboard', duration: 89ms }
```

## Melhores Práticas

1. **Inicialize stores cedo** no ciclo de vida da aplicação
2. **Use stores reativas** em vez de gerenciamento manual de estado
3. **Configure hooks apropriadamente** para as necessidades da sua aplicação
4. **Use TypeScript** para melhor experiência de desenvolvimento
5. **Trate erros graciosamente** com os error stores
6. **Configure paths públicos** no hook de autenticação
7. **Use retry mechanism** para endpoints instáveis

## Compatibilidade

- **Svelte 5.x** com runes support
- **SvelteKit 2.x** com app directory structure
- **Node.js 18+** para funcionalidades de servidor
- **TypeScript 5.x** para tipagem completa

## Dependencies

### Required
- `@200systems/mf-logger` - Sistema de logging

### Peer Dependencies  
- `@sveltejs/kit` - SvelteKit framework (^2.0.0)
- `svelte` - Svelte framework (^5.0.0)

## License

MIT