@impetik/xeer
v0.2.18
Published
Xeer: a framework for building and shipping full-stack apps. Typed server, reactive client, database, auth, tests, one-command deploy.
Maintainers
Readme
Xeer
A framework for building and shipping full-stack apps.
Xeer gives you a typed server, a reactive client, a database, authentication, and a test runner that already know about each other — then puts the whole thing on a real URL with one command. No bundler to configure, no database to provision, no CI to write.
📖 Documentation: docs.xeer.run
npx @impetik/xeer new my-app
cd my-app && npm install
npx xeer dev # local server, instant feedback
npx xeer test # the suite that ships with your app
npx xeer deploy # a real URL on a global edge networkQuickstart
1. Create an app
npx @impetik/xeer new my-app
cd my-app
npm installNothing to install first. npm install then puts Xeer in the project, so npx xeer <command> resolves
the local copy, and npm run dev / npm test work for anyone who clones the repository.
Keep the scope. A bare
npx xeerlooks for a package literally namedxeer, which is not this one, andnpx xis an unrelated package entirely. Want it on yourPATH?npm install --global @impetik/xeer, then drop thenpxfrom everything below.
xeer new writes a complete working notes app: a manifest, a typed server, a Preact client, styles, and
a passing test suite. --template <notes|todo|blog|personal-site> starts from one of the others — a
per-user task list, a blog that is public to read and private to write, or a static personal site with no
database at all. Every template checks, tests, and builds clean, and none scaffolds sign-in UI.
2. Run it
npx xeer devYour client and server run together locally, with a real database and a verified identity for every request — no account, no network, no sign-in screen. Client edits hot-reload; server edits recompile behind a health check.
Add "budgets": { "liveConnections": 100 } to xeer.app.json, then open two windows: add a note in
one and it appears in the other immediately. Pushing a write to other people's clients is opt-in,
because a held-open stream keeps your app resident for as long as a tab is open.
3. Test it
npx xeer testBuilds the app, boots it with fresh isolated state, and runs tests/*.test.ts as three distinct users —
so ownership is asserted rather than assumed.
4. Deploy it
npx xeer auth login # opens a browser, prints a confirmation code
npx xeer deploy # prints your app's URLOr ship to a side-by-side URL first, then promote the exact bundle you looked at:
npx xeer deploy --environment preview
npx xeer promote --receipt review_… # deploy prints the complete idThe programming model
An app is a manifest that declares what it has, a server of typed functions, and a client that reads them and re-renders when they change.
xeer.app.json declares the shape of everything:
{
"format": "xeer.application-source.v0",
"name": "notes",
"entrypoints": { "client": "src/client.tsx", "server": "src/server.ts" },
"database": {
"tables": {
"notes": {
"fields": {
"text": { "type": "string", "maxLength": 500 },
"ownerId": { "type": "string", "maxLength": 128 }
},
"indexes": { "by_owner": ["ownerId"] }
}
}
},
"capabilities": ["database"]
}A capability is a power the app opts into by name, alongside a config block for it — database for
the typed database above, storage for a per-app object store reached as ctx.storage. Declaring one
without the other is an error in both directions, and an undeclared capability simply does not exist in
your app: there is nothing bound and nothing to reach for.
→ docs.xeer.run/guides/capabilities
src/server.ts — ctx.db is typed from that manifest, and ctx.auth is the verified identity of the
caller, never something the browser asserted:
import { defineServer, mutation, query } from '@impetik/xeer/server';
export default defineServer({
queries: {
'notes.list': query({
input: {},
handler: (ctx) => ctx.db.table('notes').find({ where: { ownerId: ctx.auth.appUserId } }),
}),
},
mutations: {
'notes.create': mutation({
input: { text: 'string' },
handler: (ctx, input) => ctx.db.table('notes').insert({
text: input.text,
ownerId: ctx.auth.appUserId,
}),
}),
},
});src/client.tsx — useQuery knows the operation's input and output types from the server above. It
also knows which tables the query read, so a write to one of them re-renders this component. Nobody
wired that up:
import { useMutation, useQuery, useState } from '@impetik/xeer/client';
export default function App() {
const notes = useQuery('notes.list', {});
const createNote = useMutation('notes.create');
const [text, setText] = useState('');
return (
<main>
<input value={text} onInput={(event) => setText(event.currentTarget.value)} />
<button onClick={() => void createNote({ text }).then(() => setText(''))}>Add</button>
{notes.loading && <p>Loading…</p>}
<ul>{(notes.data ?? []).map((note) => <li key={note.id}>{note.text}</li>)}</ul>
</main>
);
}What comes with it
- Live updates in one manifest line. Queries record what they read, mutations report what they wrote,
and open clients refetch only what changed. Declare
budgets.liveConnectionsto push those refreshes to other people's clients. → docs.xeer.run/guides/live-updates - A database and an object store, declared not provisioned. No connection string, no bucket name, no credential — and local development gets both for real. → docs.xeer.run/guides/capabilities
- Identity before the first request. Every visitor gets a verified, stable identity with no sign-in screen — and authorization is declared in the data layer, so a table owned-per-user stays that way for every read and write. → docs.xeer.run/guides/auth
- A test runner in the box. No framework to choose, no harness to build. → docs.xeer.run/guides/testing
- Preview, promote, roll back. Content-addressed builds, so shipping exactly what you reviewed is mechanical. → docs.xeer.run/guides/deploy
- Secrets that stay secret. Client code cannot import server code, and the compiler enforces it. → docs.xeer.run/guides/env
- Machine-readable end to end.
--jsonon every command, stable diagnostic codes with suggested repairs, and an MCP server. → docs.xeer.run/guides/agents
Requirements
- Node.js
>=22.12.0. The CLI checks at startup and prints a clear error otherwise. - A Xeer account to deploy. Xeer is in closed beta, so accounts are currently by invitation.
Everything local needs no account and no network:
xeer new,xeer dev,xeer test,xeer build, andxeer previewrun entirely on your machine. See docs.xeer.run/faq.
Package name: this is published as
@impetik/xeerbecause npm's anti-typosquatting check rejected the unscoped namexeer. The installed command is still justxeer.
Commands
xeer new <directory> [--template <t>] scaffold a project (notes, todo, blog, personal-site)
xeer check [directory] validate the manifest and analyse the source
xeer dev [directory] run locally, with instant feedback
xeer test [directory] run the application's own test suite
xeer build [directory] produce a content-addressed artifact
xeer preview [directory] run that exact artifact locally
xeer doctor [directory] diagnose this machine
xeer auth login | status | logout sign in to deploy
xeer auth as <alice|bob> | clear pick the local development persona
xeer deploy [--environment preview] ship it
xeer promote --receipt review_… make the reviewed preview version live
xeer rollback <artifactId> put a previous version back
xeer deployments deployment history
xeer disable | enable | delete take an app offline, or destroy it
xeer link point this checkout at an app you own
xeer env set | ls | rm | pull environment values and secrets
xeer inspect | state | logs read a running app (--environment preview selects that slot)
xeer export | import move state in and out (deployed export selects an environment)
xeer actions print the versioned action and safety catalogueEvery command accepts --json, which emits a structured envelope (or, for the long-running commands, a
stream of newline-delimited events) suitable for driving Xeer from a program rather than a terminal.
xeer actions --json enumerates every canonical CLI and MCP action, including actions deliberately
hidden from human help, with effects, safety properties, prerequisites, path policy, and MCP exclusion
reasons.
Full reference, option by option: docs.xeer.run/reference/cli.
Troubleshooting
xeer: command not foundafter a global install — check that your npm global bin directory is onPATH(npm config get prefix, then look in<prefix>/bin), or usenpx --package=@impetik/xeer -- xeerinstead.npx xeer …doesn't work — the package is@impetik/xeer, notxeer. Usenpx --package=@impetik/xeer -- xeerorpnpm dlx @impetik/xeer.- Unsupported Node.js version — install Node.js
>=22.12.0;xeer doctorreports what you have. xeer devorxeer buildcannot find its runtime — npm 11 and newer block native install scripts by default. Runnpm approve-scripts esbuild workerdin your project, or install globally withnpm install -g --allow-scripts=workerd,esbuild @impetik/xeer.xeer doctornames the dependency that failed to resolve.- Anything with an
XE####code — look it up at docs.xeer.run/reference/diagnostics, or runxeer <command> --jsonfor the machine-readable form with a file, a span, and a suggested repair.
Links
- Documentation — docs.xeer.run
- Quickstart — docs.xeer.run/quickstart
- FAQ — docs.xeer.run/faq
- Source and issues — github.com/impetik/xeer
License
MIT
