@kizaki/sdk/browser
Browser-side query builders, auth functions, and the browser client for live data.
@kizaki/sdk/browser is the browser-side query surface. It provides the same select and filter functions as the server SDK, but builds query objects for one-shot fetches or live subscriptions instead of executing directly.
Query Builders
Browser query builders mirror the server SDK. Build a query with select, apply filters with where, pass the result to a client method or React hook.
import { select, eq } from "@kizaki/sdk/browser";
import { Project } from "@kizaki/schema";
const activeProjects = select(Project)
.fields(Project.id, Project.name, Project.createdAt)
.where(eq(Project.ownerId, userId))
.orderBy(Project.createdAt, "desc")
.limit(50);All filter functions are available: eq, neq, gt, gte, lt, lte, like, ilike, inArray, notInArray, isNull, isNotNull, plus and, or, not.
Query builder objects are inert descriptions. They do not execute until passed to a client method or hook.
BrowserKizakiClient
The underlying connection to the platform. Manages WebSocket subscriptions, caching, and presence channels.
Creating a Client
import { createBrowserClient, getDefaultBrowserClient } from "@kizaki/sdk/browser";
// New instance
const client = createBrowserClient();
// Shared default (used automatically by React hooks)
const defaultClient = getDefaultBrowserClient();Most applications do not need to create a client directly. React hooks and KizakiProvider manage this automatically. Direct access is useful for non-React frameworks or fine-grained control.
Client Methods
| Method | Purpose |
|---|---|
fetch(builder) | One-shot query. Returns { rows, totalCount } |
subscribe(builder, listener) | Live query. Listener receives { status, rows, error } on every change |
getSnapshot(builder) | Current cached state without triggering a fetch |
invalidate(builder?) | Force refetch of a specific query, or all queries if omitted |
updateQuery(builder, updater) | Optimistic update. Returns a rollback function |
joinPresence(channel, id?) | Presence tracking. Returns { count, subscribe } |
joinBroadcast(channel, id?) | Ephemeral messaging. Returns { send, lastMessage, subscribe } |
close() | Disconnect the WebSocket and release resources |
One-Shot Fetch
const { rows, totalCount } = await client.fetch(
select(Project).fields(Project.id, Project.name).limit(10)
);Live Subscription
import { createBrowserClient, select } from "@kizaki/sdk/browser";
import { Message } from "@kizaki/schema";
const client = createBrowserClient();
const sub = client.subscribe(
select(Message)
.fields(Message.id, Message.text, Message.createdAt)
.orderBy(Message.createdAt, "desc"),
(state) => {
if (state.status === "loading") showSpinner();
if (state.status === "success") renderMessages(state.rows);
if (state.status === "error") showError(state.error);
}
);
// Later:
sub.unsubscribe();The listener fires immediately with cached state (if any), then again on every server-side change via WebSocket.
Optimistic Updates
Update cached state before the server confirms. updateQuery returns a rollback function.
const rollback = client.updateQuery(
select(Project).orderBy(Project.createdAt, "desc"),
(current) => ({
...current,
rows: [{ id: "temp", name: "New Project", createdAt: new Date() }, ...current.rows],
})
);
// If the server mutation fails:
rollback();Auth Functions
Browser auth helpers are re-exported from @kizaki/sdk/auth:
login,signup,logout,getSession,getSessionSync,refreshSessiongetAuthConfigloginWithGoogle,loginWithGithub,loginWithProviderforgotPassword,resetPasswordonAuthStateChangelistAuthMethods,linkPassword,linkProvider,unlinkMethod
See the Auth reference for full documentation.
Browser Integration Helpers
Managed integration lifecycle helpers:
listIntegrations()getIntegrationStatus(key)beginIntegrationConnect(key, returnTo?)beginIntegrationUpgrade(key, "write", returnTo?)disconnectIntegration(key)
These manage connection lifecycle only. They return status and redirect into provider consent flows but never expose provider access tokens to browser code.
Provider-specific operation helpers like googleCalendar("calendar").getFreeBusy(...) are server-only and live in @kizaki/google.
import {
listIntegrations,
beginIntegrationConnect,
beginIntegrationUpgrade,
} from "@kizaki/sdk/browser";
const integrations = await listIntegrations();
if (!integrations.find((item) => item.key === "calendar")?.connected) {
await beginIntegrationConnect("calendar", "/settings");
}
await beginIntegrationUpgrade("calendar", "write", "/settings");See Inspire Integrations for the schema-side declaration.
Presence
Presence channels track connected user counts for a shared context (document, room, dashboard).
const presence = client.joinPresence("document", docId);
// Current count
console.log(presence.count);
// Subscribe to changes
const unsub = presence.subscribe((count) => {
updateViewerCount(count);
});
// Later:
unsub();Broadcast
Broadcast channels send ephemeral messages to all connected users on a channel. Messages are not persisted. Common uses: cursor positions, typing indicators, collaborative selections.
const broadcast = client.joinBroadcast("document", docId);
// Send to all other users
broadcast.send({ type: "cursor", x: 100, y: 200 });
// Most recent incoming message
console.log(broadcast.lastMessage);
// Subscribe to incoming messages
const unsub = broadcast.subscribe((message) => {
if (message.type === "cursor") drawRemoteCursor(message);
});
// Later:
unsub();Broadcast is fire-and-forget. Disconnected users do not receive missed messages.
Related guide: Realtime