50 lines
4.9 KiB
JavaScript
50 lines
4.9 KiB
JavaScript
import { z } from 'zod';
|
|
import { webScreenshotArtifactSchema } from '../webScreenshot.js';
|
|
const sampling = { step_id:z.string().min(1).max(80), frames:z.number().int().min(0).max(24).default(1), interval_ms:z.number().int().min(16).max(500).default(50) };
|
|
const target = {selector:z.string().min(1).max(500),index:z.number().int().min(0).max(100).optional()};
|
|
export const electronVisualProbeInputSchema = z.strictObject({
|
|
include_fonts:z.boolean().default(false),
|
|
include_message_content:z.boolean().default(false),
|
|
media_selectors:z.array(z.string().trim().min(1).max(500)).max(4).default([]),
|
|
track_selectors:z.array(z.string().min(1).max(500)).max(12).default([]),
|
|
actions:z.array(z.discriminatedUnion('kind',[
|
|
z.strictObject({...sampling,...target,kind:z.literal('hover')}),
|
|
z.strictObject({...sampling,...target,kind:z.literal('click'),restore:z.boolean().default(false)}),
|
|
z.strictObject({...sampling,...target,kind:z.literal('text'),text:z.string().max(2048).refine(value=>!/[\u0000-\u001f\u007f]/u.test(value),'Single-line text only')}),
|
|
z.strictObject({...sampling,...target,kind:z.literal('scroll'),delta_y:z.number().min(-3000).max(3000),restore:z.boolean().default(false)}),
|
|
z.strictObject({...sampling,kind:z.literal('key'),selector:z.string().min(1).max(500).optional(),index:z.number().int().min(0).max(100).optional(),key:z.enum(['Escape','Enter','Tab','ArrowDown','ArrowUp','ArrowLeft','ArrowRight','Home','End',' ','+','-','0']),modifiers:z.number().int().min(0).max(15).default(0)}),
|
|
z.strictObject({...sampling,kind:z.literal('wait'),duration_ms:z.number().int().min(0).max(2000)}),
|
|
z.strictObject({...sampling,kind:z.literal('viewport'),width:z.number().int().min(160).max(3840),height:z.number().int().min(160).max(2160)})
|
|
,z.strictObject({...sampling,kind:z.literal('media'),reduced_motion:z.enum(['reduce','no-preference'])})
|
|
])).max(12).default([])
|
|
}).superRefine((value,ctx)=>{
|
|
if(value.actions.reduce((n,a)=>n+a.frames,0)>64)ctx.addIssue({code:'custom',message:'At most 64 scenario frames'});
|
|
if(value.actions.reduce((n,a)=>n+a.frames*a.interval_ms+(a.duration_ms??0),0)>15000)ctx.addIssue({code:'custom',message:'Declared sampling and waits must fit 15 seconds'});
|
|
if(new Set(value.actions.map(a=>a.step_id)).size!==value.actions.length)ctx.addIssue({code:'custom',message:'Step IDs must be unique'});
|
|
if(new Set(value.media_selectors).size!==value.media_selectors.length)ctx.addIssue({code:'custom',message:'Media selectors must be unique'});
|
|
});
|
|
const mediaIdentity = {
|
|
selector:z.string(),frame_id:z.string(),node_index:z.number().int().optional(),backend_node_id:z.number().int().optional(),
|
|
selected_node:z.object({node_name:z.literal('IMG'),attributes:z.record(z.string(),z.string()),current_source_url:z.string().nullable()}).optional(),
|
|
visibility:z.object({status:z.enum(['observed','covered','unknown']),reason:z.string().optional()}).optional(),
|
|
visibility_samples:z.array(z.object({x:z.number(),y:z.number(),hit_backend_node_id:z.number().int().optional(),hit_node_index:z.number().int().optional(),hit_node_name:z.string().optional(),hit_class:z.string().optional()})).max(9).optional(),
|
|
source:z.object({url:z.string().nullable(),url_sha256:z.string().regex(/^[a-f0-9]{64}$/),selection:z.enum(['current_source_url','src']),mime_type:z.string()}).optional()
|
|
};
|
|
export const electronMediaAssetsSchema = z.object({
|
|
items:z.array(z.discriminatedUnion('status',[
|
|
z.object({...mediaIdentity,status:z.literal('exported'),artifact:z.object({mime_type:z.enum(['image/png','image/jpeg','image/gif','image/webp']),bytes:z.number().int().positive().max(2097152),sha256:z.string().regex(/^[a-f0-9]{64}$/),data_base64:z.string().max(2796204)})}),
|
|
z.object({...mediaIdentity,status:z.literal('unknown'),reason:z.string()})
|
|
])).max(4),
|
|
total_bytes:z.number().int().min(0).max(8388608),
|
|
limits:z.object({max_assets:z.literal(4),max_asset_bytes:z.literal(2097152),max_total_bytes:z.literal(8388608)}),
|
|
limitations:z.array(z.string())
|
|
});
|
|
export const platformFontSampleSchema = z.object({category:z.string(),text:z.string().max(256),fontFamily:z.string(),codeContext:z.enum(['inline','block']).optional(),platformFonts:z.array(z.object({familyName:z.string(),postScriptName:z.string(),isCustomFont:z.boolean(),glyphCount:z.number().int().min(0)}))});
|
|
export const visualProbeOutputSchema = z.object({
|
|
status:z.enum(['completed','failed']),
|
|
steps:z.array(z.object({step_id:z.string(),kind:z.string(),status:z.enum(['completed','failed']),error:z.string().nullable(),action_completed_at_ms:z.number().optional()})),
|
|
frames:z.array(z.object({step_id:z.string(),at_ms:z.number(),artifact:webScreenshotArtifactSchema,regions:z.array(z.object({selector:z.string(),bounds:z.tuple([z.number(),z.number(),z.number(),z.number()]).nullable()}))})),
|
|
restoration:z.array(z.object({kind:z.string(),status:z.enum(['completed','failed']),error:z.string().nullable()})),
|
|
limitations:z.array(z.string())
|
|
});
|