/* Shared Zod schemas for the content-declared feature graph (RFC-0018). App-agnostic — every app that adopts RFC-0018 imports from here instead of copy-pasting. Canonical home per RFC-0033. Do not import from astro:content or apps/*. Do not handle runtime resolution or navigation logic. Do not manage state or side effects. RFC-0033: Moved from app content schemas/features to @warpgogol/werkstatt-shared/schemas. Import switched from "astro/zod" to "zod" for framework neutrality. RFC-0183: Added Feature Policy schema for policy embedded in existing RFC-0047 content domains. */ // [RFC-0018] Feature graph schemas — canonical implementation in packages/share. // Import z from "zod" — not "astro/zod" — so this package stays framework-neutral. import { z } from "zod"; const featureVisibilitySchema = z.enum(["enabled", "disabled"]); export const featurePolicyVisibilitySchema = z.enum(["enabled", "disabled", "hidden", "draft"]); export const featurePolicyBehaviorValueSchema = z.union([ z.string(), z.number(), z.boolean(), z.null(), ]); export const featurePolicySchema = z.object({ visibility: featurePolicyVisibilitySchema.optional(), behavior: z.record(z.string(), featurePolicyBehaviorValueSchema).optional(), reason: z.string().optional(), expiresAt: z.string().optional(), audience: z.string().optional(), }); export const featurePolicyTargetKindSchema = z.enum(["page", "section", "component", "item"]); export const featurePolicyTargetRefSchema = z.object({ kind: featurePolicyTargetKindSchema, pageId: z.string().optional(), blockId: z.string().optional(), componentId: z.string().optional(), itemId: z.string().optional(), lang: z.string().optional(), }); export const resolvedFeaturePolicySchema = z.object({ target: featurePolicyTargetRefSchema, visibility: featurePolicyVisibilitySchema, behavior: z.record(z.string(), featurePolicyBehaviorValueSchema), sourcePath: z.string(), inheritedFrom: featurePolicyTargetRefSchema.optional(), }); const behaviorOverrideSchema = z.record(z.string(), z.any()); export const featureItemSchema = z.object({ id: z.string(), visibility: featureVisibilitySchema, behavior: behaviorOverrideSchema.optional(), }); export const featureComponentSchema = z.object({ id: z.string(), componentPath: z.string(), anchor: z.string(), visibility: featureVisibilitySchema, items: z.array(featureItemSchema).optional(), }); /** * Broad feature-graph category for a section node (RFC-0018). * * This is a FEATURE-GRAPH concept — it determines how the visibility engine * classifies and processes a section. It is NOT the per-section SemanticRole * from @warpgogol/werkstatt-shared/ontology (DNA-17, RFC-0023), which identifies each section * individually (hero, dna, final-cta, …) and lives in manifest.yaml. * * SectionKind values: * navigation — anchored nav / in-page links * hero — primary above-the-fold section * content — main informational section * supporting — supplementary / secondary section * cta — conversion / call-to-action section * custom — does not fit the above categories */ export const sectionKindSchema = z.enum([ "navigation", "hero", "content", "supporting", "cta", "custom", ]); export const featureSectionSchema = z.object({ id: z.string(), role: sectionKindSchema, anchor: z.string(), visibility: featureVisibilitySchema, components: z.array(featureComponentSchema), }); export const featurePageSchema = z.object({ id: z.string(), routeSlug: z.string(), visibility: featureVisibilitySchema, sections: z.array(featureSectionSchema), }); export const sharedComponentFeatureSchema = z.object({ id: z.string(), componentPath: z.string(), anchor: z.string(), visibility: featureVisibilitySchema, items: z.array(featureItemSchema).optional(), }); export const siteFeaturesSchema = z .object({ kind: z.enum(["page", "sharedComponent"]), }) .loose(); export type FeatureVisibility = z.infer; export type FeaturePolicyVisibility = z.infer; export type FeaturePolicyBehaviorValue = z.infer; export type FeaturePolicy = z.infer; export type FeaturePolicyTargetKind = z.infer; export type FeaturePolicyTargetRef = z.infer; export type ResolvedFeaturePolicy = z.infer; export type BehaviorOverride = z.infer; /** @see sectionKindSchema for the distinction between SectionKind and SemanticRole */ export type SectionKind = z.infer; export type FeatureItem = z.infer; export type FeatureComponent = z.infer; export type FeatureSection = z.infer; export type FeaturePage = z.infer; export type SharedComponentFeature = z.infer; export type SiteFeature = z.infer;