import { z } from "zod"; /** * Contract version stamped on every defined view — lets the host and the * generated artifact evolve the contract without breaking deployed views. * @internal */ export const VIEW_CONTRACT_VERSION = 1; /** * A view component. The return is opaque so `@sanity/federation` carries no * React dependency — the generated artifact renders it with the app's own React. * @public */ export type ViewComponent = (props: TProps) => unknown; /** * Props every view component receives, whatever its type. Per-type props * compose from this, so a prop added here reaches every view. * @public */ export interface ViewComponentBaseProps { view: TView; } /** * Fields every extension declaration shares — a view or a service. The shape is * identical (`name` + `src`); `kind` only tailors the validation message. Each * declaration adds its `type` discriminator on top. */ export function extensionDeclarationFields(kind: "View" | "Service") { const pattern = /^[a-zA-Z0-9_-]+$/; return { name: z.string().regex(pattern, `${kind} \`name\` must match ${pattern}`), src: z.string(), }; } /** Fields every view declaration shares. */ export const viewBaseFields = extensionDeclarationFields("View"); /** * Fields every interface record carries — snake_case to match the application * service's JSON. Per-type schemas add their discriminator on top. */ export const interfaceBaseFields = { id: z.string(), deployment_id: z.string(), name: z.string(), entry_point: z.string(), };