@lyeve-labs/client-svelte
v0.1.10
Published
Svelte 5 reactive stores for the LyEve Core API - thin wrapper around @lyeve-labs/client using $state runes
Readme
@lyeve-labs/client-svelte
Svelte 5 reactive stores for the LyEve CMS API. Thin wrapper around
@lyeve-labs/client using Svelte 5 runes ($state).
pnpm add @lyeve-labs/client @lyeve-labs/client-svelte<script lang="ts">
import { createCmsClient, createAsyncStore } from '@lyeve-labs/client-svelte';
import { getSchemas } from '@lyeve-labs/client-rest';
const client = createCmsClient({
baseUrl: 'https://cms.example.com',
getHeaders: () => ({ Authorization: `Bearer ${token}` }),
});
const schemas = createAsyncStore((client) => getSchemas(client), client);
</script>
{#if schemas.loading}
<p>Loading...</p>
{:else if schemas.error}
<p>Error: {schemas.error.message}</p>
{:else}
<ul>
{#each schemas.data ?? [] as schema}
<li>{schema.name}</li>
{/each}
</ul>
{/if}No Provider needed. Create a client, pass it in, done.
What's in the box
- createCmsClient: factory that returns a configured
HttpClientwith base URL and dynamic headers. - createAsyncStore: reactive async data store built on
$state. Returns{ data, error, loading, refetch }. All reactive, no boilerplate. - createMutation: a mutation that runs on demand. Returns reactive
{ data, error, loading }and arun(vars)trigger. - createAuthStore: auth state store with reactive
user,token, andisAuthenticated.setUserrecords a login,cleara logout, andloadasks/api/admin/auth/mewho the session cookie belongs to. - Svelte 5 native: built on runes. No legacy stores, no
writable.
Requirements
- Node 24 or newer
- Svelte 5.0 or newer
- @lyeve-labs/client
>=0.2.1
Install
pnpm add @lyeve-labs/client @lyeve-labs/client-svelte
# or npm install @lyeve-labs/client @lyeve-labs/client-svelte
# or yarn add @lyeve-labs/client @lyeve-labs/client-svelteThe examples below fetch through the REST helpers, which ship separately. Add
@lyeve-labs/client-rest if you want them, or pass any fetcher of your own.
Use
Data fetching
<script lang="ts">
import { createCmsClient, createAsyncStore } from '@lyeve-labs/client-svelte';
import { getSchemas } from '@lyeve-labs/client-rest';
const client = createCmsClient({
baseUrl: 'https://cms.example.com',
getHeaders: () => ({ Authorization: `Bearer ${token}` }),
});
const schemas = createAsyncStore((c) => getSchemas(c), client);
</script>
{#if schemas.loading}
<p>Loading...</p>
{:else if schemas.error}
<p>Error: {schemas.error.message}</p>
{:else}
<ul>
{#each schemas.data ?? [] as schema}
<li>{schema.name}</li>
{/each}
</ul>
{/if}
<button onclick={() => schemas.refetch()}>Reload</button>Authentication
<script lang="ts">
import { createCmsClient, createAuthStore } from '@lyeve-labs/client-svelte';
const client = createCmsClient({ baseUrl: 'https://cms.example.com' });
const auth = createAuthStore(client);
function handleLogin(e: SubmitEvent) {
e.preventDefault();
const data = new FormData(e.target as HTMLFormElement);
const credentials = {
email: data.get('email') as string,
password: data.get('password') as string,
};
// Call your auth endpoint, then store the result:
const user = { id: '1', email: credentials.email, roles: ['admin'] };
auth.setUser(user, 'jwt-token');
}
</script>
{#if !auth.isAuthenticated}
<form onsubmit={handleLogin}>
<input type="email" name="email" required />
<input type="password" name="password" required />
<button type="submit">Log in</button>
</form>
{:else}
<p>Welcome, {auth.user?.email}</p>
<button onclick={() => auth.clear()}>Log out</button>
{/if}API
createCmsClient(config)
function createCmsClient(config: {
baseUrl?: string;
getHeaders?: () => Record<string, string>;
}): HttpClient;createAsyncStore(fetcher, client)
function createAsyncStore<T>(
fetcher: (client: HttpClient) => Promise<T>,
client: HttpClient,
): {
data: T | null;
error: Error | null;
loading: boolean;
refetch: () => void;
};All fields are reactive ($state rune).
createMutation(mutator, client)
function createMutation<T, V>(
mutator: (client: HttpClient, vars: V) => Promise<T>,
client: HttpClient,
): {
data: T | null;
error: Error | null;
loading: boolean;
run: (vars: V) => Promise<T>;
};The mutation does not fire until run is called. run rethrows the error
after recording it in error.
createAuthStore(client)
interface AuthState {
user: { id: string; email: string; roles: string[] } | null;
token: string | null;
}
function createAuthStore(client: HttpClient): {
user: AuthState["user"];
token: string | null;
isAuthenticated: boolean;
setUser: (user: AuthState["user"], token: string | null) => void;
clear: () => void;
load: () => Promise<void>;
};isAuthenticated is true while a user is known or a token is held. load()
fetches /api/admin/auth/me and sets user on success, so a session restored
from a cookie is authenticated even though the page holds no token.
Local development
pnpm install # install dependencies
pnpm test # run unit tests
pnpm check # type-check
pnpm build # tsup + publint -> dist/Project layout
src/
index.ts # public API (re-exports)
index.svelte.ts # Svelte 5 entry point
runes.svelte.ts # createAsyncStore, createMutation, createAuthStore
ambient.d.ts # type declarations
tests/ # vitest test suiteVersioning
@lyeve-labs/client-svelte follows SemVer. While under 1.0,
breaking changes bump the minor version. Additive changes bump the patch.
Every release is logged in CHANGELOG.md.
Contributing
Bug reports and feature requests are welcome. See
CONTRIBUTING.md for the development setup and conventions.
License
MIT. See LICENSE.
