Files
tyx_AI_xhs/packages/template-registry/src/index.ts
T
suyx fd4cd277cc
Dada P0-A isolated Windows CI / validate-and-package (push) Waiting to run
feat(POSTV1-ASSET-ALL-16): 发布完整素材注册清单
2026-08-06 11:30:09 +08:00

176 lines
7.6 KiB
TypeScript

import type { StaticStickerCatalog, StaticStickerCatalogItem } from "@dada/static-sticker-catalog";
export const P0A_COMPLEX_RELEASE_VERSION = "p0a-complex-v1";
export const P0A_STATIC_STICKER_RELEASE_VERSION = "p0a-static-v1";
function numberedIds(prefix: string, count: number) {
return Object.freeze(Array.from({ length: count }, (_, index) => `${prefix}${String(index + 1).padStart(3, "0")}`));
}
export const P0A_TEXT_TEMPLATE_IDS = Object.freeze([
...numberedIds("FLOWER", 145),
...numberedIds("H", 119),
...numberedIds("TAG", 51),
...numberedIds("SIMPLE", 17),
]);
export const P0A_REQUIRED_FONT_PANEL_IDS = numberedIds("FONT", 86);
export const P0A_COLOR_CARD_IDS = numberedIds("COLOR", 16);
export const P0A_DYNAMIC_STICKER_IDS = numberedIds("DYN", 35);
export const P0A_DYNAMIC_RUNTIME_FONT_SOURCES = [
{ assetId: "15974853bc3294ef68e7e6d58fe74fd7", sourceReference: "fonts/15974853bc3294ef68e7e6d58fe74fd7", templateId: "DYN002" },
{ assetId: "46f8336813e4c48d06a1aef294fdccf6", sourceReference: "fonts/46f8336813e4c48d06a1aef294fdccf6", templateId: "DYN016" },
{ assetId: "53ca6b704728520da50c145eabb2e635", sourceReference: "fonts/53ca6b704728520da50c145eabb2e635", templateId: "DYN007" },
{ assetId: "cca5efc0e02fb1bf62349bd68ef30fc1", sourceReference: "fonts/cca5efc0e02fb1bf62349bd68ef30fc1", templateId: "DYN015" },
{ assetId: "dd25b35dcb7ba4476cbaa9a9592e39e2", sourceReference: "fonts/dd25b35dcb7ba4476cbaa9a9592e39e2", templateId: "DYN001" },
{ assetId: "e4210c9872f0c279b35273f230809821", sourceReference: "fonts/e4210c9872f0c279b35273f230809821", templateId: "DYN011" },
{ assetId: "f4bfd4132df2d6be97ceabadf3853505", sourceReference: "fonts/f4bfd4132df2d6be97ceabadf3853505", templateId: "DYN008" },
] as const;
export const P0A_DYNAMIC_RUNTIME_IMAGE_SOURCES = [
{ assetId: "DYN001-image28", sourceReference: "resource/image28.png", templateId: "DYN001" },
{ assetId: "DYN002-image29", sourceReference: "resource/image29.png", templateId: "DYN002" },
{ assetId: "DYN003-image30", sourceReference: "resource/image30.png", templateId: "DYN003" },
{ assetId: "DYN004-image32", sourceReference: "resource/image32.png", templateId: "DYN004" },
{ assetId: "DYN008-backendui0", sourceReference: "resource/backendui0.png", templateId: "DYN008" },
{ assetId: "DYN011-backendui0", sourceReference: "resource/backendui0.png", templateId: "DYN011" },
{ assetId: "DYN015-imager2", sourceReference: "resource/imager2_2.png", templateId: "DYN015" },
{ assetId: "DYN016-image21", sourceReference: "resource/image21.png", templateId: "DYN016" },
] as const;
export type RegisteredComplexFamily = "color_card" | "font_panel" | "interactive_sticker" | "text_template";
export interface RegisteredComplexAsset extends Record<string, unknown> {
canonical_id: string;
family: RegisteredComplexFamily;
font_panel_references?: string[];
release_status: string;
release_tier: string;
validation_status: string;
}
export interface ComplexRegistryManifest {
items: RegisteredComplexAsset[];
release_version: string;
schema_version: string;
}
export interface PublicComplexAsset extends RegisteredComplexAsset {
release_status: "enabled";
release_tier: "alpha_whitelist";
validation_status: "passed";
}
export interface P0aPublicManifest {
assets: {
color_cards: PublicComplexAsset[];
dynamic_stickers: PublicComplexAsset[];
font_panel_items: PublicComplexAsset[];
static_stickers: StaticStickerCatalogItem[];
text_templates: PublicComplexAsset[];
};
counts: {
color_cards: 16;
dynamic_stickers: 35;
font_panel_items: 86;
static_parts: 25;
static_stickers: 1407;
text_templates: 332;
};
release_tier: "alpha_whitelist";
release_version: string;
schema_version: "P0AAssetManifest/v1";
source_versions: {
complex: string;
static_stickers: string;
};
static_part_counts: Record<string, number>;
}
const expectedFamilyCounts: Readonly<Record<RegisteredComplexFamily, number>> = {
color_card: 16,
font_panel: 86,
interactive_sticker: 35,
text_template: 332,
};
function orderedItems(items: readonly RegisteredComplexAsset[], ids: readonly string[], family: RegisteredComplexFamily) {
const byId = new Map(items.filter((item) => item.family === family).map((item) => [item.canonical_id, item]));
return ids.map((id) => {
const item = byId.get(id);
if (!item) throw new Error(`P0-A allowlist item is not registered: ${id}`);
return item;
});
}
function publicItem(item: RegisteredComplexAsset): PublicComplexAsset {
return {
...item,
release_status: "enabled",
release_tier: "alpha_whitelist",
validation_status: "passed",
};
}
function validateFullRegistry(manifest: ComplexRegistryManifest) {
if (manifest.schema_version !== "asset-release-compiler/v1") throw new Error("complex registry schema version is unsupported");
const ids = new Set<string>();
for (const item of manifest.items) {
if (ids.has(item.canonical_id)) throw new Error(`duplicate registered asset ${item.canonical_id}`);
ids.add(item.canonical_id);
if (item.release_tier !== "full_p0") throw new Error(`${item.canonical_id} must remain in full_p0 before public projection`);
if (item.release_status === "enabled") throw new Error(`full_p0 item is enabled before atomic full release: ${item.canonical_id}`);
}
for (const [family, expected] of Object.entries(expectedFamilyCounts) as Array<[RegisteredComplexFamily, number]>) {
const actual = manifest.items.filter((item) => item.family === family).length;
if (actual !== expected) throw new Error(`${family} count mismatch: expected ${expected}, received ${actual}`);
}
}
function validateStaticCatalog(catalog: StaticStickerCatalog) {
if (catalog.count !== 1_407 || catalog.items.length !== 1_407) throw new Error("static sticker count mismatch: expected 1407");
const parts = new Set(catalog.items.map((item) => item.part));
if (parts.size !== 25 || [...parts].some((part) => part < 1 || part > 25)) throw new Error("static sticker parts must be exactly part1-part25");
if (Object.keys(catalog.part_counts).length !== 25) throw new Error("static sticker part counts must contain 25 parts");
}
export function createP0aPublicManifest(input: {
complexManifest: ComplexRegistryManifest;
staticCatalog: StaticStickerCatalog;
}): P0aPublicManifest {
validateFullRegistry(input.complexManifest);
validateStaticCatalog(input.staticCatalog);
const textTemplates = orderedItems(input.complexManifest.items, P0A_TEXT_TEMPLATE_IDS, "text_template");
const fontPanelItems = orderedItems(input.complexManifest.items, P0A_REQUIRED_FONT_PANEL_IDS, "font_panel");
const colorCards = orderedItems(input.complexManifest.items, P0A_COLOR_CARD_IDS, "color_card");
const dynamicStickers = orderedItems(input.complexManifest.items, P0A_DYNAMIC_STICKER_IDS, "interactive_sticker");
return {
assets: {
color_cards: colorCards.map(publicItem),
dynamic_stickers: dynamicStickers.map(publicItem),
font_panel_items: fontPanelItems.map(publicItem),
static_stickers: input.staticCatalog.items.map((item) => ({ ...item })),
text_templates: textTemplates.map(publicItem),
},
counts: {
color_cards: 16,
dynamic_stickers: 35,
font_panel_items: 86,
static_parts: 25,
static_stickers: 1_407,
text_templates: 332,
},
release_tier: "alpha_whitelist",
release_version: input.complexManifest.release_version,
schema_version: "P0AAssetManifest/v1",
source_versions: {
complex: input.complexManifest.release_version,
static_stickers: input.staticCatalog.release_version,
},
static_part_counts: { ...input.staticCatalog.part_counts },
};
}