Skip to main content
@cstar.help/svelte v0.9.0

Spell Tome of the Svelte SDK

— This is the way.

Providers

<!-- src/routes/+layout.svelte -->
<script>
  import { CStarChatProvider, CStarLibraryProvider } from '@cstar.help/svelte';
  let { children } = $props();
</script>

<CStarLibraryProvider teamSlug="acme">
  <CStarChatProvider teamSlug="acme">
    {@render children()}
  </CStarChatProvider>
</CStarLibraryProvider>

Library state

const cats = new CategoriesState();
const articles = new ArticlesState(undefined, { categorySlug: 'billing' });
const search = new ArticleSearchState();

// Single article? No per-article class — load it in +page.js:
//   const article = await getLibraryClient().article(slug);

// Read fields directly in markup
{#each articles.articles as a (a.id)}...{/each}

Chat state

const chat = new ChatState();
const tix = new TicketsState();           // no params arg — fetches the full list
const messages = new MessagesState(undefined, ticketId);
const typing = new TypingState(undefined, ticketId);

await chat.identify(customer, signature);
await tix.create({ title: 'Help' });
await messages.send(draft);

Cleanup

import { onDestroy } from 'svelte';

// destroy() exists on classes that open subscriptions:
//   MessagesState, TypingState, ArticleSearchState
const messages = new MessagesState(undefined, ticketId);
onDestroy(() => messages.destroy());

// ChatState, TicketsState, ArticlesState, CategoriesState
// have no subscriptions — nothing to tear down.

Tear down only what subscribes. Lists are fetch-once + reactive fields.

SSR

// Construction is safe on the server — fields are empty until hydration
const articles = new ArticlesState(undefined, { categorySlug: 'billing' });

{#if articles.isLoading}
  <p>Loading…</p>
{:else}
  ...
{/if}

No export const ssr = false needed. State classes skip subscribe-wiring on the server.

Gotchas

  • Client comes first, params second. ArticlesState(client?, params?) and MessagesState(client, ticketId). Pass undefined as the client to use the provider's.
  • ticketId is positional. Pass a string, not a thunk — the class throws a typed TypeError with a hint.
  • Destroy only the subscribers. destroy() exists on MessagesState, TypingState, and ArticleSearchState. The list/lookup classes don't have it.
  • Single-instance pattern. Don't new the same state class in a loop body — it'll re-fetch on every render.
  • Realtime is opt-in via the provider. Pass realtime=false on CStarChatProvider to force polling.