import {z} from 'zod'; export function credentialActionUrlAllowed(value){ try {const u=new URL(value);return u.protocol==='https:'&&!u.username&&!u.password&&!u.search&&!u.hash&&!value.includes('?')&&!value.includes('#')&&u.href===value&&!/[\u0000-\u0020\u007f]/.test(value);}catch{return false;} } const field=z.string().min(1).max(128).regex(/^[\x21-\x7e]+$/,'Credential field names require bounded printable ASCII'); export const CredentialSubmissionFormSchema=z.object({ id:z.string().min(1).max(80).regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/), actionUrl:z.string().max(4096).refine(credentialActionUrlAllowed,'An exact canonical HTTPS action URL without credentials, query or fragment is required'), usernameField:field,passwordField:field }).strict().superRefine((rule,context)=>{if(rule.usernameField===rule.passwordField)context.addIssue({code:'custom',path:['passwordField'],message:'Username and password fields must differ'});}); export const ControlledSubmissionSchema=z.object({enabled:z.boolean().default(false),forms:z.array(CredentialSubmissionFormSchema).max(32).default([])}).strict().superRefine((value,context)=>{ const ids=new Set(),targets=new Set();value.forms.forEach((rule,index)=>{if(ids.has(rule.id))context.addIssue({code:'custom',path:['forms',index,'id'],message:'Credential rule identifiers must be unique'});ids.add(rule.id);const signature=JSON.stringify([rule.actionUrl,rule.usernameField,rule.passwordField]);if(targets.has(signature))context.addIssue({code:'custom',path:['forms',index],message:'Duplicate credential target and field signature'});targets.add(signature);}); if(value.enabled&&!value.forms.length)context.addIssue({code:'custom',path:['forms'],message:'Enablement requires at least one approved login POST target'}); }).prefault({});