ChatState

A little Svelte state for a real conversation. Identify a customer from your app and let your support crew meet them in the interface you built.

Give chat a home.

Wrap your chat interface in CStarChatProvider, then construct ChatState inside a child component. Without an explicit client, it uses the nearest provider.

Support.svelte
<script lang="ts">
  import { CStarChatProvider } from '@cstar.help/svelte';
  import ChatHeader from './ChatHeader.svelte';

  let { accountKey }: { accountKey: string } = $props();
</script>

{#key accountKey}
  <CStarChatProvider teamSlug="your-team-slug">
    <ChatHeader />
  </CStarChatProvider>
{/key}

Mount this tree only for the signed-in app session. Make accountKey change when the customer, team or sign-in session changes, including signing back in as the same person. Remove the tree on app sign-out. The provider creates one client from its initial configuration and disconnects when unmounted; changing its props alone does not replace that client.

Connect the customer.

Keep this state instance with the account's chat interface. Read its fields directly in markup so Svelte can update the view.

ChatHeader.svelte
<script lang="ts">
  import { onDestroy } from 'svelte';
  import { ChatState } from '@cstar.help/svelte';

  // Construct during component initialization, inside the provider.
  const chat = new ChatState();
  let busy = $state(false);
  let feedback = $state('');
  let activeRequest: AbortController | null = null;

  onDestroy(() => {
    activeRequest?.abort();
    activeRequest = null;
  });

  async function connect() {
    if (activeRequest) return;
    const request = new AbortController();
    activeRequest = request;
    busy = true;
    feedback = '';
    try {
      // Your authenticated server signs this customer's identity.
      const response = await fetch('/api/cstar-auth', {
        signal: request.signal,
        cache: 'no-store'
      });
      if (!response.ok) throw new Error('Identity unavailable');
      const { customer, signature } = await response.json();
      if (request.signal.aborted) return;
      await chat.identify(customer, signature);
    } catch {
      if (!request.signal.aborted) {
        feedback = "Couldn't connect. Please try again.";
      }
    } finally {
      if (activeRequest === request) {
        activeRequest = null;
        busy = false;
      }
    }
  }
</script>

<section aria-label="Customer support">
  {#if chat.isIdentified}
    <p>You're connected. Your crew is here to help.</p>
    <button type="button" onclick={() => chat.disconnect()}>Disconnect chat</button>
  {:else}
    <button type="button" disabled={busy} onclick={connect}>
      {busy ? 'Connecting…' : 'Connect to support'}
    </button>
  {/if}
  <p role="status">{feedback}</p>
</section>

/api/cstar-auth is a route you build on your server. It must use your verified app session to sign only that customer's identity and return { customer, signature } with Cache-Control: no-store. Keep the identity secret out of browser code. Follow the HMAC signing example for the exact fields and timestamp.

Fields and methods

  • chat.isIdentified becomes true after this instance's identify() succeeds and false when its disconnect() runs.
  • chat.identify(customer, signature) returns the verified customer and session response. It rejects on failure.
  • chat.error holds the latest identify error. Catch the rejected promise in your event handler too.
  • chat.isRealtimeReady is this instance's realtime readiness flag. Message polling can still work without realtime, so don't use it as the gate for all chat.
  • chat.disconnect() clears the underlying chat client and subscriptions, then resets this state. It does not sign the customer out of your app.

ChatState does not expose customer, logout(), client or credential-login methods. Keep display details in your own authenticated app state or use the result from identify().

For direct client access, call getChatClient() during component initialization inside the provider, or pass an explicit ChatClient to new ChatState(client). If you use direct credential or session login, manage that authentication state in your app: this class does not mirror those calls, nor does a newly constructed instance inherit an existing client's identification flag. See the JavaScript authentication guide.

Keep the conversation going.

Add TicketsState for conversations and MessagesState for a selected thread. The customer chat guide covers failed sends, draft preservation and subscription cleanup.