@groundbrick/sveltekit-adapter
SvelteKit integration adapter para o microframework TypeScript - fornece integração client-side com APIs Express, gerenciamento de estado reativo, autenticação JWT, hooks e sistema de consentimento de cookies.
Features Implementadas
- š§ ApiClient - Cliente HTTP com autenticação, retry, timeout e suporte a cookies
- š Gerenciamento de Autenticação - Autenticação segura usando HttpOnly cookies
- š Stores Reativas - Stores Svelte para estado de auth e API com suporte a runes
- � Sistema de Notificações - Sistema completo de notificações toast com auto-clear na navegação
- ļæ½š”ļø 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
- šŖ Cookie Consent - Sistema GDPR-compliant de consentimento com Google Analytics
Instalação
npm install @groundbrick/sveltekit-adapter
Peer Dependencies
npm install @sveltejs/kit svelte
Quick Start
1. Configuração de Hooks
import { sequence } from '@sveltejs/kit/hooks';
import { createSvelteKitHooks } from '@groundbrick/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) => {
console.error('App error:', error, context);
}
}
});
export const handle = sequence(...hooks);
export { handleError };
2. Configuração do API Client
import { createApiClient } from '@groundbrick/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. Cookie Consent Setup
<script lang="ts">
import {
CookieConsent,
ConsentService,
createConsentAwareAnalytics
} from '@groundbrick/sveltekit-adapter/consent';
const consentService = ConsentService.getInstance();
const analytics = createConsentAwareAnalytics(consentService, {
gaId: 'G-XXXXXXXXXX',
enableDebug: true
});
</script>
<!-- Your app content -->
<slot />
<!-- Cookie consent banner -->
<CookieConsent
theme="light"
position="bottom"
onConsentChange={(state) => {
console.log('Consent updated:', state);
}}
/>
4. Using Stores
<script lang="ts">
import {
authStore,
apiStore,
isAuthenticated,
currentUser,
initializeStores
} from '@groundbrick/sveltekit-adapter';
initializeStores();
$: if ($isAuthenticated) {
console.log('User is logged in:', $currentUser);
}
</script>
{#if $isAuthenticated}
<h1>Welcome, {$currentUser?.name}!</h1>
{:else}
<a href="/login">Please log in</a>
{/if}
{#if $apiStore.loading}
<div class="spinner">Loading...</div>
{/if}
{#if $apiStore.error}
<div class="error">{$apiStore.error}</div>
{/if}
Module Exports
Main Package
import {
createApiClient,
authStore,
createSvelteKitHooks
} from '@groundbrick/sveltekit-adapter';
Client Module
import {
ApiClient,
createApiClient,
authStore,
apiStore,
isAuthenticated,
currentUser,
isLoading,
currentError,
initializeStores,
clearErrors
} from '@groundbrick/sveltekit-adapter/client';
Hooks Module
import {
createSvelteKitHooks,
createAuthHook,
createLoggerHook,
createErrorHandlerHook
} from '@groundbrick/sveltekit-adapter/hooks';
Consent Module
import {
CookieConsent,
ConsentService,
createConsentAwareAnalytics,
GDPR_CONFIG,
CCPA_CONFIG
} from '@groundbrick/sveltekit-adapter/consent';
API Client Features
Basic Usage
import { createApiClient } from '@groundbrick/sveltekit-adapter';
const client = createApiClient({
baseUrl: 'https://api.example.com',
timeout: 10000,
retries: 3
});
const users = await client.get('/users');
const newUser = await client.post('/users', {
name: 'John Doe',
email: 'john@example.com'
});
const profile = await client.get('/profile', {
headers: { Authorization: 'Bearer token' }
});
Advanced Configuration
const client = createApiClient({
baseUrl: 'https://api.example.com',
timeout: 15000,
retries: 5,
retryDelay: 1000,
defaultHeaders: {
'Content-Type': 'application/json',
'X-API-Version': '2024-01-01'
},
interceptors: {
request: (config) => {
config.headers['X-Timestamp'] = new Date().toISOString();
return config;
},
response: (response) => {
console.log('Response received:', response.status);
return response;
},
error: (error) => {
if (error.status === 401) {
window.location.href = '/login';
}
throw error;
}
}
});
Authentication Flow
The adapter provides secure authentication using HttpOnly cookies:
How Authentication Works:
- Server-side: Auth hook validates JWT tokens from HttpOnly cookies (no client-side token handling)
- Client-side: API Client automatically includes cookies with all requests
- Automatic cleanup: Invalid tokens are cleared through HttpOnly cookie management
- Smart redirects: Users are redirected to login with current page as return URL
- No performance impact: No unnecessary API calls on page loads
Auth Hook Configuration:
const { hooks, handleError } = createSvelteKitHooks({
auth: {
tokenKey: 'auth_token',
redirectPath: '/login',
publicPaths: [
'/login',
'/register',
'/',
'/landing',
'/api/*',
'/favicon.ico',
'/robots.txt'
],
validateExpiration: true
}
});
Cookie Consent System
GDPR Compliance
import {
ConsentService,
GDPR_CONFIG,
createConsentAwareAnalytics
} from '@groundbrick/sveltekit-adapter/consent';
const consentService = ConsentService.getInstance(GDPR_CONFIG);
const analytics = createConsentAwareAnalytics(consentService, {
gaId: 'G-XXXXXXXXXX',
anonymizeIp: true
});
analytics.trackEvent({
action: 'button_click',
category: 'UI',
label: 'signup'
});
Custom Configuration
const customConfig = {
banner: {
title: 'šŖ Cookies',
message: 'We use cookies to improve your experience.',
acceptAllText: 'Accept All',
rejectAllText: 'Reject All'
},
categories: {
functional: {
required: true,
name: 'Essential',
description: 'Required for basic functionality'
},
analytics: {
required: false,
name: 'Analytics',
description: 'Help us improve our website'
}
}
};
const consentService = ConsentService.getInstance(customConfig);
Stores System
Authentication Store
import { authStore, isAuthenticated, currentUser } from '@groundbrick/sveltekit-adapter';
$: if ($isAuthenticated) {
console.log('User:', $currentUser);
}
authStore.login({
token: 'jwt-token',
user: { id: 1, name: 'John', email: 'john@example.com' }
});
authStore.logout();
if ($currentUser?.roles?.includes('admin')) {
}
API Store
import { apiStore, isLoading, currentError } from '@groundbrick/sveltekit-adapter';
$: if ($isLoading) {
}
$: if ($currentError) {
console.error('API Error:', $currentError);
}
apiStore.clearError();
Notification System
import {
showSuccess,
showError,
showWarning,
showInfo,
clearAllNotifications,
useNavigationNotificationClear
} from '@groundbrick/sveltekit-adapter';
useNavigationNotificationClear();
showSuccess('Data saved successfully!');
showError('Something went wrong!');
showWarning('This action cannot be undone!');
showInfo('New feature available!');
showSuccess('Operation complete!', {
title: 'Success',
duration: 3000,
persistent: false
});
clearAllNotifications();
Add notification component to your layout:
<script>
import { useNavigationNotificationClear } from '@groundbrick/sveltekit-adapter';
import Notifications from '$lib/components/Notifications.svelte';
// Enable auto-clearing
useNavigationNotificationClear();
</script>
<main>
<slot />
</main>
<!-- Notifications -->
<Notifications />
Logging Estruturado
- Request/Response: Log automƔtico com timing
const loggerHook = createLoggerHook({
logRequests: true,
logResponses: true
});
- Context preservation: Mantém contexto através da aplicação
const logger = createLogger().child('user-service');
- Structured data: Logs estruturados com metadados
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
const startTime = Date.now();
await apiClient.get('/heavy-endpoint');
Melhores PrƔticas
- Inicialize stores cedo no ciclo de vida da aplicação
- Use stores reativas em vez de gerenciamento manual de estado
- Configure hooks apropriadamente para as necessidades da sua aplicação
- Use TypeScript para melhor experiĆŖncia de desenvolvimento
- Trate erros graciosamente com os error stores
- Configure paths públicos no hook de autenticação
- Use retry mechanism para endpoints instƔveis
- Implemente consent desde o inĆcio para compliance
- Configure analytics com consent awareness
- Use presets de configuração para diferentes regiões
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
@groundbrick/logger - Sistema de logging
Peer Dependencies
@sveltejs/kit - SvelteKit framework (^2.0.0)
svelte - Svelte framework (^5.0.0)
License
MIT
Packaging & build notes
-
During the package build we copy some source assets (for example, .svelte components) from src/ into the published dist/ folder. This is handled by the script scripts/copy-assets.js which runs after tsc in the package build script.
-
Why: some modules are intentionally re-exported as source Svelte components (for example analytics/components/GoogleAnalytics.svelte). The compiled TypeScript output in dist contains runtime imports to those .svelte files. To make the package consumable by apps that will compile Svelte components in their own build (SvelteKit apps), we ship the .svelte files alongside the compiled JS so imports resolve correctly.
-
Why not rsync: earlier we used rsync to copy files, but that requires rsync to be present on the build server. To make builds portable across environments we now use a small cross-platform Node script.
-
Alternatives:
- Precompile Svelte components into JavaScript during the package build (using Rollup/Vite or
svelte/compiler). This produces a distribution with JS only (no .svelte sources), which is cleaner for non-Svelte consumers but requires adding a Svelte compilation step to the package build.
- Keep shipping
.svelte files (the current approach). This is the simplest and lets SvelteKit apps compile components during app build time.
-
If you prefer a precompiled distribution, open an issue or request and we can add a Rollup/Vite build step (low-risk, slightly larger change).