@groundbrick/sveltekit-adapter
v0.2.4
Published
SvelteKit integration adapter with API client, stores, hooks, analytics, and cookie consent system
Maintainers
Readme
@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-adapterPeer Dependencies
npm install @sveltejs/kit svelteQuick Start
1. Configuração de Hooks
// src/hooks.server.ts
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) => {
// Custom error handling
console.error('App error:', error, context);
}
}
});
export const handle = sequence(...hooks);
export { handleError };2. Configuração do API Client
// src/lib/api.ts
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
// src/routes/+layout.svelte
<script lang="ts">
import {
CookieConsent,
ConsentService,
createConsentAwareAnalytics
} from '@groundbrick/sveltekit-adapter/consent';
// Initialize consent service
const consentService = ConsentService.getInstance();
// Setup analytics with consent awareness
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
// src/routes/+page.svelte
<script lang="ts">
import {
authStore,
apiStore,
isAuthenticated,
currentUser,
initializeStores
} from '@groundbrick/sveltekit-adapter';
// Initialize stores on app start
initializeStores();
// Reactive to authentication state
$: 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
// Everything from client and hooks
import {
createApiClient,
authStore,
createSvelteKitHooks
} from '@groundbrick/sveltekit-adapter';Client Module
// Just client functionality
import {
ApiClient,
createApiClient,
authStore,
apiStore,
isAuthenticated,
currentUser,
isLoading,
currentError,
initializeStores,
clearErrors
} from '@groundbrick/sveltekit-adapter/client';Hooks Module
// Just hooks functionality
import {
createSvelteKitHooks,
createAuthHook,
createLoggerHook,
createErrorHandlerHook
} from '@groundbrick/sveltekit-adapter/hooks';Consent Module
// Cookie consent system
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
});
// GET request
const users = await client.get('/users');
// POST request with data
const newUser = await client.post('/users', {
name: 'John Doe',
email: '[email protected]'
});
// Request with auth token
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) => {
// Add timestamp to all requests
config.headers['X-Timestamp'] = new Date().toISOString();
return config;
},
response: (response) => {
// Log all successful responses
console.log('Response received:', response.status);
return response;
},
error: (error) => {
// Custom error handling
if (error.status === 401) {
// Redirect to login
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:
// src/hooks.server.ts
const { hooks, handleError } = createSvelteKitHooks({
auth: {
tokenKey: 'auth_token',
redirectPath: '/login',
publicPaths: [
'/login',
'/register',
'/',
'/landing',
'/api/*', // Allow API calls to pass through
'/favicon.ico',
'/robots.txt'
],
validateExpiration: true // Enable JWT expiration checking (default: true)
}
});Cookie Consent System
GDPR Compliance
import {
ConsentService,
GDPR_CONFIG,
createConsentAwareAnalytics
} from '@groundbrick/sveltekit-adapter/consent';
// GDPR-compliant setup
const consentService = ConsentService.getInstance(GDPR_CONFIG);
// Analytics only loads with explicit consent
const analytics = createConsentAwareAnalytics(consentService, {
gaId: 'G-XXXXXXXXXX',
anonymizeIp: true
});
// Track events (respects consent automatically)
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';
// Reactive authentication state
$: if ($isAuthenticated) {
console.log('User:', $currentUser);
}
// Login
authStore.login({
token: 'jwt-token',
user: { id: 1, name: 'John', email: '[email protected]' }
});
// Logout
authStore.logout();
// Check if user has specific role
if ($currentUser?.roles?.includes('admin')) {
// Show admin content
}API Store
import { apiStore, isLoading, currentError } from '@groundbrick/sveltekit-adapter';
// Loading states
$: if ($isLoading) {
// Show spinner
}
// Error handling
$: if ($currentError) {
// Show error message
console.error('API Error:', $currentError);
}
// Manual error clearing
apiStore.clearError();Notification System
import {
showSuccess,
showError,
showWarning,
showInfo,
clearAllNotifications,
useNavigationNotificationClear
} from '@groundbrick/sveltekit-adapter';
// Enable auto-clearing on navigation (add to your root layout)
useNavigationNotificationClear();
// Show different types of notifications
showSuccess('Data saved successfully!');
showError('Something went wrong!');
showWarning('This action cannot be undone!');
showInfo('New feature available!');
// With options
showSuccess('Operation complete!', {
title: 'Success',
duration: 3000,
persistent: false // won't clear on navigation if true
});
// Clear notifications
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
// 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
// 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
// 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
// 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
- 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,
.sveltecomponents) fromsrc/into the publisheddist/folder. This is handled by the scriptscripts/copy-assets.jswhich runs aftertscin the packagebuildscript.Why: some modules are intentionally re-exported as source Svelte components (for example
analytics/components/GoogleAnalytics.svelte). The compiled TypeScript output indistcontains runtime imports to those.sveltefiles. To make the package consumable by apps that will compile Svelte components in their own build (SvelteKit apps), we ship the.sveltefiles alongside the compiled JS so imports resolve correctly.Why not rsync: earlier we used
rsyncto copy files, but that requiresrsyncto 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.sveltesources), which is cleaner for non-Svelte consumers but requires adding a Svelte compilation step to the package build. - Keep shipping
.sveltefiles (the current approach). This is the simplest and lets SvelteKit apps compile components during app build time.
- Precompile Svelte components into JavaScript during the package build (using Rollup/Vite or
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).
