create-ailk 0.1.0 → 0.2.0
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 +456 -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 +12 -5
- 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 +78 -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 +241 -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 +558 -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 +869 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +221 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +468 -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-answers.test.ts +707 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +375 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +467 -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 +120 -0
- package/templates/apps/api/src/routes/project-listings/list.ts +47 -0
- package/templates/apps/api/src/routes/project-listings/me.ts +76 -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 +106 -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 +307 -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__/consent-migration.test.ts +65 -0
- package/templates/apps/api/src/services/__tests__/consent.test.ts +282 -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__/listing-promotion.test.ts +684 -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/consent.ts +236 -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 +1296 -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/listing-promotion.ts +342 -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 +510 -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 +1472 -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 +127 -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 +90 -27
- package/templates/apps/web/lib/__tests__/site-brand.test.ts +119 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +112 -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 +121 -0
- package/templates/apps/web/lib/site-theme.ts +74 -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 +17 -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 +36 -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 +443 -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 +574 -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/migrations/20260911140000_listing_structured_address/migration.sql +32 -0
- package/templates/database/migrations/20260911180000_consent_grants/migration.sql +71 -0
- package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +30 -0
- package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +49 -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/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
|
@@ -12,30 +12,140 @@
|
|
|
12
12
|
import cors from '@fastify/cors';
|
|
13
13
|
import rateLimit from '@fastify/rate-limit';
|
|
14
14
|
import Fastify from 'fastify';
|
|
15
|
+
import type { FastifyPluginAsync, FastifyPluginCallback } from 'fastify';
|
|
15
16
|
|
|
16
17
|
import { config } from './config/index.js';
|
|
18
|
+
import { isModuleEnabled } from './config/modules.js';
|
|
17
19
|
import { registerErrorSerializer } from './lib/error-serializer.js';
|
|
18
20
|
import { validateLeadCaptureDir } from './lib/lead-capture-store.js';
|
|
19
21
|
import { assertSandboxKey } from './lib/stripe.js';
|
|
20
22
|
import { authPreHandlerPlugin } from './middleware/auth.js';
|
|
21
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
rateLimitMiddleware,
|
|
25
|
+
DEFAULT_PER_IP_PER_MINUTE_STRICT,
|
|
26
|
+
} from './middleware/rate-limit.js';
|
|
22
27
|
import { openapiRoutes } from './openapi/index.js';
|
|
28
|
+
import { exampleAeoRoute, scoreAeoRoute } from './routes/aeo/index.js';
|
|
23
29
|
import { tokenRoutes } from './routes/auth/tokens.js';
|
|
24
30
|
import { userRoutes } from './routes/auth/user.js';
|
|
25
31
|
import { checkoutRoutes } from './routes/checkout/index.js';
|
|
26
|
-
import {
|
|
32
|
+
import { getPageRoute } from './routes/content/get-page.js';
|
|
33
|
+
import { listPagesRoute } from './routes/content/list-pages.js';
|
|
34
|
+
import { listTypesRoute } from './routes/content/list-types.js';
|
|
27
35
|
import {
|
|
28
36
|
CONTENT_RATE_LIMIT_UNAUTH,
|
|
29
37
|
CONTENT_RATE_LIMIT_WINDOW,
|
|
30
38
|
} from './routes/content/rate-limit.js';
|
|
39
|
+
import { deliverableDownloadRoute } from './routes/deliverables/index.js';
|
|
40
|
+
import { flowCheckoutRoutes } from './routes/flow-checkouts/index.js';
|
|
41
|
+
import { getFlowAggregateRoute, getFlowRoute, submitFlowStepRoute } from './routes/flows/index.js';
|
|
42
|
+
import { checkoutRecommendationRoute, saveRecommendationRoute } from './routes/flows/recommender.js';
|
|
31
43
|
import {
|
|
32
44
|
leadCallbackRoute,
|
|
33
45
|
leadSubmitRoute,
|
|
34
46
|
leadSubscribeRoute,
|
|
35
47
|
} from './routes/leads/index.js';
|
|
48
|
+
import {
|
|
49
|
+
projectListingDraftPatchRoute,
|
|
50
|
+
projectListingMeRoute,
|
|
51
|
+
projectListingPublicRoute,
|
|
52
|
+
projectListingStartRoute,
|
|
53
|
+
projectListingSubmitRoute,
|
|
54
|
+
} from './routes/project-listings/index.js';
|
|
55
|
+
import { slackActionsRoute } from './routes/slack/index.js';
|
|
36
56
|
import { registerTestAuthRoute, shouldMountTestAuth } from './routes/test/auth/session.js';
|
|
57
|
+
import { waitlistSignupRoutes } from './routes/waitlist-signups/index.js';
|
|
37
58
|
import { webhooksRoutes } from './routes/webhooks/index.js';
|
|
38
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Paid-module SLICE entry points, keyed by the export each branch needs
|
|
62
|
+
* (#5182).
|
|
63
|
+
*
|
|
64
|
+
* Every value here names a file the OSS strip removes. A shipping file may not
|
|
65
|
+
* name a stripped file in ANY import form (spec D1): `import()` defers
|
|
66
|
+
* EVALUATION, not RESOLUTION, so `tsc` resolves a string-literal specifier
|
|
67
|
+
* whether or not the `isModuleEnabled()` branch containing it can ever run. The
|
|
68
|
+
* ten literal `await import()` calls that used to sit at these call sites were
|
|
69
|
+
* therefore ten TS2307 errors on the public tree, and the static
|
|
70
|
+
* `./middleware/tenant.js` import was an eleventh — measured on a stripped
|
|
71
|
+
* tree, not argued.
|
|
72
|
+
*
|
|
73
|
+
* Reading the specifier from this table is what makes it non-literal at the
|
|
74
|
+
* call site, and that INDIRECTION — not the type of the value — is what defeats
|
|
75
|
+
* resolution. S1's `isModuleEnabled()` gate is unchanged and still decides
|
|
76
|
+
* whether the branch runs; `AILK_ENABLED_MODULES` unset still means every
|
|
77
|
+
* module on, so a default build registers exactly what it registered before.
|
|
78
|
+
*
|
|
79
|
+
* This mechanism is sound here because `apps/api` is a `tsc`-only surface with
|
|
80
|
+
* no bundler. It is NOT sound in `packages/ui`: webpack cannot statically
|
|
81
|
+
* analyse a non-literal `import()` either, and compiles it to an async context
|
|
82
|
+
* with no members, so the module silently fails to load on the tree that HAS
|
|
83
|
+
* it. See the note above the imports in `packages/ui/src/sections/SectionRenderer.tsx`.
|
|
84
|
+
*
|
|
85
|
+
* `./routes/project-listings/index.js` is deliberately absent: that barrel is a
|
|
86
|
+
* MIXED directory that ships (the free anonymous listing routes are registered
|
|
87
|
+
* from it statically at the top of this file), so its dynamic import at the
|
|
88
|
+
* tenant scope is a literal on purpose and resolves fine on both trees.
|
|
89
|
+
*/
|
|
90
|
+
const SLICE_PLUGIN_SPECIFIERS = {
|
|
91
|
+
workspaceContextRoutes: './routes/workspaces/index.js',
|
|
92
|
+
workspaceSessionRoutes: './routes/workspaces/index.js',
|
|
93
|
+
sessionRoutes: './routes/workspaces/sessions.js',
|
|
94
|
+
workspaceConfigRoutes: './routes/workspaces/config.js',
|
|
95
|
+
billingRoutes: './routes/billing/index.js',
|
|
96
|
+
waitlistExperimentRoutes: './routes/waitlist-experiments/index.js',
|
|
97
|
+
createPageRoute: './routes/content/create.js',
|
|
98
|
+
updatePageRoute: './routes/content/update.js',
|
|
99
|
+
deletePageRoute: './routes/content/delete.js',
|
|
100
|
+
listAvailabilityRoute: './routes/schedule/index.js',
|
|
101
|
+
getEventMetaRoute: './routes/schedule/index.js',
|
|
102
|
+
createBookingRoute: './routes/schedule/index.js',
|
|
103
|
+
} satisfies Record<string, string>;
|
|
104
|
+
|
|
105
|
+
type SlicePluginName = keyof typeof SLICE_PLUGIN_SPECIFIERS;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Load one slice route plugin. Every entry above is a `FastifyPluginAsync`
|
|
109
|
+
* export, which is the cast's whole content — `import(nonLiteral)` yields
|
|
110
|
+
* `any`, so this boundary is the load-bearing line and names the exact shape
|
|
111
|
+
* rather than spreading `any` into `register()`.
|
|
112
|
+
*
|
|
113
|
+
* Throws rather than skipping if the export is missing: the branch only runs
|
|
114
|
+
* when the module is declared enabled, so an absent export is a build/packaging
|
|
115
|
+
* fault to surface at boot, not a condition to degrade through.
|
|
116
|
+
*/
|
|
117
|
+
async function sliceRoutePlugin(
|
|
118
|
+
name: SlicePluginName,
|
|
119
|
+
): Promise<FastifyPluginAsync> {
|
|
120
|
+
const specifier: string = SLICE_PLUGIN_SPECIFIERS[name];
|
|
121
|
+
const mod = (await import(specifier)) as Record<
|
|
122
|
+
string,
|
|
123
|
+
FastifyPluginAsync | undefined
|
|
124
|
+
>;
|
|
125
|
+
const plugin = mod[name];
|
|
126
|
+
if (!plugin) {
|
|
127
|
+
throw new Error(`slice export ${name} missing from ${specifier}`);
|
|
128
|
+
}
|
|
129
|
+
return plugin;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The multi-tenant preHandler plugin — the one slice entry that is not a
|
|
134
|
+
* route plugin. `FastifyPluginCallback`, registered with no options
|
|
135
|
+
* (apps/api/src/middleware/tenant.ts:83).
|
|
136
|
+
*/
|
|
137
|
+
async function tenantPreHandlerSlicePlugin(): Promise<FastifyPluginCallback> {
|
|
138
|
+
const specifier: string = './middleware/tenant.js';
|
|
139
|
+
const mod = (await import(specifier)) as {
|
|
140
|
+
tenantPreHandlerPlugin?: FastifyPluginCallback;
|
|
141
|
+
};
|
|
142
|
+
const plugin = mod.tenantPreHandlerPlugin;
|
|
143
|
+
if (!plugin) {
|
|
144
|
+
throw new Error('slice export tenantPreHandlerPlugin missing from ' + specifier);
|
|
145
|
+
}
|
|
146
|
+
return plugin;
|
|
147
|
+
}
|
|
148
|
+
|
|
39
149
|
/**
|
|
40
150
|
* Build Fastify server instance (for serverless or standalone)
|
|
41
151
|
* @returns Configured Fastify instance ready for requests
|
|
@@ -51,8 +161,31 @@ export async function build() {
|
|
|
51
161
|
assertSandboxKey(config.STRIPE_SECRET_KEY);
|
|
52
162
|
}
|
|
53
163
|
|
|
164
|
+
// trustProxy: true (#4730) — the Vercel serverless handler
|
|
165
|
+
// (apps/api/api/index.ts) bridges every request through Fastify's
|
|
166
|
+
// `.inject()` rather than a real socket, so `req.socket.remoteAddress`
|
|
167
|
+
// (the trustProxy:false default) is a meaningless simulated value, not
|
|
168
|
+
// the caller's address. With trustProxy enabled, req.ip instead resolves
|
|
169
|
+
// from `X-Forwarded-For` (the header Vercel's own edge sets on every
|
|
170
|
+
// inbound request) via Fastify's built-in proxy-addr parsing — reading
|
|
171
|
+
// the LEFTMOST address in a multi-hop chain, i.e. the address farthest
|
|
172
|
+
// from this process. This is what lets the per-scope rate limiter
|
|
173
|
+
// (middleware/rate-limit.ts) key on a real visitor's IP instead of a
|
|
174
|
+
// constant fallback or a shared intermediary's egress IP (see the flows/
|
|
175
|
+
// leads/aeo/schedule scopes below).
|
|
176
|
+
//
|
|
177
|
+
// Trade-off: X-Forwarded-For is caller-suppliable to anyone hitting this
|
|
178
|
+
// API directly (there is no fixed, allowlistable upstream proxy — this
|
|
179
|
+
// API's actual "proxies" are arbitrary consumer web functions), so a
|
|
180
|
+
// direct caller can still spoof a fresh identity per request. Per-IP
|
|
181
|
+
// rate limiting on these anonymous surfaces is a best-effort abuse
|
|
182
|
+
// deterrent, not a hard security boundary; this trades a small amount of
|
|
183
|
+
// spoof-resistance for correctness on the overwhelmingly common path
|
|
184
|
+
// (server-action-forwarded traffic), which was previously broken for
|
|
185
|
+
// every caller.
|
|
54
186
|
const server = Fastify({
|
|
55
187
|
logger: true,
|
|
188
|
+
trustProxy: true,
|
|
56
189
|
});
|
|
57
190
|
|
|
58
191
|
// Register error serializer — maps internal exceptions to generic strings
|
|
@@ -60,9 +193,14 @@ export async function build() {
|
|
|
60
193
|
// never reach the client. Full detail still goes to pino at error level.
|
|
61
194
|
registerErrorSerializer(server);
|
|
62
195
|
|
|
63
|
-
// Register CORS — public read API + same-origin auth callers
|
|
196
|
+
// Register CORS — public read API + same-origin auth callers.
|
|
197
|
+
// With FRONTEND_URL unset: reflect any origin in dev/test (zero-config
|
|
198
|
+
// boot) but fail CLOSED in production — `origin: true` combined with
|
|
199
|
+
// `credentials: true` would let any website read credentialed responses
|
|
200
|
+
// (security review M1). `false` disables cross-origin access entirely;
|
|
201
|
+
// same-origin and non-browser callers are unaffected.
|
|
64
202
|
await server.register(cors, {
|
|
65
|
-
origin: config.FRONTEND_URL ||
|
|
203
|
+
origin: config.FRONTEND_URL || config.NODE_ENV !== 'production',
|
|
66
204
|
credentials: true,
|
|
67
205
|
});
|
|
68
206
|
|
|
@@ -99,6 +237,8 @@ export async function build() {
|
|
|
99
237
|
contentList: 'GET /v1/content/:type',
|
|
100
238
|
contentPage: 'GET /v1/content/:type/:slug',
|
|
101
239
|
checkoutSessions: 'POST /v1/checkout/sessions',
|
|
240
|
+
billing: 'GET /v1/billing',
|
|
241
|
+
billingPortalSession: 'POST /v1/billing/portal-session',
|
|
102
242
|
},
|
|
103
243
|
};
|
|
104
244
|
});
|
|
@@ -112,11 +252,88 @@ export async function build() {
|
|
|
112
252
|
});
|
|
113
253
|
await authScope.register(tokenRoutes);
|
|
114
254
|
await authScope.register(userRoutes);
|
|
255
|
+
|
|
256
|
+
// Tenant-context routes (multi-tenant module) — auth only. They
|
|
257
|
+
// establish/inspect the active workspace, so the tenant guard does not
|
|
258
|
+
// apply to them; each enforces membership in the service layer.
|
|
259
|
+
// Module-conditional (S1, #5088): without the multi-tenant module there
|
|
260
|
+
// is no workspace concept to switch or inspect.
|
|
261
|
+
if (isModuleEnabled('multi-tenant')) {
|
|
262
|
+
await authScope.register(await sliceRoutePlugin('workspaceContextRoutes'));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Respondent signup read (#4731) — auth only, NOT tenant-guarded: a
|
|
266
|
+
// respondent has no workspace membership and the tenant guard is
|
|
267
|
+
// default-deny. Identity is request.userId; the service re-checks
|
|
268
|
+
// User.emailVerified before any Lead read.
|
|
269
|
+
await authScope.register(waitlistSignupRoutes);
|
|
270
|
+
|
|
271
|
+
// Respondent checkouts read (#4984) — the same posture as the signup
|
|
272
|
+
// read above: auth only, NOT tenant-guarded. Identity is request.userId;
|
|
273
|
+
// the only join is the lead-promotion link (never an email match).
|
|
274
|
+
await authScope.register(flowCheckoutRoutes);
|
|
275
|
+
|
|
276
|
+
// The founder's OWN listings read (#5295) — the same posture again: auth
|
|
277
|
+
// only, NOT tenant-guarded, because a founder is not a workspace member
|
|
278
|
+
// and the tenant guard is default-deny. Identity is request.userId; the
|
|
279
|
+
// only join is the owner link (ProjectListing.ownerUserId, stamped by
|
|
280
|
+
// services/listing-promotion.ts), never an email match. The tenant-scoped
|
|
281
|
+
// listing routes below keep their owner|admin floor untouched — this route
|
|
282
|
+
// is additive, not a relaxation of that floor. Registered here rather than
|
|
283
|
+
// inside the multi-tenant scope so a founder can read their own rows on a
|
|
284
|
+
// build without the module; the static `/me` path takes router precedence
|
|
285
|
+
// over the tenant scope's parametric `/v1/project-listings/:id`, exactly as
|
|
286
|
+
// the already-shipped static `/v1/project-listings/public` does.
|
|
287
|
+
await authScope.register(projectListingMeRoute);
|
|
288
|
+
|
|
289
|
+
// Tenant-guarded domain routes (multi-tenant module) — the tenant
|
|
290
|
+
// preHandler (default-deny guard, see middleware/tenant.ts) runs after
|
|
291
|
+
// auth for every route in this inner scope. No domain handler executes
|
|
292
|
+
// without request.tenant, and without the multi-tenant module there is
|
|
293
|
+
// no tenant concept at all — the whole scope is module-conditional
|
|
294
|
+
// (S1, #5088), so an OSS build that excludes multi-tenant registers
|
|
295
|
+
// none of it.
|
|
296
|
+
if (isModuleEnabled('multi-tenant')) {
|
|
297
|
+
await authScope.register(async (tenantScope) => {
|
|
298
|
+
await tenantScope.register(await tenantPreHandlerSlicePlugin());
|
|
299
|
+
await tenantScope.register(await sliceRoutePlugin('workspaceSessionRoutes'));
|
|
300
|
+
await tenantScope.register(await sliceRoutePlugin('sessionRoutes'));
|
|
301
|
+
await tenantScope.register(await sliceRoutePlugin('workspaceConfigRoutes'));
|
|
302
|
+
// Org-billing routes (#3701) — org-scoped read + Stripe customer-portal.
|
|
303
|
+
await tenantScope.register(await sliceRoutePlugin('billingRoutes'));
|
|
304
|
+
// Waitlist operator-dashboard read API (#4665 D7, B0) — tenant-scoped
|
|
305
|
+
// list/comparison/signups reads over A1's waitlist-experiment rows.
|
|
306
|
+
await tenantScope.register(
|
|
307
|
+
await sliceRoutePlugin('waitlistExperimentRoutes'),
|
|
308
|
+
);
|
|
309
|
+
// Project-listings dashboard (#4998) — tenant-scoped list/get/patch
|
|
310
|
+
// over the founder's-application-row lifecycle.
|
|
311
|
+
const { projectListingTenantRoutes } = await import(
|
|
312
|
+
'./routes/project-listings/index.js'
|
|
313
|
+
);
|
|
314
|
+
await tenantScope.register(projectListingTenantRoutes);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
115
317
|
});
|
|
116
318
|
|
|
117
319
|
// Public routes — no auth required.
|
|
118
|
-
await server.register(
|
|
320
|
+
await server.register(listTypesRoute);
|
|
321
|
+
await server.register(listPagesRoute);
|
|
322
|
+
await server.register(getPageRoute);
|
|
323
|
+
// Content-write routes (create/update/delete) — already Pro-tier gated at
|
|
324
|
+
// CALL time via requirePaidTier (apps/api/src/lib/require-paid-tier.ts);
|
|
325
|
+
// module-conditional at REGISTRATION too (S1, #5088) so an OSS build that
|
|
326
|
+
// excludes the content-write slice never wires the handler in at all. Not
|
|
327
|
+
// a MODULE_SLICES entry — see config/modules.ts.
|
|
328
|
+
if (isModuleEnabled('content-write')) {
|
|
329
|
+
await server.register(await sliceRoutePlugin('createPageRoute'));
|
|
330
|
+
await server.register(await sliceRoutePlugin('updatePageRoute'));
|
|
331
|
+
await server.register(await sliceRoutePlugin('deletePageRoute'));
|
|
332
|
+
}
|
|
119
333
|
await server.register(checkoutRoutes);
|
|
334
|
+
// Deliverable download — a capability-token URL (#3961 D5); the token
|
|
335
|
+
// itself is the sole gate, so no auth preHandler applies.
|
|
336
|
+
await server.register(deliverableDownloadRoute);
|
|
120
337
|
|
|
121
338
|
// Webhooks routes — raw-body parser scoped to this sub-router only so the
|
|
122
339
|
// global JSON parser on all other routes is unaffected.
|
|
@@ -128,17 +345,100 @@ export async function build() {
|
|
|
128
345
|
done(null, body);
|
|
129
346
|
},
|
|
130
347
|
);
|
|
348
|
+
// Slack's block_actions payload arrives as a urlencoded `payload` form
|
|
349
|
+
// field (#4999) — raw buffer here too, so the signature is verified over
|
|
350
|
+
// the EXACT bytes Slack signed, never a re-serialized parse.
|
|
351
|
+
webhooksScope.addContentTypeParser(
|
|
352
|
+
'application/x-www-form-urlencoded',
|
|
353
|
+
{ parseAs: 'buffer' },
|
|
354
|
+
(_req, body, done) => {
|
|
355
|
+
done(null, body);
|
|
356
|
+
},
|
|
357
|
+
);
|
|
131
358
|
await webhooksScope.register(webhooksRoutes);
|
|
359
|
+
await webhooksScope.register(slackActionsRoute);
|
|
132
360
|
});
|
|
133
361
|
|
|
134
|
-
// Leads routes — rate-limit middleware scoped to this sub-router
|
|
362
|
+
// Leads routes — rate-limit middleware scoped to this sub-router. Own
|
|
363
|
+
// default (10/min, pre-#4730) rather than inheriting the wider
|
|
364
|
+
// flows-sized default (#5111, DEF-004 — #4730's shared-default bump was
|
|
365
|
+
// never meant to loosen abuse protection here).
|
|
135
366
|
await server.register(async (leadsScope) => {
|
|
136
|
-
leadsScope.register(rateLimitMiddleware
|
|
367
|
+
leadsScope.register(rateLimitMiddleware, {
|
|
368
|
+
perIpPerMinute: DEFAULT_PER_IP_PER_MINUTE_STRICT,
|
|
369
|
+
});
|
|
137
370
|
await leadsScope.register(leadSubmitRoute);
|
|
138
371
|
await leadsScope.register(leadSubscribeRoute);
|
|
139
372
|
await leadsScope.register(leadCallbackRoute);
|
|
373
|
+
// Project-listings anonymous surface (#4998, reshaped by #5036) — the
|
|
374
|
+
// three-operation draft lifecycle plus the public page-render read, all
|
|
375
|
+
// on the same rate-limited, identity-blind posture as the leads routes
|
|
376
|
+
// above.
|
|
377
|
+
//
|
|
378
|
+
// Do NOT read that rate limit as a bound on anonymous draft creation. It
|
|
379
|
+
// keys on `req.ip`, and `trustProxy` is on (see the note at the top of this
|
|
380
|
+
// file), so a caller reaching the API directly can vary
|
|
381
|
+
// `X-Forwarded-For` and get a fresh budget per request. That is a
|
|
382
|
+
// pre-existing property of the limiter, not of these routes; what these
|
|
383
|
+
// routes do is keep the cost of an unbounded call small — `start` writes
|
|
384
|
+
// one row and sends nothing, and the Lead write with its operator
|
|
385
|
+
// notification waits for `submit` (PR #5042 security review, finding 4).
|
|
386
|
+
await leadsScope.register(projectListingStartRoute);
|
|
387
|
+
await leadsScope.register(projectListingDraftPatchRoute);
|
|
388
|
+
await leadsScope.register(projectListingSubmitRoute);
|
|
389
|
+
await leadsScope.register(projectListingPublicRoute);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Flows routes — anonymous surface; rate-limit middleware scoped to this
|
|
393
|
+
// sub-router, matching the leads scope above (#3956 D4 Clarifications:
|
|
394
|
+
// "follows whatever the existing anonymous /v1/leads/* routes do today").
|
|
395
|
+
// Keeps the wider, env-var-driven default (#4730 — see
|
|
396
|
+
// apps/api/src/routes/flows/README.md § Rate limit) — this is the ONE
|
|
397
|
+
// scope #4730's bump was actually sized for; unchanged by #5111.
|
|
398
|
+
await server.register(async (flowsScope) => {
|
|
399
|
+
flowsScope.register(rateLimitMiddleware);
|
|
400
|
+
await flowsScope.register(getFlowRoute);
|
|
401
|
+
await flowsScope.register(submitFlowStepRoute);
|
|
402
|
+
await flowsScope.register(getFlowAggregateRoute);
|
|
403
|
+
// The recommender's email-moment routes (#4841) — same anonymous,
|
|
404
|
+
// rate-limited posture as the three above.
|
|
405
|
+
await flowsScope.register(saveRecommendationRoute);
|
|
406
|
+
await flowsScope.register(checkoutRecommendationRoute);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// AEO score routes (#4666) — anonymous surface, same posture as the flows
|
|
410
|
+
// scope above: a waitlist respondent has no account. Rate-limited because
|
|
411
|
+
// each call fans out to the respondent's own site (an external fetch), the
|
|
412
|
+
// same reason the schedule scope below is rate-limited for a third party.
|
|
413
|
+
// Own default (10/min, pre-#4730) — see the leads scope's comment above
|
|
414
|
+
// (#5111, DEF-004).
|
|
415
|
+
await server.register(async (aeoScope) => {
|
|
416
|
+
aeoScope.register(rateLimitMiddleware, {
|
|
417
|
+
perIpPerMinute: DEFAULT_PER_IP_PER_MINUTE_STRICT,
|
|
418
|
+
});
|
|
419
|
+
await aeoScope.register(scoreAeoRoute);
|
|
420
|
+
await aeoScope.register(exampleAeoRoute);
|
|
140
421
|
});
|
|
141
422
|
|
|
423
|
+
// Schedule routes (#4416) — anonymous surface, same posture as the flows
|
|
424
|
+
// and leads scopes above: a prospect booking a call has no account, and the
|
|
425
|
+
// calLink in the request names the event, so there is no tenant scope to
|
|
426
|
+
// bind. Rate-limited because each call fans out to a third-party provider.
|
|
427
|
+
// Own default (10/min, pre-#4730) — see the leads scope's comment above
|
|
428
|
+
// (#5111, DEF-004). Module-conditional (S1, #5088): the scheduling module
|
|
429
|
+
// owns this whole route set, so an OSS build that excludes it registers
|
|
430
|
+
// neither the routes nor their imports.
|
|
431
|
+
if (isModuleEnabled('scheduling')) {
|
|
432
|
+
await server.register(async (scheduleScope) => {
|
|
433
|
+
scheduleScope.register(rateLimitMiddleware, {
|
|
434
|
+
perIpPerMinute: DEFAULT_PER_IP_PER_MINUTE_STRICT,
|
|
435
|
+
});
|
|
436
|
+
await scheduleScope.register(await sliceRoutePlugin('listAvailabilityRoute'));
|
|
437
|
+
await scheduleScope.register(await sliceRoutePlugin('getEventMetaRoute'));
|
|
438
|
+
await scheduleScope.register(await sliceRoutePlugin('createBookingRoute'));
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
142
442
|
// Test-auth route — triple-gated (NODE_ENV !== production AND
|
|
143
443
|
// AILK_TEST_AUTH_ENABLED === 'true' AND AILK_TEST_AUTH_USER_ALLOWLIST
|
|
144
444
|
// non-empty). When any gate fails, the route is never registered and
|