page.tsx179 lines · main
1import { DocsShell } from '../../components/shell';
2
3export const metadata = { title: 'client sdks' };
4
5interface Sdk {
6 pkg: string;
7 framework: string;
8 pitch: string;
9 setup: string;
10 useExample: string;
11 notes?: string;
12}
13
14const SDKS: readonly Sdk[] = [
15 {
16 pkg: '@briven/react',
17 framework: 'react',
18 pitch:
19 'reference 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.',
20 setup: `import { BrivenProvider, createClient } from '@briven/react';
21
22const client = createClient({
23 url: 'https://api.briven.tech',
24 projectId: 'p_xxx',
25 apiKey: process.env.NEXT_PUBLIC_BRIVEN_KEY,
26});
27
28export function Providers({ children }: { children: React.ReactNode }) {
29 return <BrivenProvider client={client}>{children}</BrivenProvider>;
30}`,
31 useExample: `'use client';
32import { useQuery, useMutation } from '@briven/react';
33
34export function Notes() {
35 const { data, isLoading, error } = useQuery<'listNotes', { id: string; body: string }[]>(
36 'listNotes',
37 {},
38 );
39 const create = useMutation<'createNote', { body: string }, { id: string }>('createNote');
40
41 if (isLoading) return <p>loading…</p>;
42 if (error) return <p>{error.message}</p>;
43 return (
44 <>
45 <button onClick={() => create.mutate({ body: 'hello' })}>add</button>
46 <ul>{data?.map((n) => <li key={n.id}>{n.body}</li>)}</ul>
47 </>
48 );
49}`,
50 notes:
51 'useQuery accepts a stable args object — pass primitives, not new objects on every render, or the subscription identity will churn.',
52 },
53 {
54 pkg: '@briven/svelte',
55 framework: 'svelte 5',
56 pitch:
57 "queries 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.",
58 setup: `import { setBrivenClient, createClient } from '@briven/svelte';
59
60const client = createClient({
61 url: 'https://api.briven.tech',
62 projectId: 'p_xxx',
63 apiKey: import.meta.env.VITE_BRIVEN_KEY,
64});
65
66setBrivenClient(client);`,
67 useExample: `<script lang="ts">
68 import { query, mutation } from '@briven/svelte';
69 const notes = query<'listNotes', { id: string; body: string }[]>('listNotes', {});
70 const create = mutation<'createNote', { body: string }, { id: string }>('createNote');
71</script>
72
73{#if $notes.isLoading}loading…{/if}
74{#if $notes.error}{$notes.error.message}{/if}
75<button onclick={() => create.mutate({ body: 'hello' })}>add</button>
76<ul>
77 {#each $notes.data ?? [] as n (n.id)}<li>{n.body}</li>{/each}
78</ul>`,
79 },
80 {
81 pkg: '@briven/vue',
82 framework: 'vue 3',
83 pitch:
84 'composables version of the same surface. `useQuery` returns refs; `watch(stableKey(args))` re-subscribes when arg identity changes. `onScopeDispose` closes the sub on component unmount.',
85 setup: `// main.ts
86import { createApp } from 'vue';
87import { setBrivenClient, createClient } from '@briven/vue';
88
89const client = createClient({
90 url: 'https://api.briven.tech',
91 projectId: 'p_xxx',
92 apiKey: import.meta.env.VITE_BRIVEN_KEY,
93});
94
95setBrivenClient(client);
96createApp(App).mount('#app');`,
97 useExample: `<script setup lang="ts">
98import { useQuery, useMutation } from '@briven/vue';
99const { data, isLoading, error } = useQuery<'listNotes', { id: string; body: string }[]>(
100 'listNotes',
101 {},
102);
103const { mutate } = useMutation<'createNote', { body: string }, { id: string }>('createNote');
104</script>
105
106<template>
107 <p v-if="isLoading">loading…</p>
108 <p v-else-if="error">{{ error.message }}</p>
109 <button @click="mutate({ body: 'hello' })">add</button>
110 <ul><li v-for="n in data ?? []" :key="n.id">{{ n.body }}</li></ul>
111</template>`,
112 },
113];
114
115export default function SdkPage() {
116 return (
117 <DocsShell>
118 <h1 className="font-mono text-2xl tracking-tight">client sdks</h1>
119 <p className="mt-2 font-mono text-sm text-[var(--color-text-muted)]">
120 three first-party clients with the same surface across react, svelte, and vue. each
121 manages the realtime websocket lifecycle for you — subscribe on first read, re-run
122 on row changes, close when the last consumer drops. you don&apos;t talk to the WS
123 directly.
124 </p>
125
126 <nav className="mt-6 flex flex-wrap gap-2 font-mono text-xs">
127 {SDKS.map((s) => (
128 <a
129 key={s.pkg}
130 href={`#${encodeURIComponent(s.pkg)}`}
131 className="rounded-md border border-[var(--color-border)] px-3 py-1 text-[var(--color-text-muted)] hover:text-[var(--color-text)]"
132 >
133 {s.pkg}
134 </a>
135 ))}
136 </nav>
137
138 <section className="mt-8 rounded-md border border-[var(--color-border-subtle)] bg-[var(--color-surface)] p-4 font-mono text-xs text-[var(--color-text-muted)]">
139 <strong className="text-[var(--color-text)]">key shape:</strong> the api key lives on
140 the client. browser clients use a <code>readonly</code>-scope key (
141 <code>brk_</code>); server SDKs / SSR use a <code>developer</code>-scope key.
142 rotate via the api keys tab in your project — old keys revoke immediately.
143 </section>
144
145 {SDKS.map((s) => (
146 <section
147 key={s.pkg}
148 id={s.pkg}
149 className="mt-10 scroll-mt-20 border-t border-[var(--color-border-subtle)] pt-8"
150 >
151 <div className="flex items-baseline justify-between gap-3">
152 <h2 className="font-mono text-lg tracking-tight">
153 <code>{s.pkg}</code>
154 </h2>
155 <span className="font-mono text-xs text-[var(--color-text-subtle)]">{s.framework}</span>
156 </div>
157 <p className="mt-2 font-mono text-sm text-[var(--color-text-muted)]">{s.pitch}</p>
158
159 <h3 className="mt-5 font-mono text-sm">setup</h3>
160 <pre className="mt-2 overflow-x-auto rounded-md border border-[var(--color-border-subtle)] bg-[var(--color-code-bg)] p-3 font-mono text-xs text-[var(--color-code-text)]">
161 <code>{s.setup}</code>
162 </pre>
163
164 <h3 className="mt-5 font-mono text-sm">use</h3>
165 <pre className="mt-2 overflow-x-auto rounded-md border border-[var(--color-border-subtle)] bg-[var(--color-code-bg)] p-3 font-mono text-xs text-[var(--color-code-text)]">
166 <code>{s.useExample}</code>
167 </pre>
168
169 {s.notes ? (
170 <p className="mt-3 font-mono text-xs text-[var(--color-text-subtle)]">
171 <span className="text-[var(--color-text)]">note: </span>
172 {s.notes}
173 </p>
174 ) : null}
175 </section>
176 ))}
177 </DocsShell>
178 );
179}