@allservices/sdk-svelte
v0.1.0
Published
TanStack Svelte Query hooks and Svelte 5 provider for the AllServices API.
Maintainers
Readme
@allservices/sdk-svelte
TanStack Svelte Query hooks, an <AllServicesProvider> context component, and a <SudoGuard> step-up component for the AllServices API. Built for Svelte 5 with runes and fully compatible with SvelteKit 2.
Status: alpha. Public API may change between minors until
1.0.0. Requires Svelte 5 and@tanstack/svelte-queryv6.
Install
pnpm add @allservices/sdk-svelte @allservices/sdk-core @tanstack/svelte-query svelteSetup
Mount <AllServicesProvider> at your root layout so every descendant component can resolve the TanStack QueryClient and AllServicesClient contexts.
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import { AllServicesProvider } from '@allservices/sdk-svelte';
import type { ClientConfig } from '@allservices/sdk-svelte';
const config: ClientConfig = {
region: 'eu',
credentials: 'include',
};
</script>
<AllServicesProvider {config}>
{@render children()}
</AllServicesProvider>The provider constructs an AllServicesClient and a default QueryClient internally. Pass an existing QueryClient via the optional queryClient prop to share state with other providers in the tree.
Hook usage
Hooks follow the Svelte create* naming convention instead of React's use* prefix. This avoids a collision with Svelte's reserved use: directive namespace; see Hook naming below.
Current user
<script lang="ts">
import { createCurrentUser } from '@allservices/sdk-svelte';
const user = createCurrentUser();
</script>
{#if user.isPending}
<p>Loading…</p>
{:else if user.isError}
<p role="alert">{user.error.message}</p>
{:else}
<p>Signed in as {user.data.email}</p>
{/if}Login mutation
<script lang="ts">
import { createLogin, isMfaChallenge } from '@allservices/sdk-svelte';
const login = createLogin();
let email = $state('');
let password = $state('');
let mfaCode = $state('');
$derived const challenge = login.data && isMfaChallenge(login.data) ? login.data : null;
function submit(e: SubmitEvent) {
e.preventDefault();
login.mutate({ email, password, mfaCode: challenge ? mfaCode : undefined });
}
</script>
<form onsubmit={submit}>
<input bind:value={email} placeholder="Email" autocomplete="username" />
<input type="password" bind:value={password} placeholder="Password" autocomplete="current-password" />
{#if challenge}
<input bind:value={mfaCode} inputmode="numeric" maxlength="6" placeholder="6-digit code" />
{/if}
<button type="submit" disabled={login.isPending}>
{challenge ? 'Verify' : 'Sign in'}
</button>
{#if login.isError}
<p role="alert">{login.error.message}</p>
{/if}
</form>Active sessions
<script lang="ts">
import { createSessions, createRevokeSession } from '@allservices/sdk-svelte';
const sessions = createSessions();
const revoke = createRevokeSession();
</script>
{#each sessions.data ?? [] as session (session.id)}
<div>
<span>{session.userAgent}</span>
<button onclick={() => revoke.mutate(session.id)}>Revoke</button>
</div>
{/each}Infinite security log
<script lang="ts">
import { createInfiniteSecurityLog } from '@allservices/sdk-svelte';
const log = createInfiniteSecurityLog({});
</script>
{#each log.data?.pages ?? [] as page}
{#each page.data as entry (entry.id)}
<p>{entry.eventType} — {entry.createdAt}</p>
{/each}
{/each}
{#if log.hasNextPage}
<button onclick={() => log.fetchNextPage()} disabled={log.isFetchingNextPage}>
Load more
</button>
{/if}<SudoGuard>
Wrap any action that may raise SudoRequiredError in <SudoGuard>. The component catches the error, defers the original action, and exposes isSudoRequired / resolveSudo / cancelSudo render-prop state so you can prompt for credentials and replay.
<script lang="ts">
import { SudoGuard, createDeleteMe } from '@allservices/sdk-svelte';
const deleteMe = createDeleteMe();
</script>
<SudoGuard>
{#snippet children({ run, isSudoRequired, resolveSudo, cancelSudo, isPending })}
<button onclick={() => run(() => deleteMe.mutateAsync())}>
Delete account
</button>
{#if isSudoRequired}
<SudoPrompt onSubmit={resolveSudo} onCancel={cancelSudo} {isPending} />
{/if}
{/snippet}
</SudoGuard>Accessing the client and auth state
Two accessor helpers are available outside component context (e.g. in utility modules):
import { getAllServicesClient, getAuthState } from '@allservices/sdk-svelte';
// Returns the AllServicesClient from the nearest AllServicesProvider context.
const client = getAllServicesClient();
// Returns a reactive AuthState rune: { user, isAuthenticated, isLoading }.
const auth = getAuthState();Both functions must be called during component initialisation (same constraint as Svelte's getContext).
Hook naming
AllServices follows Svelte community convention and names all query/mutation factories with a create* prefix (e.g. createCurrentUser, createLogin, createSessions). The React adapter uses use* for the same hooks. The reason is that Svelte reserves the use: directive namespace — a function named useCurrentUser is syntactically valid but creates confusion when readers scan .svelte files expecting directives. Keeping the prefix distinct makes intent immediately clear.
Full hook coverage
Every domain in @allservices/sdk-core has corresponding hooks: auth (login, register, MFA, sessions, sudo, panic, trusted devices, recovery, PATs, security log), users, roles, careers, webhooks, licensing, assets, identity providers, required actions, and health. Suspense variants (e.g. createCurrentUserSuspense) and infinite variants (e.g. createInfiniteSecurityLog, createInfiniteUsers) are included.
SSR with SvelteKit
See @allservices/sdk-sveltekit for hooks.server.ts middleware, +page.server.ts prefetch patterns, <HydrationBoundary>, and cookie helpers.
Reference app
The SvelteKit reference application at examples/sveltekit-app/ exercises every cross-cutting concern end-to-end: server prefetch + hydration, form actions, SudoGuard, infinite queries, and webhook verification.
Test utilities
See @allservices/sdk-testing-svelte for MockAllServicesProvider, renderWithSvelteProviders, and re-exports of MSW handlers and fixtures.
Documentation
See the main README.
License
UNLICENSED — internal AllServices use only.
