Capsule API

Lakebed Native accepts the same server shapes as web Lakebed and the native array style.

Server (lakebed/server)

import {
  capsule, query, mutation, endpoint,
  table, string, boolean, number, json, text
} from "lakebed/server";

Web-style schema (recommended for cross-platform)

export default capsule({
  name: "my-app",
  schema: {
    todos: table({
      title: text(),
      done: boolean().default(false),
      userId: string(),
    }),
  },
  queries: {
    listTodos: query((ctx) =>
      ctx.db.todos.where("userId", ctx.auth.userId ?? "guest").all()
    ),
  },
  mutations: {
    addTodo: mutation((ctx, args: { title: string }) =>
      ctx.db.todos.insert({ title: args.title, userId: ctx.auth.userId ?? "guest", done: false })
    ),
  },
});

Native array style (still supported)

const todos = table("todos", { title: text(), done: boolean() });
export default capsule({
  name: "my-app",
  tables: [todos],
  queries: [query("listTodos", (ctx) => ctx.db.table("todos").all())],
  mutations: [mutation("addTodo", (ctx, args) => ctx.db.table("todos").insert(args))],
});

Context (web parity)

Field Web Lakebed Native
User id ctx.auth.userId ctx.auth.userId or ctx.auth.user?.id
Display name ctx.auth.displayName ctx.auth.displayName or ctx.auth.user?.name
Avatar — ctx.auth.picture or ctx.auth.user?.avatarUrl
DB ctx.db.todos ctx.db.todos or ctx.db.table("todos")

Rows get auto id, createdAt, and updatedAt on insert/update. Field .default(value) is applied on insert.

Shared imports

Extensionless imports work in dev and build:

import { cleanTitle } from "../shared/habit";

HTTP / WS (local dev)

Client (lakebed-native/client)

import {
  useAuth, useQuery, useMutation, useConnection,
  authAs, signInWithGoogle, signOut, configureClient,
} from "lakebed-native/client";

useQuery(name, args?)

Returns { data, loading, error, refetch }:

const { data: todos, loading, error, refetch } = useQuery<Todo[]>("listTodos");
if (loading) return <Spinner />;
if (error) return <ErrorState title="Could not load" message={error.message} />;

useMutation(name, opts?)

Returns { mutate, loading, error }. Pass { onError, onSuccess } for UI handling.

useAuth()

Returns web-parity fields plus nested user:

{
  user: AuthUser | null;
  userId: string | null;
  displayName: string | null;
  picture: string | null;
  isGuest: boolean;
  loading: boolean;
  error: Error | null;
  refresh: () => Promise<void>;
}

Updates automatically on auth-changed (local WS) and hosted auth refresh. After authAs(), call refresh() if needed on HTTP-only paths.

Connection / offline

useConnection() — { status: "connected" | "disconnected" | "connecting", error, retry } for dead server / offline UX.

configureClient({ serverUrl: "http://localhost:3000" });

Assets

Place images under assets/ and reference by URI in dev, or use remote URLs:

import { Image } from "lakebed-native/ui";
<Image source={{ uri: "https://example.com/photo.jpg" }} />

Typecheck

npx lakebed-native typecheck

Runs tsc --noEmit on app/ and shared/.