快速开始

创建 City

初始化 Downcity City,准备默认数据库和 HTTP 服务。

安装包:

pnpm add @downcity/city drizzle-orm better-sqlite3

准备好数据库即可。City 首次启动时会自动补齐 DOWNCITY_CITY_ADMIN_SECRET_KEYDOWNCITY_CITY_TOKEN_SIGNING_KEYBETTER_AUTH_SECRET。provider key 则在启动后通过 Town CLI / Admin API 写入:

OPENAI_API_KEY="..."
OPENAI_BASE_URL="https://api.openai.com/v1"

创建 CityBase:

import { CityBase } 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 CityBase({ db, dialect: "sqlite", raw: sqlite });

默认数据库会落到:

./data.sqlite

本地 SQLite 推荐使用 better-sqlite3。正式部署如果使用 Postgres,也同样是先创建 Drizzle pg db,再传给 City

如果要使用 Cloudflare Workers / D1,传入 D1 对应的 Drizzle db:

import { drizzle } from "drizzle-orm/d1";

const db = drizzle(env.DB);
const base = new CityBase({ db, dialect: "sqlite", raw: env.DB });

City 会在第一次 health()handleRequest()table() 等运行时操作时自动初始化。

如果你的 City 还需要自己的业务表,可以通过 Service 或服务声明表。表会挂在对应 Service 的命名空间下,并和 City 默认数据库使用同一个数据库连接:

import { sqliteTable, text } from "drizzle-orm/sqlite-core";
import { Service } from "@downcity/city";

const notes = sqliteTable("notes", {
  id: text("id").primaryKey(),
  title: text("title").notNull(),
  status: text("status").notNull(),
});

const notesService = new Service({
  id: "notes",
  tables: { notes },
});

base.use(notesService);

const table = await base.table("notes.notes");
await table.insert({
  id: "note_1",
  title: "First note",
  status: "draft",
});

常规项目不需要手动建表;第一次运行时操作会自动准备 City 内置表和 Service 声明的表。

启动服务:

import { serve } from "@hono/node-server";

await base.health();
serve({ fetch: base.router().fetch, port: 3001, hostname: "127.0.0.1" });

这个服务就是后续多个产品共用的 City。管理和业务数据暂时通过你自己的数据库与产品后端处理。