import type { FunnelManifest } from '@funnelsgrove/runtime'; import { CURRENT_STEP_CONTRACT_VERSION, DEFAULT_FUNNEL_BREAKPOINTS, } from '@funnelsgrove/runtime'; export const templateArchitectureVersion = 1; export const rawFunnelManifest = { templateArchitectureVersion, stepContractVersion: CURRENT_STEP_CONTRACT_VERSION, meta: { title: 'Funnel Project', description: 'Lightweight starter funnel with email capture and a single paywall.', }, viewport: { width: 430, height: 932, }, breakpoints: DEFAULT_FUNNEL_BREAKPOINTS, assets: { emailCapturePreview: { type: 'image', src: '/assets/email-capture-preview.svg', width: 160, height: 120, preload: 'idle', }, paywallPreview: { type: 'image', src: '/assets/paywall-preview.svg', width: 160, height: 120, preload: 'idle', }, moneyBackBadge: { type: 'image', src: '/paywall/money-back-badge.jpg', width: 368, height: 368, preload: 'idle', }, }, steps: [ { id: 'step-1', path: '/step-1', filePath: 'src/steps/step-01.tsx', componentKey: 'stepOne', name: 'step-1', type: 'intro_hero', title: 'Step 1', }, { id: 'email-capture', path: '/email-capture', filePath: 'src/steps/step-31-email-capture.tsx', componentKey: 'stepEmailCapture', name: 'email-capture', type: 'form_input', title: 'Email Capture', assetIds: ['emailCapturePreview'], }, { id: 'paywall', path: '/paywall', filePath: 'src/steps/step-32-paywall.tsx', componentKey: 'stepPaywall', name: 'paywall', type: 'paywall_offer', kind: 'paywall', title: 'Paywall', assetIds: ['paywallPreview', 'moneyBackBadge'], }, { id: 'subscription-started', path: '/subscription-started', filePath: 'src/steps/step-33-subscription-started.tsx', componentKey: 'stepSubscriptionStarted', name: 'subscription-started', type: 'purchase_completed', kind: 'subscription-handoff', title: 'Subscription Started', }, ], edgesByStepId: { 'step-1': [{ toStepId: 'email-capture' }], 'email-capture': [{ toStepId: 'paywall' }], paywall: [{ toStepId: 'subscription-started' }], }, // Experiments are delivered by the version-bound runtime artifact. experiments: [], } as const satisfies FunnelManifest; // Keep the authored object readable by the project validator. Eager validation // would throw while this module imports and turn an actionable contract error // into an opaque runner failure. type TemplateFunnelManifest = Omit & { readonly steps: readonly ( (typeof rawFunnelManifest.steps)[number] & FunnelManifest['steps'][number] )[]; }; export const funnelManifest = rawFunnelManifest as TemplateFunnelManifest; export type FunnelStepId = (typeof funnelManifest.steps)[number]['id']; export type FunnelStepComponentKey = (typeof funnelManifest.steps)[number]['componentKey'];