client sdks
three first-party clients with the same surface across react, svelte, and vue. each manages the realtime websocket lifecycle for you — subscribe on first read, re-run on row changes, close when the last consumer drops. you don't talk to the WS directly.
readonly-scope key (brk_); server SDKs / SSR use a developer-scope key. rotate via the api keys tab in your project — old keys revoke immediately.@briven/react
reactreference client. `useQuery` re-runs on row changes via the realtime WS; `useMutation` is the same shape as TanStack Query so the api curve is short.
setup
import { BrivenProvider, createClient } from '@briven/react';
const client = createClient({
url: 'https://api.briven.tech',
projectId: 'p_xxx',
apiKey: process.env.NEXT_PUBLIC_BRIVEN_KEY,
});
export function Providers({ children }: { children: React.ReactNode }) {
return <BrivenProvider client={client}>{children}</BrivenProvider>;
}use
'use client';
import { useQuery, useMutation } from '@briven/react';
export function Notes() {
const { data, isLoading, error } = useQuery<'listNotes', { id: string; body: string }[]>(
'listNotes',
{},
);
const create = useMutation<'createNote', { body: string }, { id: string }>('createNote');
if (isLoading) return <p>loading…</p>;
if (error) return <p>{error.message}</p>;
return (
<>
<button onClick={() => create.mutate({ body: 'hello' })}>add</button>
<ul>{data?.map((n) => <li key={n.id}>{n.body}</li>)}</ul>
</>
);
}note: useQuery accepts a stable args object — pass primitives, not new objects on every render, or the subscription identity will churn.
@briven/svelte
svelte 5queries return a Readable store that fires while you're subscribed; the WS closes when the last consumer drops. svelte's reference-counted store contract does the lifecycle for us.
setup
import { setBrivenClient, createClient } from '@briven/svelte';
const client = createClient({
url: 'https://api.briven.tech',
projectId: 'p_xxx',
apiKey: import.meta.env.VITE_BRIVEN_KEY,
});
setBrivenClient(client);use
<script lang="ts">
import { query, mutation } from '@briven/svelte';
const notes = query<'listNotes', { id: string; body: string }[]>('listNotes', {});
const create = mutation<'createNote', { body: string }, { id: string }>('createNote');
</script>
{#if $notes.isLoading}loading…{/if}
{#if $notes.error}{$notes.error.message}{/if}
<button onclick={() => create.mutate({ body: 'hello' })}>add</button>
<ul>
{#each $notes.data ?? [] as n (n.id)}<li>{n.body}</li>{/each}
</ul>@briven/vue
vue 3composables version of the same surface. `useQuery` returns refs; `watch(stableKey(args))` re-subscribes when arg identity changes. `onScopeDispose` closes the sub on component unmount.
setup
// main.ts
import { createApp } from 'vue';
import { setBrivenClient, createClient } from '@briven/vue';
const client = createClient({
url: 'https://api.briven.tech',
projectId: 'p_xxx',
apiKey: import.meta.env.VITE_BRIVEN_KEY,
});
setBrivenClient(client);
createApp(App).mount('#app');use
<script setup lang="ts">
import { useQuery, useMutation } from '@briven/vue';
const { data, isLoading, error } = useQuery<'listNotes', { id: string; body: string }[]>(
'listNotes',
{},
);
const { mutate } = useMutation<'createNote', { body: string }, { id: string }>('createNote');
</script>
<template>
<p v-if="isLoading">loading…</p>
<p v-else-if="error">{{ error.message }}</p>
<button @click="mutate({ body: 'hello' })">add</button>
<ul><li v-for="n in data ?? []" :key="n.id">{{ n.body }}</li></ul>
</template>