TrueSift SDK за Svelte 5 и SvelteKit
Тази документация е само за @truesift/svelte, а не за @truesift/next. Svelte SDK използва нативни API на Svelte 5, но следва същия протокол за верификация и визуален дизайн като Next.js SDK. Публикувана версия: 0.2.0.
- npm пакет
@truesift/svelte - Избор на SDK
- Общо интерактивно демо (реализирано с React SDK)
Изисквания и инсталация
Необходими са Svelte 5 и Node.js >=20.19.0 според metadata на пакета. Примерите са за SvelteKit със сървърни маршрути.
pnpm add @truesift/svelteАлтернатива: npm install @truesift/svelte.
Импорти и публични entry points
| Път | Предназначение |
|---|---|
@truesift/svelte | Компонент, контролер и типове за клиента |
@truesift/svelte/client | TrueSiftCheck, createTrueSiftCheck и визуални помощни функции |
@truesift/svelte/server | Handler-и за маршрути и verifyTrueSiftProof |
@truesift/svelte/shared | Общи протоколни типове |
@truesift/svelte/styles.css | Незадължителен stylesheet - компонентът сам импортва стиловете си |
import { TrueSiftCheck, createTrueSiftCheck } from '@truesift/svelte/client';
import { createTrueSiftChallengeHandler, createTrueSiftVerifyHandler, verifyTrueSiftProof } from '@truesift/svelte/server';Не импортирайте /server в клиентски Svelte компоненти.
Сървърни променливи на средата
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=2500Base URL е само origin на TrueSift API, без /api/v1. SITE_KEY и SECRET_KEY са задължителни. В SvelteKit тайните се четат чрез $env/dynamic/private или друг защитен сървърен източник и *никога чрез `PUBLIC_**. По подразбиране политиката е **fail-closed (false`)**, а timeout - 2500 ms (валидни стойности 250–30000 ms).
Поток на верификацията
- Браузърът изпраща заявка към локалния same-origin маршрут
/api/truesift/challenge. - Компонентът извиква
/api/truesift/verifyи при успешна проверка получава краткоживеещverificationToken. - Защитеният business route валидира еднократния токен чрез
verifyTrueSiftProofсъс зададени от сървъра Action, Path и Origin. - Действието се изпълнява само след валиден сървърен proof. Клиентски резултат
allowне разрешава сам по себе си действие.
Интеграция със SvelteKit
1. Challenge маршрут
Файл: 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 маршрут
Файл: 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);Двата маршрута очакват JSON POST заявки и прилагат same-origin проверки.
3. Подаване на доверен Action към страницата
Файл: 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 };
};Страницата и защитеният маршрут трябва да съвпадат по Action, Path и Origin.
4. Svelte 5 компонент
Файл: 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>Забраняването на Submit бутона е само UX ограничение. Защитата реално се налага от сървърния маршрут.
5. Проверка на proof преди бизнес действието
Файл: 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 });
};Показаният handler демонстрира единствено TrueSift проверката, не изпраща имейл и не записва формуляр или данни. Реалната бизнес валидация и запис трябва да се изпълнят след успешния proof. expectedAction, expectedPath и expectedOrigin идват само от доверения сървър, не от клиентски JSON.
Визуални режими, размери и език
| Свойство | Стойности |
|---|---|
visualMode | checkbox, banner, inline, badge |
size | normal, compact, flexible, half |
theme | auto, light, dark |
locale | auto, en, de, bg |
Само за Svelte SDK: size="half" ограничава банера (visualMode="banner") до 500 px максимална ширина и остава адаптивен на малки екрани. Не променя останалите режими. Този размер липсва в Next.js SDK v0.3.0.
<TrueSiftCheck action={data.truesiftAction} visualMode="banner" size="half" theme="auto" locale="bg" />При собствен language switcher подавайте избрания език чрез locale, вместо auto. Текстовете могат да се заменят частично чрез labels.
Callback-и и ръчно управление
onReady()- извиква се след mount.onVerified(result)- може да се извика и приreview,blockи fail-open. Клиентският статус не замества сървърния proof.onError(error)- съобщава за грешки при заявки, конфигурация или мрежа.- С
autoStart={false},bind:this,start()иreset()можете да контролирате ръчно проверката.
<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>reset() не прави вече употребен verification token валиден повторно.
Headless контролер за Svelte 5
createTrueSiftCheck работи без визуалния компонент. Предоставя реактивни state, challenge, verification, error, isLoading, както и activate(), start(), reset() и destroy().
<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>Анимация, поверителност и CSP
В пакета са включени локални dotLottie анимация и WebAssembly runtime, поддръжка на reduced-motion и SVG fallback. Не е нужен външен CDN за анимацията. CSP може да изисква script-src 'self' 'wasm-unsafe-eval' за локалния WASM runtime; не добавяйте без нужда 'unsafe-eval'.
Behavioral Signals v2
@truesift/svelte@0.2.0 използва агрегирани Behavioral Signals v2, съвместими с протокола на @truesift/next@0.4.0. По-старите v1 сигнали продължават да се приемат. След challenge Svelte 5 контролерът използва прекъсваем прозорец за наблюдение от 2500 ms (измерван от началото на опита за проверка), с отделна базова линия за взаимодействията за всеки challenge. Reset, unmount и отмяна прекратяват изчакването и премахват слушателите на събития.
Временните агрегати могат да включват telemetryVersion: 2, elapsedMs, interactionCount, challengeInteractionCount, pointerMoveCount, pointerDownCount, scrollCount, touchCount, keyPressCount, focusCount, blurCount, visibilityChangeCount, firstInteractionDelayMs и activeDurationMs. Движенията на курсора и scroll се семплират през 75 ms, а броячите са ограничени до 1000. Отчет за нулево взаимодействие се изпраща само след най-малко 1000 ms видимо наблюдение. Отделен сигнал не доказва дали посетителят е човек или бот.
Не се записват натиснати клавиши, координати, стойности от формуляри, DOM цели, fingerprints или постоянни идентификатори. До сървъра през same-origin SvelteKit BFF се предават само агрегати. Метаданните referrer и currentPageUrl съдържат само origin, без пътища, query параметри или fragments. По подразбиране proof path е pathname без query; изрично зададен path се запазва за съвместимост със съществуващите expectedPath договори. Не поставяйте токени в персонализирани пътища.
Защита на SvelteKit BFF във версия 0.2.0
- Challenge и verify маршрутите приемат само JSON
POST, проверяват строго браузърнияOriginи same-origin Fetch Metadata, когато е подадена, и ограничават тялото до 32 KiB. Reverse proxy трябва да запазва публичния origin. - Поведенческите полета се валидират и ограничават; управлявани от клиента контекстни стойности не се включват в предупрежденията към upstream логовете. Сурови съобщения за upstream грешки не се разкриват.
- Външните upstream сървъри изискват HTTPS; HTTP е допустим само за локален loopback (
localhost,127.0.0.1,[::1]). - BFF отговорите включват
Cache-Control: no-storeиX-Content-Type-Options: nosniff. - Противоречиви решения за проверка и невалидни proof отговори се отхвърлят; протоколна грешка не може да се превърне във fail-open.
- Защитеното бизнес действие изисква проверен и еднократно използван proof на сървъра; клиентско решение или телеметрия не дават разрешение.
Промени във версия 0.2.0 (12.10.2026)
Добавени са Behavioral Signals v2, прекъсваемо наблюдение, по-строги Origin и размерни ограничения, защита на URL метаданните, безопасна обработка на upstream грешки и допълнителни регресионни тестове. Публичният Svelte 5 API и same-origin POST/JSON интеграцията са запазени.
Резултати от proof и правила за сигурност
ok: true,allowed: true,decision: 'allow',failOpen: false- доказано разрешена проверка.reason: 'missing' | 'invalid' | 'expired' | 'replayed' | 'mismatch'- отказ.decision: 'review' | 'block'заедно сreason: 'blocked'- отказ.reason: 'unavailable'- приfailOpen: falseотказ; приfailOpen: trueняма авторитетен proof, дориallowed: true.
Изпълнявайте защитено действие само при proof.ok && proof.allowed && !proof.failOpen. Токените са краткоживеещи и еднократни. Освен TrueSift запазете проверките за CSRF, авторизация, rate limiting и валидиране на бизнес данните.
Лиценз
Кодът на SDK е под MIT License. Включената анимация е създадена от Maxence Chanel и се разпространява отделно под Lottie Simple License, а не под MIT лиценза на WebDigiTech.