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

@@ -500,6 +500,104 @@ describe.skipIf(!hasPg)("订阅重做(真实 PG)", () => {
expect(await db().selectFrom("slot_deferral").select("id").where("slot_id", "=", mq).execute()).toHaveLength(0);
});
it("收录规则按版本优先解析,补全继承主版本,概览包含各版本的实际引用", async () => {
const makeGroup = async (name: string, autoFill: boolean) => {
const r = await h.api("POST", "/rules", { name, ruleString: "1080P | 4K" });
expect(r.status, JSON.stringify(r.body)).toBe(201);
await db().updateTable("rule_group").set({ auto_fill: autoFill }).where("id", "=", r.body.data.id).execute();
return r.body.data.id as string;
};
const legacy = await makeGroup("兼容订阅允许补全", true);
const primaryRule = await makeGroup("主版本暂停补全", false);
const e = await seedEntity(db(), { kind: "movie", title: "Converged Rules", year: 2026 });
const s = await sub(e, { kind: "movie", params: { ruleGroupIds: [legacy], include: ["Converged"] } });
const a = await asset(e, { quality: { resolution: "2160p" } });
const primary = await slot(e, s, "4K", {
position: 0,
hard: { resolutions: ["2160p"] },
currentAssetId: a,
status: "satisfied",
});
await db()
.updateTable("acquisition_slot")
.set({ rule_group_ids: JSON.stringify([primaryRule]) })
.where("id", "=", primary)
.execute();
const secondary = await slot(e, s, "1080p", { position: 1, hard: { resolutions: ["1080p"] } });
// 正常 API 保存共同过滤,生成私有组;它参与评估但不混入可见的规则名称。
expect(
(await h.api("PATCH", `/subscriptions/${s}`, { params: { ruleGroupIds: [legacy], include: ["Converged"] } }))
.status,
).toBe(200);
const r = await rel(e, "Converged.Rules.2026.1080p.WEB-DL.x264-GRP");
const deferred = await evaluateAcquisition(h.d, { sourceReleaseId: r });
expect(deferred.deferred).toContainEqual({ sourceReleaseId: r, slotId: secondary, reason: "auto_fill_off" });
const overview = async () => (await h.api("GET", "/subscriptions?q=Converged%20Rules")).body.data.items[0];
const before = await overview();
expect(before.ruleGroups.map((g: { id: string }) => g.id)).toEqual([primaryRule, legacy]);
expect(before.slots.map((x: { ruleGroupIds: string[] }) => x.ruleGroupIds)).toEqual([[primaryRule], [legacy]]);
expect(before.autoFill).toMatchObject({ enabled: false, source: "rule_group" });
await db().updateTable("rule_group").set({ auto_fill: true }).where("id", "=", primaryRule).execute();
await db().updateTable("rule_group").set({ auto_fill: false }).where("id", "=", legacy).execute();
expect((await overview()).autoFill).toMatchObject({ enabled: true, source: "rule_group" });
const enabled = await evaluateAcquisition(h.d, { sourceReleaseId: r });
expect(enabled.plans, JSON.stringify(enabled)).toHaveLength(1);
expect(
await db()
.selectFrom("acquisition_plan")
.select(["slot_id", "evaluation"])
.where("id", "=", enabled.plans[0]!)
.executeTakeFirstOrThrow(),
).toMatchObject({
slot_id: secondary,
evaluation: { autoFill: true, primarySlotId: primary },
});
await h.api("PATCH", `/subscriptions/${s}`, { params: { ruleGroupIds: [legacy], autoFill: "off" } });
expect((await overview()).autoFill).toMatchObject({ enabled: false, source: "subscription" });
});
it("普通订阅保存保留旧质量过滤和每个版本独立的洗版设置", async () => {
const e = await seedEntity(db(), { kind: "series", title: "兼容编辑剧", year: 2026 });
const params = { resolution: "4k", source: "uhd", effect: "atmos" };
const s = await sub(e, { params });
await slot(e, s, "1080p", {
hard: { resolutions: ["1080p"], codecs: ["H.265"] },
upgrade: { enabled: false, mode: "per_unit" },
});
await slot(e, s, "4K", { hard: { resolutions: ["2160p"] }, upgrade: { enabled: true, mode: "full_pack" } });
const slots = () =>
db()
.selectFrom("acquisition_slot")
.select(["id", "revision", "hard_conditions", "upgrade_threshold"])
.where("subscription_id", "=", s)
.orderBy("id")
.execute();
const before = await slots();
const saved = await h.api("PATCH", `/subscriptions/${s}`, { params: { ...params, searchIntervalHours: 6 } });
expect(saved.status, JSON.stringify(saved.body)).toBe(200);
expect(saved.body.data.params).toEqual({ ...params, searchIntervalHours: 6 });
expect(await slots()).toEqual(before);
const privateGroup = await db()
.selectFrom("rule_group")
.select("hard")
.where("scope", "@>", JSON.stringify({ subscriptionId: s }))
.where("deleted_at", "is", null)
.executeTakeFirstOrThrow();
expect(JSON.stringify(privateGroup.hard)).toContain("Atmos");
expect(JSON.stringify(privateGroup.hard)).toContain("UHD");
const cleared = await h.api("PATCH", `/subscriptions/${s}`, { params: { searchIntervalHours: 6 } });
expect(cleared.status, JSON.stringify(cleared.body)).toBe(200);
expect(await slots()).toEqual(before);
expect(
await db()
.selectFrom("rule_group")
.select("id")
.where("scope", "@>", JSON.stringify({ subscriptionId: s }))
.where("deleted_at", "is", null)
.execute(),
).toEqual([]);
});
it("表单:MP 字段与旧键兼容(规范化后只存规范键);校验 400;同作品同季 409;best_version → 升级策略", async () => {
const e = await seedEntity(db(), { kind: "series", title: "表单剧", year: 2025 });
const site = await db()