Anvil Cloud / Runtime
Generated client
The builder emits generated client files under .anvil/generated.
The goal is to keep browser code attached to manifest-derived query and mutation metadata instead of hard-coded runtime paths. React/Vite is the current default Cell UI path, and the generated client is the paved road for that path.
Output
.anvil/generated/
api.d.ts
client.ts
client.ts exposes metadata for declared queries and mutations. api.d.ts gives TypeScript a stable shape for generated API names.
Browser client
The browser package is @anvil-cloud/client.
Current responsibilities:
- provide a
createClientfunction - route query and mutation calls to the local or deployed runtime
- avoid hard-coded runtime paths in Cell client code
- attach bearer tokens through
setTokenorgetToken - throw structured
AnvilClientErrorfailures - provide React hook helpers for loading/error state and manual refetch
Direct client use
import { createClient } from "@anvil-cloud/client";
import { api, createAnvilApiClient } from "@anvil/generated/client";
const generated = createAnvilApiClient({
getToken: () => localStorage.getItem("anvil_token")
});
await generated.queries.listNotes({});
await generated.mutations.createNote({
title: "Write docs"
});
The generated helper is the paved road. Use the lower-level client when you need to pass generated definitions around explicitly:
import { createApiClient, createClient } from "@anvil-cloud/client";
import { api } from "@anvil/generated/client";
const client = createClient({
getToken: () => localStorage.getItem("anvil_token")
});
const generated = createApiClient(client, api);
await generated.queries.listNotes({});
By default the runtime URL is the same origin. Pass runtimeUrl when a client
is served from a different origin:
const client = createClient({
runtimeUrl: "https://preview.example.test",
getToken: () => sessionStorage.getItem("token")
});
React hooks
The hook runtime is injected, but React/Vite is the default and documented path.
import * as React from "react";
import { createAnvilHooks, createClient } from "@anvil-cloud/client";
import { api } from "@anvil/generated/client";
const client = createClient({
getToken: () => localStorage.getItem("anvil_notes_token")
});
const { useQuery, useMutation } = createAnvilHooks(client, React);
const notes = useQuery(api.queries.listNotes, {});
const createNote = useMutation(api.mutations.createNote);
await createNote.mutate({ title: "Ship the demo" });
await notes.refetch();
useQuery returns:
status:loading,success, orerrordataerrorrefetch()
useMutation returns:
status:idle,loading,success, orerrordataerrormutate(input)
There is no cache policy layer yet. Invalidation is explicit: call refetch
after a mutation when the visible query data should change.
Runtime target
Client code should not assume the runtime URL by hand. Local and deployed runtime targets should be supplied through the client package and generated metadata.
Hard-coded URLs are easy. They are also how preview, local, and deployed environments slowly become three different products.
In local dev, Vite serves the client and proxies runtime calls back to Anvil Local. In preview, the deployed client can call the preview runtime through the same generated metadata and browser client API.
Auth tokens
For local demos, use the CLI to create a user and mint a token:
anvil cloud auth add-user local_demo --email demo@example.test --roles admin --json
anvil cloud auth token local_demo --json
In a real app, token acquisition belongs to the auth provider. The generated client only needs a token source:
const client = createClient({
getToken: async () => authSession.currentAccessToken()
});
When no token is available, authenticated runtime handlers return
AUTH_REQUIRED.
Errors
Runtime failures throw AnvilClientError. It carries the HTTP status, runtime
code, message, and optional diagnostic details from the runtime payload.
import { isAnvilClientError } from "@anvil-cloud/client";
try {
await client.query(api.queries.listNotes, {});
} catch (error) {
if (isAnvilClientError(error) && error.code === "AUTH_REQUIRED") {
// Ask the auth provider for a fresh session or token.
}
}
Status
Generated client output is part of the alpha builder path. The current surface is
metadata plus small runtime helpers, not a full application data layer. The next
useful work is better typed examples, clearer token handling, and cache
invalidation patterns around examples/notes.