import cloud from "@lafjs/cloud"; import { createHash } from "crypto"; export const COLLECTION = "activityConfigs"; export const records = (): any => (cloud.mongo.db as any).collection(COLLECTION); export const configId = (activityId: string, version: string) => createHash("sha256").update(JSON.stringify([activityId, version])).digest("hex"); /** Missing flags on legacy records retain the enabled behavior. */ export const isEnabled = (record: any): boolean => !!record && record.enabled !== false; /** Published records are immutable. Runtime selection never uses a future publication. */ export async function publish(activityId: string, configVersion: string, effectiveFrom: number, config: any, enabled = true) { if (typeof enabled !== "boolean") throw new Error("enabled 必须为布尔值"); if (typeof configVersion !== "string" || !/^[A-Za-z0-9_:-]{1,100}$/.test(configVersion) || !Number.isSafeInteger(effectiveFrom) || effectiveFrom <= Date.now()) throw new Error("配置版本必填,且只能发布未来生效的配置"); const row = { _id: configId(activityId, configVersion), activityId, recordType: "version", configVersion, status: "published", effectiveFrom, publishedAt: Date.now(), config, enabled }; const old = await records().findOne({ _id: row._id }); if (old) { if (old.effectiveFrom !== effectiveFrom || JSON.stringify(old.config) !== JSON.stringify(config) || isEnabled(old) !== enabled) throw new Error("配置版本已存在,不可修改"); return old; } try { await records().insertOne(row); } catch (error) { const saved = await records().findOne({ _id: row._id }); if (!saved || saved.effectiveFrom !== effectiveFrom || JSON.stringify(saved.config) !== JSON.stringify(config) || isEnabled(saved) !== enabled) throw error; return saved; } return row; } export async function latest(activityId: string, at: number, publishedBefore = at, extra: any = {}) { const rows = await records().find({ ...extra, activityId, recordType: "version", status: "published", effectiveFrom: { $lte: at }, publishedAt: { $lte: publishedBefore } }) .sort({ effectiveFrom: -1, publishedAt: -1, _id: 1 }).limit(2).toArray(); if (rows[1] && rows[0].effectiveFrom === rows[1].effectiveFrom && rows[0].publishedAt === rows[1].publishedAt) throw new Error("配置生效时间冲突,请调整发布版本"); return rows[0] || null; } /** For new activity periods: never fall back past a disabled selected version. */ export async function latestEnabled(activityId: string, at: number, publishedBefore = at, extra: any = {}) { const row = await latest(activityId, at, publishedBefore, extra); return isEnabled(row) ? row : null; } export async function setupIndexes() { await records().createIndex({ activityId: 1, configVersion: 1 }, { unique: true, partialFilterExpression: { recordType: "version" }, name: "activity_config_version" }); await records().createIndex({ activityId: 1, recordType: 1, status: 1, effectiveFrom: -1, publishedAt: -1 }); await records().createIndex({ activityId: 1, "config.periodId": 1, publishedAt: -1 }); } export default async function () { return { code: 0, msg: "internal module" }; }