TrueSift SDK für Svelte 5 und SvelteKit
Dieses Dokument gilt ausschließlich für @truesift/svelte, nicht für @truesift/next. Das Svelte-SDK nutzt native Svelte-5-APIs und dasselbe TrueSift-Verifikationsprotokoll und Widget-Design wie das Next.js SDK. Aktuelle veröffentlichte Version: 0.2.0.
- npm-Paket
@truesift/svelte - Andere SDKs auswählen
- Gemeinsame interaktive Vorschau (technisch mit dem React-SDK gerendert)
Voraussetzungen und Installation
Svelte 5, für die folgenden Beispiele SvelteKit mit Server-Routen und Node.js >=20.19.0 gemäß den Paketanforderungen.
pnpm add @truesift/svelteAlternativ: npm install @truesift/svelte.
Import-Pfade
| Import | Verwendung |
|---|---|
@truesift/svelte | Komponente, Controller, Client-Typen |
@truesift/svelte/client | TrueSiftCheck, createTrueSiftCheck, UI-Hilfen |
@truesift/svelte/server | Server-Routen und verifyTrueSiftProof |
@truesift/svelte/shared | Gemeinsame Protokolltypen |
@truesift/svelte/styles.css | Optional; die Komponente importiert ihre Styles bereits selbst |
import { TrueSiftCheck, createTrueSiftCheck } from '@truesift/svelte/client';
import { createTrueSiftChallengeHandler, createTrueSiftVerifyHandler, verifyTrueSiftProof } from '@truesift/svelte/server';Niemals /server in Browser-Komponenten importieren.
Serverseitige Umgebungsvariablen
TRUESIFT_API_BASE_URL=https://api.truesift.de
TRUESIFT_SITE_KEY=your_site_key
TRUESIFT_SECRET_KEY=your_secret_key
TRUESIFT_DEFAULT_ACTION=your_registered_action
TRUESIFT_FAIL_OPEN=false
TRUESIFT_TIMEOUT_MS=2500Die API-URL enthält nur den Ursprung, kein /api/v1. SITE_KEY und SECRET_KEY sind erforderlich. In SvelteKit bleiben die Zugangsdaten in $env/dynamic/private oder einem anderen serverseitigen Konfigurationskanal, *niemals in `PUBLIC_**. Standardmäßig arbeitet das SDK mit **Fail-Closed (false`)**. Der Timeout beträgt standardmäßig 2500 ms (zulässig: 250–30000 ms).
Verifikationsablauf
- Der Browser ruft die same-origin-Route
/api/truesift/challengeauf. - Die Komponente verwendet
/api/truesift/verifyund erhält bei erfolgreicher Verifikation einen kurzlebigenverificationToken. - Die geschützte Business-Route prüft den einmal verwendbaren Token über
verifyTrueSiftProof, mit vertrauenswürdigen Werten für Action, Path und Origin. - Nur nach erfolgreicher serverseitiger Proof-Prüfung wird die fachliche Aktion ausgeführt. Ein clientseitiges
allowist keine Freigabe.
SvelteKit Integration
1. Challenge-Route
Datei: src/routes/api/truesift/challenge/+server.ts
import { env } from '$env/dynamic/private';
import type { RequestHandler } from './$types';
import { createTrueSiftChallengeHandler } from '@truesift/svelte/server';
const handleChallenge = createTrueSiftChallengeHandler({
apiBaseUrl: env.TRUESIFT_API_BASE_URL,
siteKey: env.TRUESIFT_SITE_KEY,
secretKey: env.TRUESIFT_SECRET_KEY,
defaultAction: env.TRUESIFT_DEFAULT_ACTION,
failOpen: false
});
export const POST: RequestHandler = ({ request }) => handleChallenge(request);2. Verify-Route
Datei: src/routes/api/truesift/verify/+server.ts
import { env } from '$env/dynamic/private';
import type { RequestHandler } from './$types';
import { createTrueSiftVerifyHandler } from '@truesift/svelte/server';
const handleVerify = createTrueSiftVerifyHandler({
apiBaseUrl: env.TRUESIFT_API_BASE_URL,
siteKey: env.TRUESIFT_SITE_KEY,
secretKey: env.TRUESIFT_SECRET_KEY,
defaultAction: env.TRUESIFT_DEFAULT_ACTION,
failOpen: false
});
export const POST: RequestHandler = ({ request }) => handleVerify(request);Beide Endpunkte erwarten JSON-POST-Anfragen und erzwingen Same-Origin-Prüfungen.
3. Vertrauenswürdige Action an die Seite geben
Datei: src/routes/contact/+page.server.ts
import { env } from '$env/dynamic/private';
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = () => {
const action = env.TRUESIFT_DEFAULT_ACTION?.trim();
if (!action) error(500, 'TrueSift action is not configured');
return { truesiftAction: action };
};Client und Business-Route müssen dieselbe Action, denselben Page-Path und denselben Origin verwenden.
4. Svelte-5-Komponente einbinden
Datei: src/routes/contact/+page.svelte
<script lang="ts">
import { TrueSiftCheck } from '@truesift/svelte/client';
import type { TrueSiftClientVerificationResult } from '@truesift/svelte';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
let verificationToken = $state<string | null>(null);
let submitting = $state(false);
let message = $state('');
function handleVerified(result: TrueSiftClientVerificationResult): void {
verificationToken =
result.status === 'verified' &&
result.allowed &&
result.decision === 'allow'
? result.verificationToken ?? null
: null;
}
async function submitContact(): Promise<void> {
if (!verificationToken || submitting) return;
const token = verificationToken;
verificationToken = null; // A verification token cannot be reused.
submitting = true;
message = '';
try {
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
verificationToken: token
// Include validated contact fields from your form.
})
});
message = response.ok
? 'Verification accepted.'
: 'Verification could not be completed. Please try again.';
} catch {
message = 'The request could not be completed. Please verify again.';
} finally {
submitting = false;
}
}
</script>
<TrueSiftCheck
action={data.truesiftAction}
path="/contact"
visualMode="checkbox"
size="normal"
theme="auto"
locale="auto"
onVerified={handleVerified}
onError={() => (verificationToken = null)}
/>
<button type="button" disabled={!verificationToken || submitting} onclick={submitContact}>
Submit
</button>
<p role="status">{message}</p>Der deaktivierte Submit-Button ist lediglich eine UI-Sperre. Die Sicherheitsgrenze ist die Business-Route auf dem Server.
5. Proof vor der Geschäftsaktion prüfen
Datei: src/routes/api/contact/+server.ts
import { json } from '@sveltejs/kit';
import { env } from '$env/dynamic/private';
import type { RequestHandler } from './$types';
import { verifyTrueSiftProof } from '@truesift/svelte/server';
export const POST: RequestHandler = async ({ request, url }) => {
if (request.headers.get('origin') !== url.origin) {
return json({ error: 'Invalid request origin' }, { status: 403 });
}
if (!request.headers.get('content-type')?.includes('application/json')) {
return json({ error: 'Unsupported content type' }, { status: 415 });
}
const body: unknown = await request.json().catch(() => null);
if (typeof body !== 'object' || body === null || Array.isArray(body)) {
return json({ error: 'Invalid request' }, { status: 400 });
}
const { verificationToken } = body as Record<string, unknown>;
const expectedAction = env.TRUESIFT_DEFAULT_ACTION?.trim();
if (!expectedAction) {
return json({ error: 'Verification is unavailable' }, { status: 503 });
}
const proof = await verifyTrueSiftProof(
{
verificationToken: typeof verificationToken === 'string' ? verificationToken : '',
expectedAction,
expectedPath: '/contact',
expectedOrigin: url.origin
},
{
apiBaseUrl: env.TRUESIFT_API_BASE_URL,
siteKey: env.TRUESIFT_SITE_KEY,
secretKey: env.TRUESIFT_SECRET_KEY,
failOpen: false
}
);
if (!proof.ok || !proof.allowed || proof.failOpen) {
return json(
{ error: 'Verification rejected' },
{ status: proof.reason === 'unavailable' ? 503 : 403 }
);
}
// The verification gate has passed. Validate and process the
// contact request here, using your application's business logic.
return json({ verified: true });
};Das Beispiel validiert nur die Verifikation und führt noch keine E-Mail-, Formular- oder Datenbank-Aktion aus. Eigentliche Validierung und Verarbeitung sind nach erfolgreicher Proof-Prüfung zu implementieren. expectedAction, expectedPath und expectedOrigin dürfen niemals aus Browser-JSON stammen.
Darstellung: Modi und Größen
| Eigenschaft | Verfügbare Werte |
|---|---|
visualMode | checkbox, banner, inline, badge |
size | normal, compact, flexible, half |
theme | auto, light, dark |
locale | auto, en, de, bg |
Nur im Svelte SDK: size="half" begrenzt einen visualMode="banner" auf 500 px und passt sich schmaleren Bildschirmen an. Andere Modi verwenden dadurch kein besonderes Halbbreiten-Layout. Diese Größe fehlt im Next.js SDK v0.3.0.
<TrueSiftCheck action={data.truesiftAction} visualMode="banner" size="half" theme="auto" locale="de" />Für einen eigenen Language-Switcher den gewünschten Wert explizit als locale übergeben. Benutzerdefinierte Beschriftungen lassen sich über labels teilweise überschreiben.
Callback und manuelle Steuerung
onReady()wird nach dem Mount aufgerufen.onVerified(result)kann auchreview,blockoder Fail-Open enthalten. Nurstatus === 'verified',allowed,decision === 'allow'und der Token sind relevante Browserhinweise; die endgültige Entscheidung bleibt serverseitig.onError(error)meldet Konfigurations-, Netzwerk- oder Request-Fehler.- Mit
autoStart={false},bind:this,start()undreset()können Sie die Prüfung manuell steuern.
<script lang="ts">
import { TrueSiftCheck } from '@truesift/svelte/client';
import type { TrueSiftCheckActions } from '@truesift/svelte/client';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
let check = $state<TrueSiftCheckActions | undefined>();
</script>
<TrueSiftCheck bind:this={check} action={data.truesiftAction} autoStart={false} />
<button type="button" onclick={() => void check?.start()}>Verify</button>
<button type="button" onclick={() => check?.reset()}>Reset</button>Ein verwendeter Token ist auch nach reset() nicht erneut verwendbar.
Headless Svelte-5-Controller
Ohne die visuelle Komponente stellt createTrueSiftCheck die States state, challenge, verification, error, isLoading sowie activate(), start(), reset() und destroy() bereit.
<script lang="ts">
import { onMount } from 'svelte';
import { createTrueSiftCheck } from '@truesift/svelte/client';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
const check = createTrueSiftCheck(() => ({
action: data.truesiftAction,
path: '/contact'
}));
onMount(() => {
check.activate();
return () => check.destroy();
});
</script>
<button type="button" disabled={check.isLoading} onclick={() => void check.start()}>
Verify
</button>
<p aria-live="polite">{check.state}</p>Animation, Datenschutz und Content Security Policy
Der TrueSift-Shield mit dotLottie-WebAssembly ist lokal im Paket enthalten, einschließlich Reduced-Motion-Unterstützung und SVG-Fallback. Ein externes Animations-CDN wird nicht benötigt. Für die lokale WASM-Laufzeit kann die CSP script-src 'self' 'wasm-unsafe-eval' benötigen; fügen Sie nicht pauschal 'unsafe-eval' hinzu.
Behavioral Signals v2
@truesift/svelte@0.2.0 verwendet aggregierte Behavioral Signals v2, abgestimmt auf @truesift/next@0.4.0. Ältere v1-Signale bleiben kompatibel. Der Svelte-5-Controller startet nach der Challenge eine abbrechbare 2.500-ms-Beobachtung (gemessen ab Beginn des Verifikationsversuchs) mit einer eigenen Interaktionsbasis pro Challenge. Reset, Unmount und Abbruch stoppen Wartezeiten und entfernen Event-Listener.
Die temporäre Momentaufnahme kann telemetryVersion: 2, elapsedMs, interactionCount, challengeInteractionCount, pointerMoveCount, pointerDownCount, scrollCount, touchCount, keyPressCount, focusCount, blurCount, visibilityChangeCount, firstInteractionDelayMs und activeDurationMs enthalten. Pointerbewegungen und Scrolls werden alle 75 ms abgetastet; Zähler sind auf 1.000 begrenzt. Ein Null-Interaktionssignal wird erst nach mindestens 1.000 ms sichtbarer Beobachtung ausgegeben. Ein einzelnes Signal beweist weder Mensch noch Bot.
Es werden keine Tasteneingaben, Pointerkoordinaten, Formularwerte, DOM-Ziele, Fingerprints oder dauerhaften Besucherkennungen erfasst. Die aggregierten Werte gelangen nur über die Same-Origin-SvelteKit-Routen zum Server. referrer und currentPageUrl enthalten ausschließlich die Origins, keine Pfade oder Query-Parameter. Der standardmäßige Proof-Pfad enthält nur location.pathname; explizit gesetzte path-Werte bleiben aus Kompatibilitätsgründen unverändert. Keine Zugangsdaten in benutzerdefinierte Pfade aufnehmen.
Absicherung der SvelteKit-BFF-Routen in 0.2.0
- Challenge und Verify akzeptieren nur JSON-
POST, prüfen den Browser-Originstreng, berücksichtigen Same-Origin-Fetch-Metadata und begrenzen den Request-Body auf 32 KiB. Reverse-Proxies müssen den öffentlichen Origin erhalten. - Behavioral-Felder sind validiert und begrenzt; durch Clients steuerbare Kontextwerte werden nicht in Upstream-Warnlogs aufgenommen. Rohe Upstream-Fehlermeldungen werden nicht weitergereicht.
- Entfernte Upstreams erfordern HTTPS; HTTP ist nur für lokales Loopback (
localhost,127.0.0.1,[::1]) zulässig. - BFF-Antworten setzen
Cache-Control: no-storeundX-Content-Type-Options: nosniff. - Widersprüchliche Verifikationsentscheidungen und fehlerhafte Proof-Antworten werden abgelehnt; Protokollfehler dürfen kein Fail-Open auslösen.
- Geschützte Geschäftsaktionen erfordern weiterhin einen serverseitig geprüften und einmalig verbrauchten Proof.
Versionshinweise: 0.2.0 (12.10.2026)
Behavioral Signals v2, abbrechbare Beobachtung, verschärfte Origin- und Größenprüfungen, URL-Datenschutz, robuste Fehlerbehandlung und zusätzliche adversariale Regressionstests. Die öffentliche Svelte-5-Komponenten-API und der Same-Origin-POST/JSON-Ablauf bleiben erhalten.
Proof-Ergebnisse und Sicherheitsregeln
ok: true,allowed: true,decision: 'allow',failOpen: false: autoritativer Proof.reason: 'missing' | 'invalid' | 'expired' | 'replayed' | 'mismatch': nicht akzeptieren.decision: 'review' | 'block'undreason: 'blocked': nicht akzeptieren.reason: 'unavailable': beifailOpen: falseablehnen; beifailOpen: truekein autoritativer Proof trotzallowed: true.
Geschützte Aktionen nur bei proof.ok && proof.allowed && !proof.failOpen ausführen. Tokens sind kurzlebig, einmalig nutzbar und stets gegen die erwartete serverseitige Action, Origin und Path zu prüfen. CSRF, Autorisierung, Rate Limiting und die Validierung der Geschäftsaktion bleiben Aufgabe der Anwendung.
Lizenz
Der SDK-Code steht unter der MIT-Lizenz. Die mitgelieferte Animation von Maxence Chanel steht unter der separaten Lottie Simple License, nicht unter der MIT-Lizenz von WebDigiTech.