Downcity City DocsQuickstart
Try It Now
Run a complete call chain with the default database, AdminClient, and UserClient.
1. Start City
import { City, AIService, Provider } from "@downcity/city";
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
const sqlite = new Database("./data.sqlite");
sqlite.pragma("journal_mode = WAL");
const db = Object.assign(drizzle(sqlite), {
$client: { exec: (sql: string) => sqlite.exec(sql) },
});
const base = new City({ db, dialect: "sqlite", raw: sqlite });
const echo = new Provider("echo", {
text: async (ctx) => ({
id: crypto.randomUUID(),
role: "assistant",
parts: [{ type: "text", text: `Echo: ${ctx.input.prompt}` }],
}),
stream: async (ctx) => { /* ... */ },
});
const ai = new AIService();
ai.use(echo.model({ id: "local-echo", name: "Local Echo", default: true }));
base.use(ai);
await base.health();
serve({ fetch: base.router().fetch, port: 43127, hostname: "127.0.0.1" });2. Create Studio & Token
const admin = new AdminClient({
base_url: "http://127.0.0.1:43127",
admin_secret_key: process.env.DOWNCITY_CITY_ADMIN_SECRET_KEY,
});
const studio = await admin.studios.create({ name: "Demo Studio" });
const token = await admin.studios.tokens.apply({
studio_id: studio.studio_id,
user_id: "user_123",
ttl: "7d",
});3. Client Call
const client = new UserClient({
base_url: "http://127.0.0.1:43127",
studio_id: studio.studio_id,
user_token: token.user_token,
});
// SDK pathway
const result = await client.ai.text({ prompt: "Hello" });
// OpenAI-compatible pathway
// POST /v1/ai/chat/completions