refactor(core): migrate to Bun and converge acquisition policies and Agent boundaries

This commit is contained in:
root committed 2026-10-13 14:37:03 +08:00
1 parent 3f1c6d02f6
commit 27c0f27434
268 files changed
+7468 -7852

No files matched your search

+1 -1
View File
@@ -5,7 +5,7 @@ PostgreSQL 访问层:Kysely 客户端与连接池、表类型(`src/types.ts`)、
## 规则
- **迁移是唯一事实来源**。所有 schema 变更只能新增迁移,已发布迁移不得修改。迁移用原生 DDL 书写(`src/migration-helpers.ts`:`entityTable()` 统一加 uuid 主键 `gen_random_uuid()`、`created_at/updated_at` 与 updated_at 触发器;`oneOf()` 生成状态 CHECK)。`migrations/` 内相对导入必须带 `.ts` 扩展名(Kysely 用原生 `import()` 加载)。
- **`src/types.ts` 是生成物**:`deno task db:migrate && deno task gen:types`。CHECK 枚举自动变成字面量联合(如 `AcquisitionSlotStatus`)。`test/schema.test.ts` 会在隔离 schema 里重新反射并比对,漂移即失败;`packages/contracts/test/db-sync.test.ts` 再校验 contracts 的 Row schema 与枚举和这里一致。
- **`src/types.ts` 是生成物**:`bun run db:migrate && bun run gen:types`。CHECK 枚举自动变成字面量联合(如 `AcquisitionSlotStatus`)。`test/schema.test.ts` 会在隔离 schema 里重新反射并比对,漂移即失败;`packages/contracts/test/db-sync.test.ts` 再校验 contracts 的 Row schema 与枚举和这里一致。
- 状态列一律 `text + CHECK`,不用 PG enum(便于迁移加值)。JSONB 只放证据、规则参数、原文快照与演进字段;稳定查询字段用关系列。
- 凭证只存 `secret_ref`(→ `secret.id`),明文不入库、不进日志。
- `createDb()` 把 `int8` 解析为 `number`(超出 2^53 抛错)、`date` 保持 `YYYY-MM-DD` 字符串。写 jsonb 数组时须先 `JSON.stringify`(pg 会把 JS 数组当 PG 数组)。
-12
View File
@@ -1,12 +0,0 @@
{
"name": "@umt/db",
"version": "0.3.44",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
"typecheck": "deno run -A npm:typescript/tsc --noEmit -p tsconfig.json",
"migrate": "deno run -A --env-file=../../.env scripts/migrate.ts latest",
"reset": "deno run -A --env-file=../../.env scripts/migrate.ts reset",
"gen:types": "deno run -A --env-file=../../.env scripts/gen-types.ts"
}
}
+11
View File
@@ -4,5 +4,16 @@
"type": "module",
"exports": {
".": "./src/index.ts"
},
"version": "0.3.44",
"scripts": {
"test": "bun x --bun vitest run",
"typecheck": "bun x --bun tsc --noEmit -p tsconfig.json",
"migrate": "bun --env-file=../../.env scripts/migrate.ts latest",
"reset": "bun --env-file=../../.env scripts/migrate.ts reset",
"gen:types": "bun --env-file=../../.env scripts/gen-types.ts"
},
"dependencies": {
"@umt/runtime": "workspace:*"
}
}
+2 -2
View File
@@ -3,7 +3,7 @@ import { fileURLToPath } from "node:url";
import { type Kysely, sql } from "kysely";
// 从已迁移的数据库反射出 src/types.ts:列类型 + CHECK (col in (...)) 枚举字面量联合。
// 迁移是唯一事实来源;改表后运行 `deno task gen:types`,测试会校验两者无漂移。
// 迁移是唯一事实来源;改表后运行 `bun run gen:types`,测试会校验两者无漂移。
interface ColumnInfo {
table_name: string;
@@ -77,7 +77,7 @@ export async function generateTypesSource(db: Kysely<any>): Promise<string> {
const out: string[] = [
"// 本文件由 scripts/gen-types.ts 从迁移后的数据库反射生成,请勿手改。",
"// 改表:新增迁移 → deno task db:migrate → deno task gen:types。",
"// 改表:新增迁移 → bun run db:migrate → bun run gen:types。",
"",
'import type { ColumnType, Generated, Insertable, Selectable, Updateable } from "kysely";',
"",
+1 -1
View File
@@ -1,4 +1,4 @@
// 用法:deno task gen:types —— 对 DATABASE_URL 的当前 schema 反射并重写 src/types.ts
// 用法:bun run gen:types —— 对 DATABASE_URL 的当前 schema 反射并重写 src/types.ts
import { writeFileSync } from "node:fs";
import { createDb } from "../src/index.ts";
import { formatWithBiome, generateTypesSource, TYPES_FILE } from "./gen-types-lib.ts";
+1 -1
View File
@@ -1,4 +1,4 @@
// 用法:deno task db:migrate / db:reset(= deno run -A --env-file=.env packages/db/scripts/migrate.ts latest|reset)
// 用法:bun run db:migrate / db:reset(= bun --env-file=.env packages/db/scripts/migrate.ts latest|reset)
import { createDb, migrateToLatest, resetSchema } from "../src/index.ts";
const cmd = process.argv[2] ?? "latest";
+1 -1
View File
@@ -1,5 +1,5 @@
// 本文件由 scripts/gen-types.ts 从迁移后的数据库反射生成,请勿手改。
// 改表:新增迁移 → deno task db:migrate → deno task gen:types。
// 改表:新增迁移 → bun run db:migrate → bun run gen:types。
import type { ColumnType, Generated, Insertable, Selectable, Updateable } from "kysely";
+1 -1
View File
@@ -3,7 +3,7 @@ import { Kysely, PostgresDialect } from "kysely";
import pg from "pg";
import { PgTokenBucket } from "../../src/rate-limit.ts";
const [url, schema, key, n, capacity, rate] = Deno.args as [string, string, string, string, string, string];
const [url, schema, key, n, capacity, rate] = process.argv.slice(2) as [string, string, string, string, string, string];
const db = new Kysely<unknown>({
dialect: new PostgresDialect({
pool: new pg.Pool({ connectionString: url, max: 1, options: `-c search_path=${schema},public` }),
+3 -2
View File
@@ -1,4 +1,5 @@
import { fileURLToPath } from "node:url";
import { Command } from "@umt/runtime";
import { Kysely, PostgresDialect, sql } from "kysely";
import pg from "pg";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
@@ -70,8 +71,8 @@ describe.skipIf(skip)("PgTokenBucket(真实 PG)", () => {
const rate = 20;
const perProc = 12;
const procs = [0, 1, 2].map(() =>
new Deno.Command(Deno.execPath(), {
args: ["run", "-A", script, url, schema, "t:procs", String(perProc), String(capacity), String(rate)],
new Command(process.execPath, {
args: [script, url, schema, "t:procs", String(perProc), String(capacity), String(rate)],
stdout: "piped",
stderr: "piped",
}).output(),