create-ailk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -3
- package/component-catalog.md +295 -0
- package/dist/cli.js +92 -16
- package/dist/component-catalog.d.ts +11 -0
- package/dist/component-catalog.js +39 -0
- package/dist/copy.d.ts +7 -0
- package/dist/copy.js +24 -0
- package/dist/derive-architecture.d.ts +13 -0
- package/dist/derive-architecture.js +238 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +19 -2
- package/dist/lib/extract-module-bundle.d.ts +16 -0
- package/dist/lib/extract-module-bundle.js +184 -0
- package/dist/lib/fetch-module.d.ts +55 -0
- package/dist/lib/fetch-module.js +125 -0
- package/dist/lib/module-license-gate.d.ts +48 -0
- package/dist/lib/module-license-gate.js +67 -0
- package/dist/lib/module-tier.d.ts +35 -0
- package/dist/lib/module-tier.js +37 -0
- package/dist/module-architecture.d.ts +175 -0
- package/dist/module-architecture.js +663 -0
- package/dist/parse-args.d.ts +47 -1
- package/dist/parse-args.js +143 -2
- package/dist/programmatic.d.ts +160 -3
- package/dist/programmatic.js +196 -7
- package/dist/surfaces.d.ts +211 -0
- package/dist/surfaces.js +532 -0
- package/dist/sync-routes.d.ts +92 -0
- package/dist/sync-routes.js +350 -0
- package/package.json +22 -14
- package/templates/.claude/rules/architecture.md +6 -2
- package/templates/.claude/skills/README.md +9 -9
- package/templates/.claude/skills/add-schema/SKILL.md +14 -7
- package/templates/.claude/skills/add-schema/references/schema-types.md +109 -6
- package/templates/.claude/skills/provision-config/SKILL.md +1 -1
- package/templates/.claude/skills/scaffold-commerce/SKILL.md +498 -1
- package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +370 -0
- package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +376 -0
- package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +471 -0
- package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +365 -0
- package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +60 -0
- package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +446 -0
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +4 -4
- package/templates/.env.example +126 -2
- package/templates/CLAUDE.md +11 -5
- package/templates/README.md +1 -1
- package/templates/apps/api/.env.example +38 -0
- package/templates/apps/api/CLAUDE.md +75 -1
- package/templates/apps/api/LICENSE +201 -0
- package/templates/apps/api/api/index.ts +6 -141
- package/templates/apps/api/jest.config.cjs +16 -0
- package/templates/apps/api/package.json +22 -6
- package/templates/apps/api/src/__tests__/module-exclusion.test.ts +141 -0
- package/templates/apps/api/src/__tests__/server.test.ts +46 -0
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +211 -0
- package/templates/apps/api/src/bin/abandon-sweep.ts +42 -0
- package/templates/apps/api/src/bin/deliverable-resend.ts +144 -0
- package/templates/apps/api/src/bin/deliverable-upload.ts +114 -0
- package/templates/apps/api/src/bin/followup-sweep.ts +44 -0
- package/templates/apps/api/src/bin/listing-csv-sweep.ts +46 -0
- package/templates/apps/api/src/bin/seed-presets.ts +58 -0
- package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +104 -0
- package/templates/apps/api/src/bin/session-retention-sweep.ts +46 -0
- package/templates/apps/api/src/cli.ts +5 -11
- package/templates/apps/api/src/config/index.ts +35 -0
- package/templates/apps/api/src/config/modules.ts +43 -0
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +11 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +231 -0
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +2 -2
- package/templates/apps/api/src/lib/site.ts +16 -0
- package/templates/apps/api/src/lib/stripe.ts +22 -0
- package/templates/apps/api/src/lib/tenant-db.ts +225 -0
- package/templates/apps/api/src/lib/ws-token.ts +91 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +7 -1
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +7 -1
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +91 -4
- package/templates/apps/api/src/middleware/auth.ts +43 -8
- package/templates/apps/api/src/middleware/rate-limit.ts +78 -3
- package/templates/apps/api/src/middleware/tenant.ts +99 -0
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +92 -0
- package/templates/apps/api/src/openapi/spec.ts +312 -3
- package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +175 -0
- package/templates/apps/api/src/routes/aeo/index.ts +107 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +5 -2
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +22 -3
- package/templates/apps/api/src/routes/auth/tokens.ts +13 -1
- package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +450 -0
- package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +262 -0
- package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +436 -0
- package/templates/apps/api/src/routes/billing/index.ts +36 -0
- package/templates/apps/api/src/routes/billing/portal.ts +182 -0
- package/templates/apps/api/src/routes/billing/read.ts +75 -0
- package/templates/apps/api/src/routes/billing/usage.ts +153 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +99 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +20 -8
- package/templates/apps/api/src/routes/content/create.ts +1 -0
- package/templates/apps/api/src/routes/content/delete.ts +1 -0
- package/templates/apps/api/src/routes/content/index.ts +42 -6
- package/templates/apps/api/src/routes/content/update.ts +1 -0
- package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +393 -0
- package/templates/apps/api/src/routes/deliverables/index.ts +200 -0
- package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +443 -0
- package/templates/apps/api/src/routes/flow-checkouts/index.ts +82 -0
- package/templates/apps/api/src/routes/flows/README.md +147 -0
- package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +752 -0
- package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +671 -0
- package/templates/apps/api/src/routes/flows/index.ts +202 -0
- package/templates/apps/api/src/routes/flows/recommender.ts +443 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +438 -31
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +10 -10
- package/templates/apps/api/src/routes/leads/index.ts +43 -9
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +547 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +815 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +742 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +424 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +364 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +566 -0
- package/templates/apps/api/src/routes/project-listings/get.ts +70 -0
- package/templates/apps/api/src/routes/project-listings/index.ts +105 -0
- package/templates/apps/api/src/routes/project-listings/list.ts +47 -0
- package/templates/apps/api/src/routes/project-listings/patch-copy.ts +222 -0
- package/templates/apps/api/src/routes/project-listings/patch-draft.ts +97 -0
- package/templates/apps/api/src/routes/project-listings/patch.ts +136 -0
- package/templates/apps/api/src/routes/project-listings/public.ts +52 -0
- package/templates/apps/api/src/routes/project-listings/respond.ts +37 -0
- package/templates/apps/api/src/routes/project-listings/resume-token.ts +22 -0
- package/templates/apps/api/src/routes/project-listings/start.ts +98 -0
- package/templates/apps/api/src/routes/project-listings/submit.ts +122 -0
- package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +490 -0
- package/templates/apps/api/src/routes/schedule/index.ts +249 -0
- package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +385 -0
- package/templates/apps/api/src/routes/slack/actions.ts +177 -0
- package/templates/apps/api/src/routes/slack/index.ts +38 -0
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +16 -6
- package/templates/apps/api/src/routes/test/auth/session.ts +8 -6
- package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +577 -0
- package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +78 -0
- package/templates/apps/api/src/routes/waitlist-experiments/index.ts +41 -0
- package/templates/apps/api/src/routes/waitlist-experiments/list.ts +64 -0
- package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +42 -0
- package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +84 -0
- package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +119 -0
- package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +238 -0
- package/templates/apps/api/src/routes/waitlist-signups/index.ts +101 -0
- package/templates/apps/api/src/routes/webhooks/README.md +35 -12
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +315 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +270 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +248 -20
- package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +356 -0
- package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +671 -0
- package/templates/apps/api/src/routes/workspaces/config.ts +125 -0
- package/templates/apps/api/src/routes/workspaces/index.ts +194 -0
- package/templates/apps/api/src/routes/workspaces/sessions.ts +218 -0
- package/templates/apps/api/src/server.ts +293 -7
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +489 -0
- package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +475 -0
- package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +132 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +523 -0
- package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +359 -0
- package/templates/apps/api/src/services/__tests__/entitlements.test.ts +142 -0
- package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +425 -0
- package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +2840 -0
- package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +393 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +8 -8
- package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +560 -0
- package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +406 -0
- package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +290 -0
- package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +736 -0
- package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +475 -0
- package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +340 -0
- package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +983 -0
- package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +278 -0
- package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +71 -0
- package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +379 -0
- package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +941 -0
- package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +588 -0
- package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +768 -0
- package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +1314 -0
- package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +341 -0
- package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +567 -0
- package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +474 -0
- package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +354 -0
- package/templates/apps/api/src/services/abandon-email.ts +307 -0
- package/templates/apps/api/src/services/aeo-score.ts +288 -0
- package/templates/apps/api/src/services/answer-distributions.ts +138 -0
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +523 -0
- package/templates/apps/api/src/services/entitlements.ts +102 -0
- package/templates/apps/api/src/services/flow-aggregate.ts +232 -0
- package/templates/apps/api/src/services/flow-checkouts.ts +123 -0
- package/templates/apps/api/src/services/flow-engine.ts +1278 -0
- package/templates/apps/api/src/services/lead-promotion.ts +176 -0
- package/templates/apps/api/src/services/lead-routing.ts +3 -3
- package/templates/apps/api/src/services/listing-config.ts +102 -0
- package/templates/apps/api/src/services/listing-csv-sweep.ts +455 -0
- package/templates/apps/api/src/services/playbook-compile.ts +398 -0
- package/templates/apps/api/src/services/playbook-render.ts +263 -0
- package/templates/apps/api/src/services/project-listing-decision.ts +490 -0
- package/templates/apps/api/src/services/project-listing-flow.ts +426 -0
- package/templates/apps/api/src/services/project-listing-issue.ts +251 -0
- package/templates/apps/api/src/services/project-listings.ts +1124 -0
- package/templates/apps/api/src/services/recommender-capture.ts +835 -0
- package/templates/apps/api/src/services/scheduling/cal-provider.ts +392 -0
- package/templates/apps/api/src/services/scheduling/index.ts +63 -0
- package/templates/apps/api/src/services/scheduling/types.ts +88 -0
- package/templates/apps/api/src/services/slack-notify.ts +240 -0
- package/templates/apps/api/src/services/tenant-context.ts +451 -0
- package/templates/apps/api/src/services/usage-aggregation.ts +516 -0
- package/templates/apps/api/src/services/usage-credits.ts +340 -0
- package/templates/apps/api/src/services/usage-metering.ts +699 -0
- package/templates/apps/api/src/services/waitlist-dashboard.ts +947 -0
- package/templates/apps/api/src/services/waitlist-experiments.ts +213 -0
- package/templates/apps/api/src/services/waitlist-followup.ts +486 -0
- package/templates/apps/api/src/services/waitlist-scoring.ts +166 -0
- package/templates/apps/api/src/services/waitlist-signups.ts +165 -0
- package/templates/apps/api/src/vercel-handler.ts +165 -0
- package/templates/apps/api/tsconfig.json +0 -12
- package/templates/apps/mcp/CLAUDE.md +19 -9
- package/templates/apps/mcp/LICENSE +201 -0
- package/templates/apps/mcp/__tests__/create_page.test.ts +1 -0
- package/templates/apps/mcp/__tests__/delete_page.test.ts +1 -0
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +105 -0
- package/templates/apps/mcp/__tests__/parity.test.ts +70 -6
- package/templates/apps/mcp/__tests__/request_callback.test.ts +4 -4
- package/templates/apps/mcp/__tests__/schedule_tools.test.ts +242 -0
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +4 -4
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +4 -4
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +47 -0
- package/templates/apps/mcp/__tests__/update_page.test.ts +1 -0
- package/templates/apps/mcp/package.json +6 -4
- package/templates/apps/mcp/src/config/modules.ts +37 -0
- package/templates/apps/mcp/src/server.ts +109 -18
- package/templates/apps/mcp/src/tools/capture_lead.ts +1 -1
- package/templates/apps/mcp/src/tools/create_booking.ts +58 -0
- package/templates/apps/mcp/src/tools/create_page.ts +1 -0
- package/templates/apps/mcp/src/tools/delete_page.ts +1 -0
- package/templates/apps/mcp/src/tools/get_event_meta.ts +55 -0
- package/templates/apps/mcp/src/tools/get_flow.ts +61 -0
- package/templates/apps/mcp/src/tools/index.ts +25 -0
- package/templates/apps/mcp/src/tools/list_availability.ts +67 -0
- package/templates/apps/mcp/src/tools/purchase.ts +3 -0
- package/templates/apps/mcp/src/tools/submit_flow_step.ts +83 -0
- package/templates/apps/mcp/src/tools/update_page.ts +1 -0
- package/templates/apps/mcp/tsconfig.json +1 -9
- package/templates/apps/web/.env.example +44 -0
- package/templates/apps/web/CLAUDE.md +28 -0
- package/templates/apps/web/LICENSE +201 -0
- package/templates/apps/web/__tests__/__mocks__/code-highlight.jest-stub.ts +24 -0
- package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +33 -0
- package/templates/apps/web/__tests__/__mocks__/next-intl.ts +18 -0
- package/templates/apps/web/__tests__/__mocks__/server-only.ts +13 -0
- package/templates/apps/web/__tests__/__mocks__/style-mock.js +4 -0
- package/templates/apps/web/__tests__/__mocks__/vercel-analytics-server.ts +9 -0
- package/templates/apps/web/__tests__/jest-support/import-meta-transformer.cjs +90 -0
- package/templates/apps/web/__tests__/setup.ts +22 -32
- package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +6 -3
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +8 -2
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +260 -0
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +263 -0
- package/templates/apps/web/app/[locale]/(authed)/account/sign-out-button.tsx +39 -0
- package/templates/apps/web/app/[locale]/(authed)/layout.tsx +54 -0
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +96 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +309 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +149 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +273 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/gate.test.tsx +172 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +171 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +179 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +116 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ForbiddenState.tsx +24 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +66 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +61 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +114 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +139 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +85 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +67 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/format.ts +111 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +179 -0
- package/templates/apps/web/app/[locale]/about/page.tsx +10 -1
- package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +6 -1
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/careers/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/case-studies/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/clients/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +21 -1
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +188 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +242 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +29 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/intake-analytics.test.ts +51 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +39 -15
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +21 -3
- package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +49 -0
- package/templates/apps/web/app/[locale]/contact/intake-script.ts +66 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +14 -4
- package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/courses/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +1 -0
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/downloads/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +12 -2
- package/templates/apps/web/app/[locale]/events/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/faq/page.tsx +10 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +265 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +445 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +341 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +287 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +302 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +128 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +254 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +144 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +108 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +532 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +121 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +457 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +396 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +114 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +52 -0
- package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/integrations/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/launch-service/page.tsx +14 -1
- package/templates/apps/web/app/[locale]/layout.tsx +115 -16
- package/templates/apps/web/app/[locale]/page.tsx +10 -1
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/partners/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/products/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +10 -0
- package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +110 -0
- package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +96 -0
- package/templates/apps/web/app/[locale]/projects/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +12 -2
- package/templates/apps/web/app/[locale]/resources/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +96 -0
- package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +92 -0
- package/templates/apps/web/app/[locale]/schedule/page.tsx +82 -0
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/services/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/sign-in/__tests__/next-path.test.ts +31 -0
- package/templates/apps/web/app/[locale]/sign-in/__tests__/page.test.tsx +152 -0
- package/templates/apps/web/app/[locale]/sign-in/next-path.ts +0 -0
- package/templates/apps/web/app/[locale]/sign-in/page.tsx +83 -0
- package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +123 -0
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/testimonials/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +93 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +48 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/globals.css +35 -0
- package/templates/apps/web/app/llms.txt/route.ts +2 -1
- package/templates/apps/web/app/og/route.tsx +10 -2
- package/templates/apps/web/auth.ts +8 -0
- package/templates/apps/web/components/sign-out-trigger.tsx +42 -0
- package/templates/apps/web/content/en/blog/README.txt +25 -0
- package/templates/apps/web/content/en/docs/index.mdx +28 -0
- package/templates/apps/web/jest.config.cjs +84 -27
- package/templates/apps/web/lib/__tests__/site-brand.test.ts +119 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +499 -0
- package/templates/apps/web/lib/account-config.ts +13 -0
- package/templates/apps/web/lib/server-api.ts +85 -0
- package/templates/apps/web/lib/site-brand.tsx +118 -0
- package/templates/apps/web/messages/en.json +275 -7
- package/templates/apps/web/middleware.ts +11 -3
- package/templates/apps/web/next.config.mjs +8 -2
- package/templates/apps/web/package.json +16 -7
- package/templates/apps/web/postcss.config.mjs +23 -0
- package/templates/apps/web/public/.well-known/security.txt +3 -3
- package/templates/apps/web/src/lib/routes.ts +15 -2
- package/templates/apps/web/tsconfig.json +1 -16
- package/templates/content/_site.mdx +24 -25
- package/templates/content/en/AboutPage/about.mdx +24 -14
- package/templates/content/en/ContactPage/contact.mdx +23 -14
- package/templates/content/en/FAQPage/faq.mdx +10 -392
- package/templates/content/en/HomePage/home.mdx +14 -285
- package/templates/database/CHANGELOG.md +382 -0
- package/templates/database/LICENSE +201 -0
- package/templates/database/README.md +3 -1
- package/templates/database/__tests__/flows-listing-diagnostic.test.ts +392 -0
- package/templates/database/__tests__/flows-presets.test.ts +173 -0
- package/templates/database/__tests__/prefixed-ids.db.test.ts +146 -0
- package/templates/database/__tests__/seed.test.ts +88 -0
- package/templates/database/__tests__/user-cascade.test.ts +19 -4
- package/templates/database/auth/schema.prisma +521 -0
- package/templates/database/config/schema.prisma +234 -0
- package/templates/database/content/schema.prisma +263 -0
- package/templates/database/flows/listing-diagnostic.ts +182 -0
- package/templates/database/flows/presets.ts +315 -0
- package/templates/database/inbox/__tests__/schema.test.ts +4 -0
- package/templates/database/inbox/schema.prisma +476 -3
- package/templates/database/jest.config.cjs +8 -0
- package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +201 -0
- package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +67 -0
- package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +46 -0
- package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +25 -0
- package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +49 -0
- package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +197 -0
- package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +32 -0
- package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +22 -0
- package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +151 -0
- package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +223 -0
- package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +22 -0
- package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +32 -0
- package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +40 -0
- package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +4 -0
- package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +2 -0
- package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +2 -0
- package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +29 -0
- package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +6 -0
- package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +39 -0
- package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +24 -0
- package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +3 -0
- package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +33 -0
- package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +30 -0
- package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +47 -0
- package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +16 -0
- package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +47 -0
- package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +10 -0
- package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +26 -0
- package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +90 -0
- package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +174 -0
- package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +14 -0
- package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +25 -0
- package/templates/database/ops/schema.prisma +27 -0
- package/templates/database/package.json +42 -4
- package/templates/database/prisma.config.ts +1 -1
- package/templates/database/schema.prisma +19 -435
- package/templates/database/scripts/db-generate-locked.sh +0 -0
- package/templates/database/seed-test.ts +14 -4
- package/templates/database/seed.ts +148 -0
- package/templates/database/tenancy.ts +45 -0
- package/templates/database/tsconfig.flows.json +15 -0
- package/templates/database/tsconfig.json +7 -1
- package/templates/database/tsconfig.tenancy.json +14 -0
- package/templates/package.json +30 -55
- package/templates/pnpm-workspace.yaml +0 -3
- package/templates/project.yaml +1 -1
- package/templates/tsconfig.json +1 -37
- package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +0 -94
- package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +0 -75
- package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +0 -82
- package/templates/apps/web/__tests__/auth/env-helpers.test.ts +0 -168
- package/templates/apps/web/__tests__/authority-list-routes.test.tsx +0 -208
- package/templates/apps/web/__tests__/better-stack.test.ts +0 -66
- package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +0 -87
- package/templates/apps/web/__tests__/blog-source-populated.test.ts +0 -130
- package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +0 -60
- package/templates/apps/web/__tests__/google-analytics.test.tsx +0 -104
- package/templates/apps/web/__tests__/i18n/middleware.test.ts +0 -119
- package/templates/apps/web/__tests__/i18n/routing.test.ts +0 -114
- package/templates/apps/web/__tests__/i18n/translations.test.ts +0 -191
- package/templates/apps/web/__tests__/json-ld.test.ts +0 -98
- package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +0 -580
- package/templates/apps/web/__tests__/layout-stealth.test.ts +0 -39
- package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +0 -103
- package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +0 -114
- package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +0 -94
- package/templates/apps/web/__tests__/page.test.tsx +0 -230
- package/templates/apps/web/__tests__/products-services-phase1.test.tsx +0 -321
- package/templates/apps/web/__tests__/projects-routes.test.tsx +0 -392
- package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +0 -475
- package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +0 -53
- package/templates/apps/web/__tests__/routes/blog-route.test.tsx +0 -191
- package/templates/apps/web/__tests__/routes/llms-txt.test.ts +0 -123
- package/templates/apps/web/__tests__/routes/robots-txt.test.ts +0 -52
- package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +0 -78
- package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +0 -203
- package/templates/apps/web/__tests__/section-routes.test.tsx +0 -693
- package/templates/apps/web/__tests__/security-headers.test.ts +0 -201
- package/templates/apps/web/__tests__/sentry-config.test.ts +0 -116
- package/templates/apps/web/__tests__/sitemap-locales.test.ts +0 -415
- package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +0 -844
- package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +0 -120
- package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +0 -202
- package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +0 -152
- package/templates/apps/web/content/en/blog/index.mdx +0 -15
- package/templates/apps/web/content/en/blog/launching-ailk.mdx +0 -20
- package/templates/apps/web/content/en/docs/getting-started.mdx +0 -30
- package/templates/content/.gitkeep +0 -0
- package/templates/content/CLAUDE.md +0 -85
- package/templates/content/ar/HomePage/home.mdx +0 -123
- package/templates/content/ar/_site.mdx +0 -35
- package/templates/content/de/_site.mdx +0 -29
- package/templates/content/en/.gitkeep +0 -0
- package/templates/content/en/AboutPage/about.schema.json +0 -82
- package/templates/content/en/BookCall/book-call.mdx +0 -19
- package/templates/content/en/BookCall/book-call.schema.json +0 -121
- package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +0 -20
- package/templates/content/en/CareersList/careers.mdx +0 -24
- package/templates/content/en/CaseStudiesList/case-studies.mdx +0 -22
- package/templates/content/en/CaseStudiesList/showcase.mdx +0 -8
- package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +0 -32
- package/templates/content/en/CaseStudy/schema-builder-migration.mdx +0 -41
- package/templates/content/en/ClientsList/clients.mdx +0 -38
- package/templates/content/en/ContactPage/contact.schema.json +0 -100
- package/templates/content/en/ContactPoint/primary.mdx +0 -14
- package/templates/content/en/Course/aeo-fundamentals.mdx +0 -37
- package/templates/content/en/Course/schema-builder-workshop.mdx +0 -62
- package/templates/content/en/CoursesList/courses.mdx +0 -22
- package/templates/content/en/DownloadsList/downloads.mdx +0 -22
- package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +0 -39
- package/templates/content/en/Event/ailk-launch-day-2026.mdx +0 -35
- package/templates/content/en/EventsList/events.mdx +0 -26
- package/templates/content/en/FAQPage/faq.schema.json +0 -231
- package/templates/content/en/GlossaryList/glossary.mdx +0 -19
- package/templates/content/en/GlossaryList/glossary.schema.json +0 -300
- package/templates/content/en/HomePage/home.schema.json +0 -88
- package/templates/content/en/HomePage/launch-service.mdx +0 -475
- package/templates/content/en/HomePage/launch-service.schema.json +0 -138
- package/templates/content/en/HowTo/add-mdx-content.mdx +0 -38
- package/templates/content/en/HowTo/configure-aeo-scoring.mdx +0 -35
- package/templates/content/en/HowTo/set-up-json-ld.mdx +0 -36
- package/templates/content/en/Integration/github-actions.mdx +0 -31
- package/templates/content/en/Integration/openai-api.mdx +0 -26
- package/templates/content/en/Integration/vercel.mdx +0 -32
- package/templates/content/en/IntegrationsList/integrations.mdx +0 -22
- package/templates/content/en/JobPosting/content-strategist.mdx +0 -46
- package/templates/content/en/JobPosting/developer-advocate.mdx +0 -47
- package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +0 -57
- package/templates/content/en/LandingPage/aeo-audit.mdx +0 -19
- package/templates/content/en/LandingPage/aeo-audit.schema.json +0 -92
- package/templates/content/en/LandingPage/agency-waitlist.mdx +0 -340
- package/templates/content/en/LandingPage/agency-waitlist.schema.json +0 -152
- package/templates/content/en/LandingPage/developers.mdx +0 -19
- package/templates/content/en/LandingPage/developers.schema.json +0 -109
- package/templates/content/en/LandingPage/for-agencies.mdx +0 -390
- package/templates/content/en/LandingPage/for-agencies.schema.json +0 -107
- package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +0 -417
- package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +0 -105
- package/templates/content/en/LandingPage/for-businesses.mdx +0 -19
- package/templates/content/en/LandingPage/for-businesses.schema.json +0 -96
- package/templates/content/en/LandingPage/platform.mdx +0 -369
- package/templates/content/en/LandingPage/platform.schema.json +0 -166
- package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +0 -19
- package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +0 -102
- package/templates/content/en/LandingPage/vs-wordpress.mdx +0 -19
- package/templates/content/en/LandingPage/vs-wordpress.schema.json +0 -53
- package/templates/content/en/NewsletterSignup/newsletter.mdx +0 -236
- package/templates/content/en/NewsletterSignup/newsletter.schema.json +0 -91
- package/templates/content/en/Organization/site-owner.mdx +0 -16
- package/templates/content/en/Partner/prisma.mdx +0 -31
- package/templates/content/en/Partner/supabase.mdx +0 -30
- package/templates/content/en/Partner/vercel.mdx +0 -28
- package/templates/content/en/PartnersList/partners.mdx +0 -22
- package/templates/content/en/Person/founder.mdx +0 -18
- package/templates/content/en/Pricing/pricing.mdx +0 -538
- package/templates/content/en/Pricing/pricing.schema.json +0 -209
- package/templates/content/en/PrivacyPage/privacy.mdx +0 -165
- package/templates/content/en/PrivacyPage/privacy.schema.json +0 -64
- package/templates/content/en/Product/ailk.mdx +0 -19
- package/templates/content/en/Product/ailk.schema.json +0 -94
- package/templates/content/en/Product/api-launch-kit.mdx +0 -26
- package/templates/content/en/Product/launch-kit.mdx +0 -28
- package/templates/content/en/ProductsList/products.mdx +0 -26
- package/templates/content/en/Project/ailk-phase-2.mdx +0 -54
- package/templates/content/en/ProjectsList/projects.mdx +0 -25
- package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +0 -27
- package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +0 -28
- package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +0 -39
- package/templates/content/en/ResourcesHub/resources.mdx +0 -22
- package/templates/content/en/Service/consulting.mdx +0 -22
- package/templates/content/en/Service/implementation.mdx +0 -30
- package/templates/content/en/Service/launch-service.mdx +0 -232
- package/templates/content/en/Service/launch.mdx +0 -228
- package/templates/content/en/ServicesList/services.mdx +0 -84
- package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +0 -44
- package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +0 -47
- package/templates/content/en/SoftwareProduct/ailk-schema.mdx +0 -49
- package/templates/content/en/TeamList/team.mdx +0 -63
- package/templates/content/en/TeamMember/founder.mdx +0 -72
- package/templates/content/en/TermsPage/terms.mdx +0 -19
- package/templates/content/en/TermsPage/terms.schema.json +0 -99
- package/templates/content/en/TestimonialsList/testimonials.mdx +0 -44
- package/templates/content/en/UseCasesList/use-cases.mdx +0 -30
- package/templates/content/en/Whitepaper/ax-first-product-development.mdx +0 -27
- package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +0 -27
- package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +0 -31
- package/templates/content/en-XA/AboutPage/about.mdx +0 -8
- package/templates/content/en-XA/FAQPage/faq.mdx +0 -8
- package/templates/content/en-XA/HomePage/home.mdx +0 -8
- package/templates/content/es/_site.mdx +0 -30
- package/templates/content/fr/_site.mdx +0 -30
- package/templates/content/ja/_site.mdx +0 -30
- package/templates/content/pt-BR/AboutPage/about.mdx +0 -8
- package/templates/content/pt-BR/FAQPage/faq.mdx +0 -8
- package/templates/content/pt-BR/HomePage/home.mdx +0 -23
package/dist/surfaces.js
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route-surface registry — which public routes a scaffolded site carries.
|
|
3
|
+
*
|
|
4
|
+
* A SURFACE is one public route surface of the presentation tier (see
|
|
5
|
+
* architecture.yaml `composition_model`): a hub route plus the detail route and
|
|
6
|
+
* content directories that feed it. The registry is the single source of the
|
|
7
|
+
* surface vocabulary, in the same spirit as `module-architecture.ts` is the
|
|
8
|
+
* single source of the module→architecture-slice mapping — a code registry, not
|
|
9
|
+
* N hand-maintained template trees.
|
|
10
|
+
*
|
|
11
|
+
* Two tiers:
|
|
12
|
+
*
|
|
13
|
+
* - CORE_SURFACE_PATHS — the routes every AILK site has regardless of what
|
|
14
|
+
* the business is (`/`, `/about`, `/contact`, `/faq`, `/thanks/{slug}`).
|
|
15
|
+
* Always scaffolded, never gateable.
|
|
16
|
+
* - GATEABLE_SURFACES — everything else. A surface is scaffolded ONLY when
|
|
17
|
+
* the declared architecture carries it; otherwise its route directories are
|
|
18
|
+
* skipped by `copyTemplate` and the routes are ABSENT from the scaffold,
|
|
19
|
+
* not present-and-placeholdering (spec #4154 D1).
|
|
20
|
+
*
|
|
21
|
+
* The default (`--modules marketing`) enables NO gateable surface: every one of
|
|
22
|
+
* them is a claim about the business that the scaffolder cannot make. The path
|
|
23
|
+
* from there is the `suggest-site-pages` → `scaffold-page` skill pair that
|
|
24
|
+
* already ships in `templates/.claude/skills/`.
|
|
25
|
+
*
|
|
26
|
+
* Zero runtime dependencies — create-ailk is a published, standalone CLI.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately imports nothing from `parse-args.ts`: that module imports THIS
|
|
29
|
+
* one (for the `--surfaces` vocabulary in its help text), so a back-import
|
|
30
|
+
* would close a cycle. The module vocabulary is re-stated here as the keys of
|
|
31
|
+
* `MODULE_SURFACES`, and `__tests__/surface-gating.test.ts` asserts those keys
|
|
32
|
+
* equal `RECOGNIZED_MODULES` so the two cannot drift.
|
|
33
|
+
*/
|
|
34
|
+
/** Template-relative prefix every `apps/web` route directory sits under. */
|
|
35
|
+
const ROUTE_ROOT = "apps/web/app/[locale]";
|
|
36
|
+
/**
|
|
37
|
+
* Route paths (site-relative, for the record written into `architecture.yaml`)
|
|
38
|
+
* that every scaffold carries.
|
|
39
|
+
*
|
|
40
|
+
* `/thanks/{slug}` is a DETAIL route only — `app/[locale]/thanks/` holds just
|
|
41
|
+
* `[slug]/page.tsx`, there is no `/thanks` hub — and it is the completion target
|
|
42
|
+
* `/contact`'s forms hand off to, so it travels with core rather than standing
|
|
43
|
+
* alone as a gateable surface. It ships no starter content: a confirmation page
|
|
44
|
+
* is authored per form, when the form exists.
|
|
45
|
+
*/
|
|
46
|
+
export const CORE_SURFACE_PATHS = [
|
|
47
|
+
"/",
|
|
48
|
+
"/about",
|
|
49
|
+
"/contact",
|
|
50
|
+
"/faq",
|
|
51
|
+
"/thanks/{slug}",
|
|
52
|
+
];
|
|
53
|
+
/** Template-relative route directories that are always copied. */
|
|
54
|
+
export const CORE_ROUTE_DIRS = [
|
|
55
|
+
`${ROUTE_ROOT}/about`,
|
|
56
|
+
`${ROUTE_ROOT}/contact`,
|
|
57
|
+
`${ROUTE_ROOT}/faq`,
|
|
58
|
+
`${ROUTE_ROOT}/thanks`,
|
|
59
|
+
// #5014 — ships unconditionally in every scaffold today (SNAPSHOT_DIRS
|
|
60
|
+
// copies all of apps/web verbatim, no `--surfaces` gating on this route),
|
|
61
|
+
// so joining CORE_ROUTE_DIRS only makes the REGISTRY match what already
|
|
62
|
+
// ships — it does not change what a fresh scaffold carries.
|
|
63
|
+
`${ROUTE_ROOT}/sign-in`,
|
|
64
|
+
];
|
|
65
|
+
/**
|
|
66
|
+
* Directory names skipped by `listTemplateRouteDirs`'s walker even though they
|
|
67
|
+
* hold direct files — co-located helper trees, never routes of their own.
|
|
68
|
+
* `__tests__` is the original member; `components` is `#5014`'s addition
|
|
69
|
+
* (`(authed)/waitlist/components/`) — a route dir's own subtree copy already
|
|
70
|
+
* brings either kind along, so registering them as independent syncable units
|
|
71
|
+
* would be both redundant and, for `components`, unresolvable (no page/route
|
|
72
|
+
* file, so no `ROUTE_SINCE` entry would ever be correct for it).
|
|
73
|
+
*/
|
|
74
|
+
export const NON_ROUTE_DIRS = new Set([
|
|
75
|
+
"__tests__",
|
|
76
|
+
"components",
|
|
77
|
+
]);
|
|
78
|
+
/**
|
|
79
|
+
* The gateable surface vocabulary, sorted by id (the sort IS the emitted
|
|
80
|
+
* `available:` order — keep it alphabetical so the derivation stays
|
|
81
|
+
* byte-deterministic).
|
|
82
|
+
*/
|
|
83
|
+
export const GATEABLE_SURFACES = [
|
|
84
|
+
{
|
|
85
|
+
id: "blog",
|
|
86
|
+
routes: [`${ROUTE_ROOT}/blog`],
|
|
87
|
+
content: ["apps/web/content/<locale>/blog"],
|
|
88
|
+
navLabelKey: "blog",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "careers",
|
|
92
|
+
routes: [`${ROUTE_ROOT}/careers`],
|
|
93
|
+
content: ["content/<locale>/CareersList", "content/<locale>/JobPosting"],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "case-studies",
|
|
97
|
+
routes: [`${ROUTE_ROOT}/case-studies`],
|
|
98
|
+
content: [
|
|
99
|
+
"content/<locale>/CaseStudiesList",
|
|
100
|
+
"content/<locale>/CaseStudy",
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: "clients",
|
|
105
|
+
routes: [`${ROUTE_ROOT}/clients`],
|
|
106
|
+
content: ["content/<locale>/ClientsList"],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: "courses",
|
|
110
|
+
routes: [`${ROUTE_ROOT}/courses`],
|
|
111
|
+
content: ["content/<locale>/CoursesList", "content/<locale>/Course"],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
// Dev-only Server-Action ↔ MCP parity harness (`/dev/purchase`). Explicitly
|
|
115
|
+
// not customer-visible navigation; it has no place in a scaffold by default.
|
|
116
|
+
id: "dev",
|
|
117
|
+
routes: [`${ROUTE_ROOT}/dev`],
|
|
118
|
+
content: [],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "docs",
|
|
122
|
+
routes: [`${ROUTE_ROOT}/docs`],
|
|
123
|
+
content: ["apps/web/content/<locale>/docs"],
|
|
124
|
+
navLabelKey: "docs",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "downloads",
|
|
128
|
+
routes: [`${ROUTE_ROOT}/downloads`],
|
|
129
|
+
content: ["content/<locale>/DownloadsList"],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: "events",
|
|
133
|
+
routes: [`${ROUTE_ROOT}/events`],
|
|
134
|
+
content: ["content/<locale>/EventsList", "content/<locale>/Event"],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
// API-backed (the flow engine); no MDX of its own.
|
|
138
|
+
id: "flows",
|
|
139
|
+
routes: [`${ROUTE_ROOT}/flows`],
|
|
140
|
+
content: [],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "how-to",
|
|
144
|
+
routes: [`${ROUTE_ROOT}/how-to`],
|
|
145
|
+
content: ["content/<locale>/HowTo"],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: "integrations",
|
|
149
|
+
routes: [`${ROUTE_ROOT}/integrations`],
|
|
150
|
+
content: [
|
|
151
|
+
"content/<locale>/IntegrationsList",
|
|
152
|
+
"content/<locale>/Integration",
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
// A single HomePage-typed landing (`HomePage/launch-service.mdx` upstream);
|
|
157
|
+
// no content directory of its own.
|
|
158
|
+
id: "launch-service",
|
|
159
|
+
routes: [`${ROUTE_ROOT}/launch-service`],
|
|
160
|
+
content: [],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "partners",
|
|
164
|
+
routes: [`${ROUTE_ROOT}/partners`],
|
|
165
|
+
content: ["content/<locale>/PartnersList", "content/<locale>/Partner"],
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "products",
|
|
169
|
+
routes: [`${ROUTE_ROOT}/products`],
|
|
170
|
+
content: ["content/<locale>/ProductsList", "content/<locale>/Product"],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "projects",
|
|
174
|
+
routes: [`${ROUTE_ROOT}/projects`],
|
|
175
|
+
content: ["content/<locale>/ProjectsList", "content/<locale>/Project"],
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "resources",
|
|
179
|
+
routes: [`${ROUTE_ROOT}/resources`],
|
|
180
|
+
content: [
|
|
181
|
+
"content/<locale>/ResourcesHub",
|
|
182
|
+
"content/<locale>/ResourceDetail",
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
// The `scheduling` MODULE's presentation tier — the booking page and the
|
|
187
|
+
// confirmation page the module OWNS (`/schedule` + `/schedule/confirmed`,
|
|
188
|
+
// one directory, so one entry gates both). API-backed like `flows`: the
|
|
189
|
+
// booker reads its slots from apps/api's `/v1/schedule/*` routes and the
|
|
190
|
+
// event name from `SCHEDULING_CAL_LINK`, so there is no MDX of its own.
|
|
191
|
+
id: "schedule",
|
|
192
|
+
routes: [`${ROUTE_ROOT}/schedule`],
|
|
193
|
+
content: [],
|
|
194
|
+
navLabelKey: "schedule",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: "services",
|
|
198
|
+
routes: [`${ROUTE_ROOT}/services`],
|
|
199
|
+
content: ["content/<locale>/ServicesList", "content/<locale>/Service"],
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "software",
|
|
203
|
+
routes: [`${ROUTE_ROOT}/software`],
|
|
204
|
+
content: ["content/<locale>/SoftwareProduct"],
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: "tech-articles",
|
|
208
|
+
routes: [`${ROUTE_ROOT}/tech-articles`],
|
|
209
|
+
content: ["content/<locale>/TechArticle"],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: "testimonials",
|
|
213
|
+
routes: [`${ROUTE_ROOT}/testimonials`],
|
|
214
|
+
content: ["content/<locale>/TestimonialsList"],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: "use-cases",
|
|
218
|
+
routes: [`${ROUTE_ROOT}/use-cases`],
|
|
219
|
+
content: ["content/<locale>/UseCasesList"],
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: "whitepapers",
|
|
223
|
+
routes: [`${ROUTE_ROOT}/whitepapers`],
|
|
224
|
+
content: ["content/<locale>/Whitepaper"],
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
/** The recognized `--surfaces` vocabulary, sorted. */
|
|
228
|
+
export const RECOGNIZED_SURFACES = GATEABLE_SURFACES.map((s) => s.id);
|
|
229
|
+
/**
|
|
230
|
+
* Surfaces each recognized module contributes.
|
|
231
|
+
*
|
|
232
|
+
* `marketing` (the default) contributes NONE — a default scaffold is core-only.
|
|
233
|
+
* `docs` mounts the Fumadocs presentation surface; `multi-tenant` brings the
|
|
234
|
+
* flow-stepper surface with its API-backed engine; `scheduling` brings the
|
|
235
|
+
* booking page and the confirmation page the module owns.
|
|
236
|
+
*/
|
|
237
|
+
export const MODULE_SURFACES = {
|
|
238
|
+
marketing: [],
|
|
239
|
+
docs: ["docs"],
|
|
240
|
+
"multi-tenant": ["flows"],
|
|
241
|
+
scheduling: ["schedule"],
|
|
242
|
+
};
|
|
243
|
+
/** Thrown on an unrecognized surface id. Mirrors parse-args' ParseError shape. */
|
|
244
|
+
export class SurfaceError extends Error {
|
|
245
|
+
constructor(message) {
|
|
246
|
+
super(message);
|
|
247
|
+
this.name = "SurfaceError";
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Parse a surface CSV (the `--surfaces` value) into a validated, normalized,
|
|
252
|
+
* sorted, deduped list.
|
|
253
|
+
*
|
|
254
|
+
* Splits on `,`, trims + lowercases each entry, drops empties, and validates
|
|
255
|
+
* each against RECOGNIZED_SURFACES. An absent flag (or an all-empty value)
|
|
256
|
+
* yields the empty list — the caller composes it with the module-derived set.
|
|
257
|
+
*
|
|
258
|
+
* @throws SurfaceError on an unrecognized surface id, naming the vocabulary.
|
|
259
|
+
*/
|
|
260
|
+
export function parseSurfaces(raw) {
|
|
261
|
+
if (raw === undefined)
|
|
262
|
+
return [];
|
|
263
|
+
const requested = raw
|
|
264
|
+
.split(",")
|
|
265
|
+
.map((s) => s.trim().toLowerCase())
|
|
266
|
+
.filter(Boolean);
|
|
267
|
+
for (const s of requested) {
|
|
268
|
+
if (!RECOGNIZED_SURFACES.includes(s)) {
|
|
269
|
+
throw new SurfaceError(`unknown surface "${s}". Recognized: ${RECOGNIZED_SURFACES.join(", ")}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return [...new Set(requested)].sort();
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Resolve the enabled gateable-surface set from the selected modules plus any
|
|
276
|
+
* explicitly requested surfaces.
|
|
277
|
+
*
|
|
278
|
+
* The result is a sorted, deduped set — the same (modules, explicit) input
|
|
279
|
+
* always yields the same output, so both the copied tree and the derived
|
|
280
|
+
* `architecture.yaml` stay byte-deterministic.
|
|
281
|
+
*/
|
|
282
|
+
export function resolveSurfaces(modules = ["marketing"], explicit = []) {
|
|
283
|
+
const set = new Set();
|
|
284
|
+
for (const m of modules) {
|
|
285
|
+
const contributed = MODULE_SURFACES[m.trim().toLowerCase()];
|
|
286
|
+
// Defensive: parse-args rejects an unknown module first. Skip rather than
|
|
287
|
+
// throw a second, differently-worded error for the same bad input.
|
|
288
|
+
if (contributed === undefined)
|
|
289
|
+
continue;
|
|
290
|
+
for (const s of contributed)
|
|
291
|
+
set.add(s);
|
|
292
|
+
}
|
|
293
|
+
for (const s of explicit) {
|
|
294
|
+
if (!RECOGNIZED_SURFACES.includes(s)) {
|
|
295
|
+
throw new SurfaceError(`unknown surface "${s}". Recognized: ${RECOGNIZED_SURFACES.join(", ")}`);
|
|
296
|
+
}
|
|
297
|
+
set.add(s);
|
|
298
|
+
}
|
|
299
|
+
return [...set].sort();
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The template-relative route directories to SKIP when copying the template —
|
|
303
|
+
* every gateable surface not in `enabled`.
|
|
304
|
+
*
|
|
305
|
+
* Paths are emitted with forward slashes (the template tree's own separator);
|
|
306
|
+
* `copy.ts` normalizes the walked path before matching so the comparison holds
|
|
307
|
+
* on Windows too.
|
|
308
|
+
*/
|
|
309
|
+
export function excludedRoutePaths(enabled) {
|
|
310
|
+
const on = new Set(enabled);
|
|
311
|
+
const out = [];
|
|
312
|
+
for (const surface of GATEABLE_SURFACES) {
|
|
313
|
+
if (on.has(surface.id))
|
|
314
|
+
continue;
|
|
315
|
+
out.push(...surface.routes);
|
|
316
|
+
}
|
|
317
|
+
return out.sort();
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* The content directories belonging to gateable surfaces that are NOT enabled,
|
|
321
|
+
* with `<locale>` left in place for the caller to expand.
|
|
322
|
+
*
|
|
323
|
+
* Consumed by the sync-mode drift report so an already-scaffolded site is told
|
|
324
|
+
* about orphan content as well as orphan routes — orphan content is not inert:
|
|
325
|
+
* `/sitemap.xml` and `/llms.txt` enumerate the content adapter, so content whose
|
|
326
|
+
* route has been removed would advertise URLs that 404.
|
|
327
|
+
*/
|
|
328
|
+
export function excludedContentPaths(enabled) {
|
|
329
|
+
const on = new Set(enabled);
|
|
330
|
+
const out = [];
|
|
331
|
+
for (const surface of GATEABLE_SURFACES) {
|
|
332
|
+
if (on.has(surface.id))
|
|
333
|
+
continue;
|
|
334
|
+
out.push(...surface.content);
|
|
335
|
+
}
|
|
336
|
+
return out.sort();
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Route manifest (#4986): every template route directory, keyed relative to
|
|
340
|
+
* ROUTE_ROOT (`apps/web/app/[locale]`), → the `@working-theory/*` fixed-group
|
|
341
|
+
* release line (`.changeset/config.json` `fixed`) that first carried it — the
|
|
342
|
+
* version a consumer pins, so `sync-routes` can say "added in 0.14.0".
|
|
343
|
+
* create-ailk's own version is changesets-ignored and is NOT the axis.
|
|
344
|
+
*
|
|
345
|
+
* A route directory is a directory under ROUTE_ROOT that directly holds at
|
|
346
|
+
* least one file, excluding `__tests__` trees, whose top segment the registry
|
|
347
|
+
* recognizes (CORE_ROUTE_DIRS or a gateable surface's `routes`). Adding a
|
|
348
|
+
* route directory to the template REQUIRES an entry here —
|
|
349
|
+
* `__tests__/sync-routes.test.ts` fails otherwise.
|
|
350
|
+
*
|
|
351
|
+
* `0.0.0` = predates the manifest; the first release that carried it is not
|
|
352
|
+
* recoverable (history was squashed, no tags). Only the recommender routes
|
|
353
|
+
* (#4891, 0.14.0) are attributable.
|
|
354
|
+
*/
|
|
355
|
+
export const ROUTE_SINCE = {
|
|
356
|
+
about: "0.0.0",
|
|
357
|
+
"blog/[[...slug]]": "0.0.0",
|
|
358
|
+
careers: "0.0.0",
|
|
359
|
+
"careers/[slug]": "0.0.0",
|
|
360
|
+
"case-studies": "0.0.0",
|
|
361
|
+
"case-studies/[slug]": "0.0.0",
|
|
362
|
+
clients: "0.0.0",
|
|
363
|
+
contact: "0.0.0",
|
|
364
|
+
courses: "0.0.0",
|
|
365
|
+
"courses/[slug]": "0.0.0",
|
|
366
|
+
"dev/purchase": "0.0.0",
|
|
367
|
+
"docs/[[...slug]]": "0.0.0",
|
|
368
|
+
downloads: "0.0.0",
|
|
369
|
+
events: "0.0.0",
|
|
370
|
+
"events/[slug]": "0.0.0",
|
|
371
|
+
faq: "0.0.0",
|
|
372
|
+
"flows/[slug]": "0.0.0",
|
|
373
|
+
"flows/[slug]/results/[payload]": "0.14.0",
|
|
374
|
+
"flows/[slug]/start": "0.18.0",
|
|
375
|
+
"how-to": "0.0.0",
|
|
376
|
+
"how-to/[slug]": "0.0.0",
|
|
377
|
+
integrations: "0.0.0",
|
|
378
|
+
"integrations/[slug]": "0.0.0",
|
|
379
|
+
"launch-service": "0.0.0",
|
|
380
|
+
partners: "0.0.0",
|
|
381
|
+
"partners/[slug]": "0.0.0",
|
|
382
|
+
products: "0.0.0",
|
|
383
|
+
"products/[slug]": "0.0.0",
|
|
384
|
+
projects: "0.0.0",
|
|
385
|
+
"projects/[slug]": "0.0.0",
|
|
386
|
+
// #5048 — the founder-application reference mount. It carries the client
|
|
387
|
+
// wrapper only and no `page.tsx`: a route needs a question set, and a
|
|
388
|
+
// question set is the SITE's content. A scaffolded site adds its own route
|
|
389
|
+
// beside this file and passes its own config.
|
|
390
|
+
"projects/apply": "0.18.0",
|
|
391
|
+
resources: "0.0.0",
|
|
392
|
+
"resources/[slug]": "0.0.0",
|
|
393
|
+
schedule: "0.0.0",
|
|
394
|
+
"schedule/confirmed": "0.0.0",
|
|
395
|
+
services: "0.0.0",
|
|
396
|
+
"services/[slug]": "0.0.0",
|
|
397
|
+
software: "0.0.0",
|
|
398
|
+
"software/[slug]": "0.0.0",
|
|
399
|
+
"tech-articles": "0.0.0",
|
|
400
|
+
"tech-articles/[slug]": "0.0.0",
|
|
401
|
+
testimonials: "0.0.0",
|
|
402
|
+
"thanks/[slug]": "0.14.0",
|
|
403
|
+
"use-cases": "0.0.0",
|
|
404
|
+
whitepapers: "0.0.0",
|
|
405
|
+
"whitepapers/[slug]": "0.0.0",
|
|
406
|
+
// #5014 — the (authed) route GROUP: layout.tsx + sign-in-gate.tsx sit
|
|
407
|
+
// directly under "(authed)" (a Next.js route group — its parens are not a
|
|
408
|
+
// URL segment); account/ and waitlist/ are its two syncable sub-trees.
|
|
409
|
+
// None of these are attributable to a historical release the way the
|
|
410
|
+
// "0.0.0 = predates the manifest" entries above are, but they are also not
|
|
411
|
+
// genuinely new at HEAD — this run resolves them to the CURRENT fixed-group
|
|
412
|
+
// version (0.18.0) per the correction recorded on Epic #5076 (the issue's
|
|
413
|
+
// own text cites a stale 0.15.0), the same "attach at today's version"
|
|
414
|
+
// choice #5048's "projects/apply" entry already made for the same reason.
|
|
415
|
+
"(authed)": "0.18.0",
|
|
416
|
+
"(authed)/account": "0.18.0",
|
|
417
|
+
"(authed)/waitlist": "0.18.0",
|
|
418
|
+
"(authed)/waitlist/[experimentId]": "0.18.0",
|
|
419
|
+
"(authed)/waitlist/[experimentId]/signups/[leadId]": "0.18.0",
|
|
420
|
+
"sign-in": "0.18.0",
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* Surface id of the registry that owns `routeDir` (ROUTE_ROOT-relative): the
|
|
424
|
+
* string `"core"` for CORE_ROUTE_DIRS, `"authed"` for the `(authed)` route
|
|
425
|
+
* GROUP (#5014 — syncable like core, but reported under its own identity
|
|
426
|
+
* rather than conflated with CORE_ROUTE_DIRS's always-copied set, since it is
|
|
427
|
+
* a route GROUP rather than a route directory of its own), a gateable
|
|
428
|
+
* surface's id, or undefined when the top segment is outside the registry
|
|
429
|
+
* entirely.
|
|
430
|
+
*/
|
|
431
|
+
export function surfaceForRouteDir(routeDir) {
|
|
432
|
+
const topSegment = routeDir.split("/")[0];
|
|
433
|
+
if (topSegment === "(authed)")
|
|
434
|
+
return "authed";
|
|
435
|
+
const top = `${ROUTE_ROOT}/${topSegment}`;
|
|
436
|
+
if (CORE_ROUTE_DIRS.includes(top))
|
|
437
|
+
return "core";
|
|
438
|
+
return GATEABLE_SURFACES.find((s) => s.routes.includes(top))?.id;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Non-route consumer-side files a route's own source imports, that a sync
|
|
442
|
+
* must ALSO bring along so `--apply` never leaves a route that cannot
|
|
443
|
+
* compile (#5014's third clause). Template-relative, `/`-separated, keyed by
|
|
444
|
+
* the same route string `ROUTE_SINCE` uses. `sync-routes` copies a listed
|
|
445
|
+
* file only when the target does not already have it — it never overwrites,
|
|
446
|
+
* the same rule routes themselves follow.
|
|
447
|
+
*
|
|
448
|
+
* `(authed)/account` depending on two files INSIDE `(authed)/waitlist`
|
|
449
|
+
* (`ForbiddenState.tsx`, `format.ts`) is real, found by reading the account
|
|
450
|
+
* page's own imports, not guessed from the issue text: the account page
|
|
451
|
+
* renders a shared "forbidden" empty state and shared count/date formatters
|
|
452
|
+
* that the waitlist dashboard also uses, rather than duplicating them.
|
|
453
|
+
*/
|
|
454
|
+
export const ROUTE_DEPENDENCIES = {
|
|
455
|
+
"sign-in": ["apps/web/lib/auth-env.ts", "apps/web/lib/site-brand.tsx"],
|
|
456
|
+
"(authed)": ["apps/web/auth.ts", "apps/web/lib/auth-env.ts"],
|
|
457
|
+
"(authed)/account": [
|
|
458
|
+
"apps/web/lib/account-config.ts",
|
|
459
|
+
"apps/web/lib/server-api.ts",
|
|
460
|
+
`${ROUTE_ROOT}/(authed)/waitlist/components/ForbiddenState.tsx`,
|
|
461
|
+
`${ROUTE_ROOT}/(authed)/waitlist/format.ts`,
|
|
462
|
+
],
|
|
463
|
+
"(authed)/waitlist": ["apps/web/lib/server-api.ts"],
|
|
464
|
+
};
|
|
465
|
+
/**
|
|
466
|
+
* i18n message namespaces (dot-path into `apps/web/messages/<locale>.json`) a
|
|
467
|
+
* route needs (#5014's third clause). CHECK-ONLY: a consumer's `messages/`
|
|
468
|
+
* file already exists in every scaffold (it is not itself route-gated) and
|
|
469
|
+
* may carry the site owner's own edits, so `sync-routes` reports a missing
|
|
470
|
+
* namespace rather than attempting to merge JSON keys into it — a blind merge
|
|
471
|
+
* risks corrupting hand-authored translations. Adding the namespace is left
|
|
472
|
+
* to the site owner, same as any other reported gap.
|
|
473
|
+
*/
|
|
474
|
+
export const ROUTE_MESSAGE_NAMESPACES = {
|
|
475
|
+
"sign-in": ["signIn"],
|
|
476
|
+
"(authed)/account": ["account"],
|
|
477
|
+
"(authed)/waitlist": ["waitlistDashboard.gate"],
|
|
478
|
+
};
|
|
479
|
+
/** Template-relative path of the generated site-nav registry. */
|
|
480
|
+
export const NAV_CONFIG_PATH = "apps/web/lib/nav-config.ts";
|
|
481
|
+
/**
|
|
482
|
+
* Render `apps/web/lib/nav-config.ts` for an enabled surface set.
|
|
483
|
+
*
|
|
484
|
+
* The site nav is NOT content-derived — it is a static list the layout renders
|
|
485
|
+
* into the header and the footer. Left as the template ships it, a gated
|
|
486
|
+
* scaffold would link `/docs` and `/blog` on every page while neither route
|
|
487
|
+
* exists: two dead links, sitewide, by default. So the nav follows the declared
|
|
488
|
+
* surface set for the same reason the route tree does.
|
|
489
|
+
*
|
|
490
|
+
* Only surfaces carrying a `navLabelKey` are linked, because a nav entry needs
|
|
491
|
+
* a translated label and the template's `nav` namespace ships keys for exactly
|
|
492
|
+
* `home`, `docs`, and `blog`. Emitting an entry whose `labelKey` has no
|
|
493
|
+
* translation would trade a dead link for a missing-message error.
|
|
494
|
+
*
|
|
495
|
+
* Deterministic: entries follow GATEABLE_SURFACES order (alphabetical by id),
|
|
496
|
+
* after the always-present home entry.
|
|
497
|
+
*/
|
|
498
|
+
export function renderNavConfig(enabled) {
|
|
499
|
+
const on = new Set(enabled);
|
|
500
|
+
const linked = GATEABLE_SURFACES.filter((s) => s.navLabelKey !== undefined && on.has(s.id));
|
|
501
|
+
const entries = [
|
|
502
|
+
' { labelKey: "home", path: "/" },',
|
|
503
|
+
...linked.map((s) => ` { labelKey: "${s.navLabelKey}", path: "/${s.id}" },`),
|
|
504
|
+
];
|
|
505
|
+
// The emitted file imports the consumer's `NavItem` type from the UI package.
|
|
506
|
+
// Assembled from fragments so THIS source file never contains the literal
|
|
507
|
+
// import string: `tools/lint-architecture.ts` matches on source text, so a
|
|
508
|
+
// literal would read as create-ailk importing @working-theory/ui and fail the
|
|
509
|
+
// boundary lint. Same technique module-architecture.ts uses for its own
|
|
510
|
+
// forbidden-pattern data (NO_UPSTREAM_IMPORT_PATTERN).
|
|
511
|
+
const navItemImport = [
|
|
512
|
+
"import type { NavItem } ",
|
|
513
|
+
"from ",
|
|
514
|
+
'"@working-theory/ui";',
|
|
515
|
+
].join("");
|
|
516
|
+
return `// nav-config.ts — site-nav registry.
|
|
517
|
+
//
|
|
518
|
+
// GENERATED by create-ailk from the declared route surfaces. Every entry here
|
|
519
|
+
// points at a route this site actually carries — the nav is regenerated with
|
|
520
|
+
// the surface set so it can never link a page that was not scaffolded.
|
|
521
|
+
//
|
|
522
|
+
// Adding a link: scaffold the page (the \`scaffold-page\` skill), then add an
|
|
523
|
+
// entry below with a \`labelKey\` that exists in the \`nav\` namespace of
|
|
524
|
+
// \`apps/web/messages/<locale>.json\`. Paths are locale-agnostic — Nav prefixes
|
|
525
|
+
// them with the active locale at render.
|
|
526
|
+
${navItemImport}
|
|
527
|
+
|
|
528
|
+
export const navItems: NavItem[] = [
|
|
529
|
+
${entries.join("\n")}
|
|
530
|
+
];
|
|
531
|
+
`;
|
|
532
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { WorkspaceVersionMap } from "./substitute.js";
|
|
2
|
+
export interface SyncRoutesOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The already-scaffolded repo (absolute or relative). Must exist, be a
|
|
5
|
+
* directory, and contain `architecture.yaml` — the same validation as
|
|
6
|
+
* `syncArchitectureSync`.
|
|
7
|
+
*/
|
|
8
|
+
targetDir: string;
|
|
9
|
+
/** The template tree to sync FROM (the package's `templates/` dir). */
|
|
10
|
+
templatesDir: string;
|
|
11
|
+
/**
|
|
12
|
+
* Workspace version map for `copyTemplate`. Route dirs carry no package.json,
|
|
13
|
+
* so it never applies; passed for fidelity with the scaffold path.
|
|
14
|
+
*/
|
|
15
|
+
versions: WorkspaceVersionMap;
|
|
16
|
+
/** Copy the missing routes into the target. Default false = check only. */
|
|
17
|
+
apply?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** One route directory the report names. */
|
|
20
|
+
export interface RouteReport {
|
|
21
|
+
/** ROUTE_ROOT-relative, `/`-separated. */
|
|
22
|
+
route: string;
|
|
23
|
+
/** `"core"`, `"authed"` (the `(authed)` route group, #5014), or a gateable surface's id. */
|
|
24
|
+
surface: string;
|
|
25
|
+
/** The `ROUTE_SINCE` release line that first carried the route. */
|
|
26
|
+
since: string;
|
|
27
|
+
/** `ROUTE_DEPENDENCIES[route]`, when declared — see that export for the contract. */
|
|
28
|
+
dependencies: readonly string[];
|
|
29
|
+
/** `ROUTE_MESSAGE_NAMESPACES[route]`, when declared. */
|
|
30
|
+
messageNamespaces: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
export interface SyncRoutesResult {
|
|
33
|
+
/** Resolved absolute path to the synced directory. */
|
|
34
|
+
targetDir: string;
|
|
35
|
+
/** In-scope template route dirs examined. */
|
|
36
|
+
checked: number;
|
|
37
|
+
/** Template route dirs absent from the target, sorted by route. */
|
|
38
|
+
missing: RouteReport[];
|
|
39
|
+
/** Route dirs present but with a direct file absent or changed, sorted. */
|
|
40
|
+
modified: RouteReport[];
|
|
41
|
+
/** Route dirs copied this run (the missing list when applying, else empty). */
|
|
42
|
+
applied: string[];
|
|
43
|
+
/**
|
|
44
|
+
* `ROUTE_DEPENDENCIES` files, of any route in `missing`, absent from the
|
|
45
|
+
* target — copied when `apply` is set (never overwriting), else reported
|
|
46
|
+
* only. Sorted, deduplicated.
|
|
47
|
+
*/
|
|
48
|
+
missingDependencies: string[];
|
|
49
|
+
/** Dependency files copied this run. Sorted. */
|
|
50
|
+
appliedDependencies: string[];
|
|
51
|
+
/**
|
|
52
|
+
* `ROUTE_MESSAGE_NAMESPACES` dot-paths, of any route in `missing`, absent
|
|
53
|
+
* from the target's `messages/en.json`. CHECK-ONLY — never copied (see
|
|
54
|
+
* `ROUTE_MESSAGE_NAMESPACES`'s own doc for why). Sorted, deduplicated.
|
|
55
|
+
*/
|
|
56
|
+
missingMessageNamespaces: string[];
|
|
57
|
+
/** Gateable surface ids the target does not carry, sorted. */
|
|
58
|
+
skippedSurfaces: string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The template's route directories, ROUTE_ROOT-relative and sorted.
|
|
62
|
+
*
|
|
63
|
+
* A route directory is a directory under ROUTE_ROOT (not the root itself)
|
|
64
|
+
* that directly holds at least one regular file, is not inside a
|
|
65
|
+
* `NON_ROUTE_DIRS` tree (`__tests__`, `components`), and whose top segment
|
|
66
|
+
* the registry recognizes (`surfaceForRouteDir`).
|
|
67
|
+
*/
|
|
68
|
+
export declare function listTemplateRouteDirs(templatesDir: string): string[];
|
|
69
|
+
/**
|
|
70
|
+
* Compare an already-scaffolded repo's route tree with the template's and,
|
|
71
|
+
* when `apply` is set, copy in the route dirs it is missing.
|
|
72
|
+
*
|
|
73
|
+
* Throws Error on a missing target, a non-directory target, a directory with
|
|
74
|
+
* no `architecture.yaml`, or a template route dir without a `ROUTE_SINCE`
|
|
75
|
+
* entry; the CLI's top-level catch turns that into a `[create-ailk] <message>`
|
|
76
|
+
* stderr write + exit 1.
|
|
77
|
+
*/
|
|
78
|
+
export declare function syncRoutes(opts: SyncRoutesOptions): SyncRoutesResult;
|
|
79
|
+
/** Render the report the CLI prints after a run. Ends with a newline. */
|
|
80
|
+
export declare function formatSyncRoutesReport(result: SyncRoutesResult, apply: boolean): string;
|
|
81
|
+
export interface SyncRoutesArgs {
|
|
82
|
+
/** Positional target directory; undefined = the caller's cwd. */
|
|
83
|
+
target: string | undefined;
|
|
84
|
+
apply: boolean;
|
|
85
|
+
help: boolean;
|
|
86
|
+
}
|
|
87
|
+
export declare const SYNC_ROUTES_HELP = "create-ailk sync-routes \u2014 copy template routes an existing site is missing.\n\nUsage:\n create-ailk sync-routes [<target-dir>] [--apply]\n\nArguments:\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --apply Copy the missing route directories into the target.\n Without it the command only reports: exit 1 when a\n route is missing, 0 when in sync.\n --help, -h Print this message.\n\nChecks every core route plus the routes of each surface the site carries; a\nsurface gated off at scaffold time is skipped, not drift. A route the site has\nchanged locally is reported and never overwritten. Nothing is ever deleted.\n";
|
|
88
|
+
/**
|
|
89
|
+
* Parse the argv AFTER the `sync-routes` word. Strict `node:util` parseArgs,
|
|
90
|
+
* like `parseCliArgs`; at most one positional.
|
|
91
|
+
*/
|
|
92
|
+
export declare function parseSyncRoutesArgs(argv: string[]): SyncRoutesArgs;
|