Files
probably-rendering-one-more…/apps/waterfall-wiki/src/lib/studio-designs.ts
T
codex-bot 94932418ca
studio CI and deployment / verify-and-deploy (push) Successful in 5m55s
waterfall-wiki CI and deployment / verify-and-deploy (push) Failing after 18m23s
Connect all 27 source layouts to parameterized Studio pages and shared design storage
2026-10-27 14:51:17 +08:00

11 lines
1.6 KiB
TypeScript

import {randomUUID} from 'node:crypto';
import {z} from 'zod';
import {db} from './db';
import {parameters,LayoutParameterError} from './layout-parameters';
import layouts from '../content/studio-layouts.json';
export const designInput=z.object({layoutId:z.string(),name:z.string().trim().min(1).max(120),parameters:z.unknown()}).strict();
export const updateDesignInput=designInput.omit({layoutId:true}).extend({revision:z.number().int().positive()}).strict();
export function designOutput(r:Record<string,unknown>){return {id:r.id,layoutId:r.layout_id,name:r.name,parameters:r.parameters,revision:r.revision,createdAt:r.created_at,updatedAt:r.updated_at,url:'/studio/designs/'+r.id,renderUrl:'/studio/api/layouts/'+r.layout_id};}
export async function validateDesign(layoutId:string,raw:unknown){const layout=layouts.find(l=>l.id===layoutId);if(!layout)throw new LayoutParameterError('排版不存在');const p=parameters(layout,raw),images=[...new Set(Object.values(p.images).flatMap(i=>i.assetId?[i.assetId]:[]))];if(images.length){const found=await db().query("SELECT id FROM assets WHERE kind='image' AND id=ANY($1::uuid[])",[images]);if(found.rowCount!==images.length)throw new LayoutParameterError('引用的图片素材不存在')}return p;}
export async function createDesign(input:z.infer<typeof designInput>){const p=await validateDesign(input.layoutId,input.parameters);const r=await db().query('INSERT INTO studio_designs(id,layout_id,name,parameters) VALUES($1,$2,$3,$4) RETURNING *',[randomUUID(),input.layoutId,input.name,JSON.stringify(p)]);return designOutput(r.rows[0]);}