快速开始

创建 Federation

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

服务端运行时的类是 Federation(文档里也叫 Federation),产品侧用 City 客户端去访问它。两者的区别见 Federation 与 City

最快的本地创建和启动方式是:

fed create ./my-fed
cd my-fed
pnpm install
fed deploy

默认模板使用 Node.js + SQLite。fed deploy12314 开始分配端口,把进程登记到系统级 Fed 管理状态,并交互式配置管理员 ID 和密码;之后可以在任意路径运行 fed 查看并直接进入管理。下文是需要手动嵌入 Federation runtime 时的 SDK 写法。

安装包:

pnpm add @downcity/federation @downcity/database-sqlite

准备好数据库即可。fed deploy 会交互式配置管理员 ID 和密码;密码只保存为 PBKDF2 摘要,登录后使用管理员会话 Token。Federation 首次启动时会自动补齐 DOWNCITY_FEDERATION_TOKEN_SIGNING_KEYBETTER_AUTH_SECRET。provider key 则在启动后通过 Admin API 或 fed 的 admin workspace 写入:

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

创建 Federation:

import { Federation } from "@downcity/federation";
import { Database } from "@downcity/database-sqlite";

const database = new Database({ filename: "./data.sqlite" });
const base = new Federation({ database });

默认数据库会落到:

./data.sqlite

本地 SQLite 使用 @downcity/database-sqlite。正式部署使用 PostgreSQL 时,改用 @downcity/database-postgresql

如果要使用 Cloudflare Workers / D1,传入 D1 Adapter:

import { Database } from "@downcity/database-d1";

const database = new Database({ binding: env.DB });
const base = new Federation({ database });

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

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

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

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",
});

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

启动服务:

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

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

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