import { defineAction } from "@agent-native/core"; import { assertAccess } from "@agent-native/core/sharing"; import { eq } from "drizzle-orm"; import { z } from "zod"; import { getDb, schema } from "../server/db/index.js"; import { extractDominantColors } from "../server/lib/image-processing.js"; import { nowIso, parseJson, stringifyJson } from "../server/lib/json.js"; import { getObject } from "../server/lib/storage.js"; import type { StyleBrief } from "../shared/api.js"; export default defineAction({ description: "Extract dominant colors from reference images and write them into the library style brief palette.", schema: z.object({ libraryId: z.string(), }), run: async ({ libraryId }) => { await assertAccess("asset-library", libraryId, "editor"); const db = getDb(); const [library] = await db .select() .from(schema.assetLibraries) .where(eq(schema.assetLibraries.id, libraryId)) .limit(1); if (!library) throw new Error("Asset library not found."); const assets = await db .select() .from(schema.assets) .where(eq(schema.assets.libraryId, libraryId)); const counts = new Map(); for (const asset of assets .filter((asset) => asset.status === "reference") .slice(0, 24)) { const buffer = await getObject(asset.objectKey).catch(() => null); if (!buffer) continue; for (const color of await extractDominantColors(buffer).catch(() => [])) { counts.set(color, (counts.get(color) ?? 0) + 1); } } const palette = [...counts.entries()] .sort((a, b) => b[1] - a[1]) .slice(0, 8) .map(([color]) => color); const styleBrief = parseJson(library.styleBrief, {}); styleBrief.palette = palette; await db .update(schema.assetLibraries) .set({ styleBrief: stringifyJson(styleBrief), updatedAt: nowIso() }) .where(eq(schema.assetLibraries.id, libraryId)); return { libraryId, palette }; }, });