import { z } from 'zod'; import type { PortfolioContent, PublicAssetManifest, ProductionInputs, SiteConfig } from './types.ts'; const canonicalNavigationIds = [ 'start', 'profile', 'experience', 'infrastructure', 'selected-builds', 'additional-work', 'toolkit', 'contact', ] as const; const socialHosts = { GitHub: 'github.com', GitLab: 'gitlab.com', LinkedIn: 'linkedin.com', } as const; const approvedPrivateProjectTitles = [ 'Private self-hosted medication tracker', 'Private healthcare platform', 'Private game prototype', ] as const; const hasUnpairedSurrogate = (value: string): boolean => { for (let index = 0; index < value.length; index += 1) { const codeUnit = value.charCodeAt(index); if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) { const next = value.charCodeAt(index + 1); if (next < 0xdc00 || next > 0xdfff) return true; index += 1; } else if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) { return true; } } return false; }; const hasVisibleCopy = (value: string): boolean => value.trim().length > 0 && value === value.normalize('NFC') && !hasUnpairedSurrogate(value) && !/[\u0000-\u001f\u007f]/u.test(value); const visibleString = z.string().refine(hasVisibleCopy, 'Visible copy must be non-empty, well-formed Unicode, NFC-normalized, and control-character free.'); const opaqueId = z.string().regex(/^[a-z][a-z0-9-]{0,63}$/, 'IDs must be generated safe identifiers.'); const httpUrl = z.string().refine((value) => { if (value !== value.normalize('NFC') || hasUnpairedSurrogate(value) || /[\u0000-\u001f\u007f]/u.test(value)) { return false; } try { const url = new URL(value); const authority = /^https:\/\/([^/?#]+)/u.exec(value)?.[1]; return url.protocol === 'https:' && !url.username && !url.password && !url.search && !url.hash && authority !== undefined && !authority.includes(':'); } catch { return false; } }, 'URL must be an absolute HTTPS URL without credentials, query, or fragment.'); const navigationItemSchema = z.object({ id: z.enum(canonicalNavigationIds), label: visibleString, }).strict(); const soundtrackAssetSourcesSchema = z.object({ opusAssetId: opaqueId, mp3AssetId: opaqueId, }).strict(); const mediaPresentationBase = { assetId: opaqueId, alt: visibleString, caption: visibleString.optional(), longDescription: visibleString.optional(), }; const mediaTableSchema = z.object({ caption: visibleString, columns: z.array(visibleString).min(2), rows: z.array(z.array(visibleString).min(2)).min(1), }).strict().superRefine((table, context) => { for (const [index, row] of table.rows.entries()) { if (row.length !== table.columns.length) { context.addIssue({ code: 'custom', message: 'Every chart table row must match the column count.', path: ['rows', index] }); } } }); const mediaPresentationSchema = z.discriminatedUnion('kind', [ z.object({ kind: z.literal('image'), ...mediaPresentationBase }).strict(), z.object({ kind: z.literal('video'), ...mediaPresentationBase, fallbackAssetId: opaqueId.optional(), posterAssetId: opaqueId, caption: visibleString, longDescription: visibleString, }).strict(), z.object({ kind: z.literal('chart'), ...mediaPresentationBase, caption: visibleString, chart: z.object({ variables: visibleString, trend: visibleString, conclusion: visibleString, table: mediaTableSchema.optional(), }).strict(), }).strict(), ]); const projectSchema = z.object({ id: opaqueId, title: visibleString, visibility: z.enum(['public', 'private']), maturity: z.enum(['learning', 'experimental', 'prototype', 'work-in-progress', 'active']), summary: visibleString, problem: visibleString, contribution: visibleString, technicalDecisions: z.array(visibleString).min(1), outcome: visibleString, url: httpUrl.optional(), assetIds: z.array(opaqueId), media: z.array(mediaPresentationSchema).optional(), mediaLayout: z.enum(['single', 'portrait-strip', 'chart-pair']).optional(), }).strict().superRefine((project, context) => { if (project.visibility === 'private' && project.url !== undefined) { context.addIssue({ code: 'custom', message: 'A private project may not include a url.', path: ['url'] }); } if (project.visibility === 'private' && !approvedPrivateProjectTitles.includes(project.title as (typeof approvedPrivateProjectTitles)[number])) { context.addIssue({ code: 'custom', message: 'Private project title must use an approved generic title.', path: ['title'] }); } if (project.media !== undefined) { const mediaAssetIds = project.media.flatMap((media) => media.kind === 'video' ? [media.assetId, ...(media.fallbackAssetId === undefined ? [] : [media.fallbackAssetId]), media.posterAssetId] : [media.assetId]); const declared = [...project.assetIds].sort(); const presented = [...mediaAssetIds].sort(); if (new Set(declared).size !== declared.length || new Set(presented).size !== presented.length || JSON.stringify(declared) !== JSON.stringify(presented)) { context.addIssue({ code: 'custom', message: 'Project media must have an exact, duplicate-free asset closure.', path: ['assetIds'], }); } } if (project.mediaLayout !== undefined && (project.media === undefined || project.media.length === 0)) { context.addIssue({ code: 'custom', message: 'Project mediaLayout requires at least one media presentation.', path: ['mediaLayout'], }); } }); const portfolioContentSchema = z.object({ identity: z.object({ name: z.literal('Luca Pîslaru'), role: z.literal('System Administrator & Full-Stack Developer'), valueProposition: visibleString, location: z.object({ city: visibleString, country: visibleString, countryCode: z.string().regex(/^[A-Z]{2}$/, 'Country code must be a two-letter uppercase code.'), }).strict(), availability: visibleString, }).strict(), navigation: z.array(navigationItemSchema).length(8), profile: z.object({ introduction: visibleString, screeningFacts: z.array(z.object({ label: visibleString, value: visibleString }).strict()), }).strict(), experience: z.array(z.object({ id: opaqueId, role: visibleString, organization: visibleString, dates: visibleString, location: visibleString.optional(), highlights: z.array(visibleString).min(2).max(4), }).strict()).min(1), systemsOperations: z.object({ id: opaqueId, title: z.literal('Professional systems operations'), summary: visibleString, evidence: z.array(visibleString).min(1), }).strict(), infrastructure: z.object({ id: opaqueId, title: z.literal('Secure self-hosted platform and lifecycle'), summary: visibleString, bands: z.array(z.object({ id: opaqueId, title: visibleString, summary: visibleString }).strict()).length(4), featuredOperation: z.object({ title: visibleString, context: visibleString, actions: z.array(visibleString).min(3).max(6), outcome: visibleString, }).strict(), }).strict(), projects: z.object({ selected: z.array(projectSchema).length(3), additional: z.array(projectSchema).min(1), }).strict(), toolkit: z.array(z.object({ title: visibleString, technologies: z.array(z.object({ name: visibleString, assetId: opaqueId.optional() }).strict()).min(1), }).strict()).min(1), contact: z.object({ introduction: visibleString, email: z.object({ localPart: visibleString, domain: visibleString }).strict().refine( ({ localPart, domain }) => !localPart.includes('@') && !domain.includes('@') && z.email().safeParse(`${localPart}@${domain}`).success, 'Contact email parts must form a valid address.', ), avatarAssetId: opaqueId.optional(), social: z.array(z.object({ service: z.enum(['GitHub', 'GitLab', 'LinkedIn']), url: httpUrl, }).strict()).superRefine((links, context) => { for (const [index, link] of links.entries()) { const host = new URL(link.url).hostname; if (host !== socialHosts[link.service]) { context.addIssue({ code: 'custom', message: `Social URL must use the approved ${link.service} host.`, path: [index, 'url'] }); } } }), cvMessage: visibleString, }).strict(), metadata: z.object({ title: visibleString, description: visibleString, socialPreviewAssetId: opaqueId.optional(), }).strict(), soundtrack: z.object({ intro: soundtrackAssetSourcesSchema, main: soundtrackAssetSourcesSchema, afterglow: soundtrackAssetSourcesSchema, driveLift: soundtrackAssetSourcesSchema, }).strict().optional(), sceneDescription: visibleString, }).strict().superRefine((content, context) => { const navigationIds = content.navigation.map((item) => item.id); if (new Set(navigationIds).size !== canonicalNavigationIds.length || canonicalNavigationIds.some((id) => !navigationIds.includes(id))) { context.addIssue({ code: 'custom', message: 'Navigation must contain each canonical section ID exactly once.', path: ['navigation'] }); } const projects = [...content.projects.selected, ...content.projects.additional]; const projectIds = projects.map((project) => project.id); if (new Set(projectIds).size !== projectIds.length) { context.addIssue({ code: 'custom', message: 'Project IDs must be unique.', path: ['projects'] }); } if (content.projects.selected.filter((project) => project.maturity === 'experimental').length !== 1) { context.addIssue({ code: 'custom', message: 'Selected builds must include exactly one supporting experimental research panel.', path: ['projects', 'selected'] }); } const experienceIds = content.experience.map((record) => record.id); if (new Set(experienceIds).size !== experienceIds.length) { context.addIssue({ code: 'custom', message: 'Experience IDs must be unique.', path: ['experience'] }); } const bandIds = content.infrastructure.bands.map((band) => band.id); if (new Set(bandIds).size !== bandIds.length) { context.addIssue({ code: 'custom', message: 'Infrastructure band IDs must be unique.', path: ['infrastructure', 'bands'] }); } }); const mediaTypes = [ 'image/avif', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/webp', 'video/mp4', 'video/webm', 'audio/ogg', 'audio/mpeg', ] as const; const fileExtensionByMediaType: Record<(typeof mediaTypes)[number], string> = { 'image/avif': 'avif', 'image/jpeg': 'jpg', 'image/png': 'png', 'image/svg+xml': 'svg', 'image/webp': 'webp', 'video/mp4': 'mp4', 'video/webm': 'webm', 'audio/ogg': 'opus', 'audio/mpeg': 'mp3', }; const publicAssetSchema = z.object({ id: opaqueId, fileName: z.string().regex(/^[a-z0-9][a-z0-9-]*\.(avif|jpg|png|svg|webp|mp4|webm|opus|mp3)$/, 'Asset filenames must be generated safe filenames.'), sha256: z.string().regex(/^[a-f0-9]{64}$/, 'Asset sha256 must be lowercase hexadecimal.'), mediaType: z.enum(mediaTypes), width: z.number().int().positive().nullable(), height: z.number().int().positive().nullable(), durationMs: z.number().int().positive().nullable(), rightsHolder: visibleString, license: visibleString, attribution: visibleString, }).strict().superRefine((asset, context) => { if (!asset.fileName.endsWith(`.${fileExtensionByMediaType[asset.mediaType]}`)) { context.addIssue({ code: 'custom', message: 'Asset filename extension must match media type.', path: ['fileName'] }); } const image = asset.mediaType.startsWith('image/'); const video = asset.mediaType.startsWith('video/'); const audio = asset.mediaType.startsWith('audio/'); if (image && (asset.width === null || asset.height === null || asset.durationMs !== null)) { context.addIssue({ code: 'custom', message: 'Image assets require dimensions and no duration.', path: ['width'] }); } if (video && (asset.width === null || asset.height === null || asset.durationMs === null)) { context.addIssue({ code: 'custom', message: 'Video assets require dimensions and duration.', path: ['durationMs'] }); } if (audio && (asset.width !== null || asset.height !== null || asset.durationMs === null)) { context.addIssue({ code: 'custom', message: 'Audio assets require null dimensions and a positive duration.', path: ['durationMs'] }); } }); const publicAssetManifestSchema = z.object({ assets: z.array(publicAssetSchema) }).strict().superRefine((manifest, context) => { const ids = manifest.assets.map((asset) => asset.id); if (new Set(ids).size !== ids.length) { context.addIssue({ code: 'custom', message: 'Duplicate asset ID in manifest.', path: ['assets'] }); } const filenames = manifest.assets.map((asset) => asset.fileName); if (new Set(filenames).size !== filenames.length || new Set(filenames.map((name) => name.toLocaleLowerCase('en-US'))).size !== filenames.length) { context.addIssue({ code: 'custom', message: 'Asset filenames must be unique without case-fold collisions.', path: ['assets'] }); } }); const siteConfigSchema = z.object({ environment: z.enum(['preview', 'production']), canonicalUrl: httpUrl, buildId: z.string().regex(/^[a-z0-9][a-z0-9._-]{0,127}$/, 'Build ID must be a safe immutable identifier.'), }).strict().superRefine((site, context) => { if (site.environment === 'preview' && site.canonicalUrl !== 'https://portfolio.localhost/') { context.addIssue({ code: 'custom', message: 'Preview canonical URL must be exactly https://portfolio.localhost/.', path: ['canonicalUrl'] }); } if (site.environment === 'production') { context.addIssue({ code: 'custom', message: 'Production hostname is not approved.', path: ['canonicalUrl'] }); } }); export const parsePortfolioContent = (input: unknown): PortfolioContent => portfolioContentSchema.parse(input) as PortfolioContent; export const parsePublicAssetManifest = (input: unknown): PublicAssetManifest => publicAssetManifestSchema.parse(input) as PublicAssetManifest; export const parseSiteConfig = (input: unknown): SiteConfig => siteConfigSchema.parse(input) as SiteConfig; const productionInputsSchema = z.object({ content: portfolioContentSchema, manifest: publicAssetManifestSchema, site: siteConfigSchema, }).strict(); export const parseProductionInputSnapshot = (input: unknown): ProductionInputs => { const { content, manifest, site } = productionInputsSchema.parse(input); const manifestIds = new Set(manifest.assets.map((asset) => asset.id)); const referencedAssetIds = [ ...(content.contact.avatarAssetId === undefined ? [] : [content.contact.avatarAssetId]), ...content.projects.selected.flatMap((project) => project.assetIds), ...content.projects.additional.flatMap((project) => project.assetIds), ...content.toolkit.flatMap((group) => group.technologies.flatMap((technology) => technology.assetId === undefined ? [] : [technology.assetId])), ...(content.metadata.socialPreviewAssetId === undefined ? [] : [content.metadata.socialPreviewAssetId]), ...(content.soundtrack === undefined ? [] : [ content.soundtrack.intro.opusAssetId, content.soundtrack.intro.mp3AssetId, content.soundtrack.main.opusAssetId, content.soundtrack.main.mp3AssetId, content.soundtrack.afterglow.opusAssetId, content.soundtrack.afterglow.mp3AssetId, content.soundtrack.driveLift.opusAssetId, content.soundtrack.driveLift.mp3AssetId, ]), ]; const seenReferences = new Set(); for (const assetId of referencedAssetIds) { if (seenReferences.has(assetId)) { throw new Error(`Duplicate public asset reference: ${assetId}`); } seenReferences.add(assetId); if (!manifestIds.has(assetId)) { throw new Error(`Unmanifested asset reference: ${assetId}`); } } for (const assetId of manifestIds) { if (!seenReferences.has(assetId)) { throw new Error(`Unreferenced manifest asset: ${assetId}`); } } return { content, manifest, site } as ProductionInputs; }; export const validateProductionInputs = ( contentInput: unknown, manifestInput: unknown, siteInput: unknown, _preparedAssetRoot: URL, ): ProductionInputs => parseProductionInputSnapshot({ content: contentInput, manifest: manifestInput, site: siteInput, });