import type { StaticStickerCatalog, StaticStickerCatalogItem } from "@dada/static-sticker-catalog"; export const P0A_TEXT_TEMPLATE_IDS = [ "FLOWER001", "FLOWER002", "FLOWER003", "FLOWER004", "FLOWER005", "FLOWER006", "FLOWER007", "FLOWER008", "H001", "H002", "H003", "H004", "H005", "H006", "H007", "H008", "TAG001", "TAG002", "TAG003", "TAG004", "TAG005", "TAG006", "TAG007", "TAG051", "SIMPLE001", "SIMPLE002", "SIMPLE003", "SIMPLE004", "SIMPLE005", "SIMPLE006", "SIMPLE007", "SIMPLE008", ] as const; // Derived from exact package-hash matches between the 32 frozen templates and the 86-item font panel. export const P0A_REQUIRED_FONT_PANEL_IDS = [ "FONT005", "FONT008", "FONT011", "FONT021", "FONT022", "FONT027", "FONT039", "FONT043", "FONT046", "FONT052", "FONT081", ] as const; export const P0A_COLOR_CARD_IDS = ["COLOR001", "COLOR002", "COLOR008", "COLOR016"] as const; export const P0A_DYNAMIC_STICKER_IDS = [ "DYN001", "DYN002", "DYN003", "DYN004", "DYN007", "DYN008", "DYN011", "DYN012", "DYN015", "DYN016", ] as const; export type RegisteredComplexFamily = "color_card" | "font_panel" | "interactive_sticker" | "text_template"; export interface RegisteredComplexAsset extends Record { 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: 4; dynamic_stickers: 10; font_panel_items: 11; static_parts: 25; static_stickers: 1407; text_templates: 32; }; release_tier: "alpha_whitelist"; release_version: string; schema_version: "P0AAssetManifest/v1"; source_versions: { complex: string; static_stickers: string; }; static_part_counts: Record; } const expectedFamilyCounts: Readonly> = { 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(); 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"); } function fontIdsForTemplates(templates: readonly RegisteredComplexAsset[]) { const referenced = new Set(); for (const template of templates) { for (const fontId of template.font_panel_references ?? []) referenced.add(fontId); } referenced.add("FONT081"); return [...referenced].sort((left, right) => Number(left.slice(4)) - Number(right.slice(4))); } 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 derivedFontIds = fontIdsForTemplates(textTemplates); if (JSON.stringify(derivedFontIds) !== JSON.stringify(P0A_REQUIRED_FONT_PANEL_IDS)) { throw new Error(`P0-A referenced font panel mismatch: received ${derivedFontIds.join(",")}`); } const fontPanelItems = orderedItems(input.complexManifest.items, derivedFontIds, "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: 4, dynamic_stickers: 10, font_panel_items: 11, static_parts: 25, static_stickers: 1_407, text_templates: 32, }, 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 }, }; }