create-ailk 0.5.0 → 0.6.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 +55 -8
- package/component-catalog.json +336 -27
- package/component-catalog.md +25 -12
- package/dist/cli.js +54 -5
- package/dist/copy.d.ts +14 -0
- package/dist/copy.js +38 -1
- package/dist/lib/api-boot-assertion.d.ts +46 -0
- package/dist/lib/api-boot-assertion.js +70 -0
- package/dist/lib/extract-module-bundle.d.ts +20 -1
- package/dist/lib/extract-module-bundle.js +64 -5
- package/dist/lib/import-graph.d.ts +29 -0
- package/dist/lib/import-graph.js +140 -0
- package/dist/lib/module-license-gate.d.ts +6 -1
- package/dist/lib/module-license-gate.js +6 -1
- package/dist/lib/pro-callout.js +1 -1
- package/dist/module-architecture.d.ts +1 -0
- package/dist/module-architecture.js +253 -127
- package/dist/modules/commerce/0.6.0.tar.gz +0 -0
- package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
- package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
- package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
- package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
- package/dist/modules/workspace/0.6.0.tar.gz +0 -0
- package/dist/programmatic.js +14 -10
- package/dist/surfaces.js +105 -7
- package/dist/template-manifest.d.ts +33 -0
- package/dist/template-manifest.js +99 -16
- package/dist/template-names.d.ts +1 -1
- package/dist/template-names.js +1 -0
- package/package.json +3 -2
- package/site-templates/marketing-site/DESIGN.md +148 -0
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +22 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +9 -2
- package/site-templates/marketing-site/ailk-template.json +1 -1
- package/site-templates/marketing-site-free/DESIGN.md +148 -0
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +2 -2
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +1 -0
- package/site-templates/minimalism-site/DESIGN.md +148 -0
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +10 -2
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +47 -35
- package/site-templates/minimalism-site/ailk-template.json +2 -1
- package/site-templates/minimalism-site/assets/wordmark-placeholder.svg +28 -0
- package/site-templates/minimalism-site/content/en/HomePage/home.mdx +49 -19
- package/site-templates/saas-product/DESIGN.md +148 -0
- package/site-templates/simple-service/DESIGN.md +148 -0
- package/site-templates/simple-service/TEMPLATE-MANIFEST.json +240 -0
- package/site-templates/simple-service/TEMPLATE-MANIFEST.md +278 -0
- package/site-templates/simple-service/ailk-template.json +10 -0
- package/site-templates/simple-service/content/en/AboutPage/about.mdx +38 -0
- package/site-templates/simple-service/content/en/ContactPage/contact.mdx +67 -0
- package/site-templates/simple-service/content/en/FAQPage/faq.mdx +56 -0
- package/site-templates/simple-service/content/en/HomePage/home.mdx +85 -0
- package/site-templates/simple-service/content/en/Service/landscape-design.mdx +40 -0
- package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +40 -0
- package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +40 -0
- package/site-templates/simple-service/content/en/ServicesList/services.mdx +72 -0
- package/site-templates/simple-service/provenance.json +4 -0
- package/templates/.env.example +72 -7
- package/templates/CLAUDE.md +2 -3
- package/templates/DESIGN.md +155 -0
- package/templates/README.md +42 -8
- package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +8 -0
- package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +12 -0
- package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +12 -0
- package/templates/apps/api/.env.example +13 -0
- package/templates/apps/api/CLAUDE.md +26 -2
- package/templates/apps/api/jest.config.cjs +3 -0
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +407 -0
- package/templates/apps/api/src/__tests__/module-exclusion.test.ts +83 -7
- package/templates/apps/api/src/__tests__/server.test.ts +471 -0
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +45 -0
- package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +2 -0
- package/templates/apps/api/src/config/index.ts +62 -0
- package/templates/apps/api/src/config/modules.ts +7 -3
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +238 -2
- package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +143 -0
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +23 -0
- package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +125 -0
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +20 -0
- package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +317 -0
- package/templates/apps/api/src/lib/__tests__/site.test.ts +238 -0
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +75 -0
- package/templates/apps/api/src/lib/auth-email-budget.ts +160 -0
- package/templates/apps/api/src/lib/content-adapter.ts +57 -31
- package/templates/apps/api/src/lib/deliverable-asset-store.ts +76 -0
- package/templates/apps/api/src/lib/error-serializer.ts +23 -3
- package/templates/apps/api/src/lib/outbound-http.ts +7 -2
- package/templates/apps/api/src/lib/require-commerce-claim.ts +250 -0
- package/templates/apps/api/src/lib/site.ts +208 -9
- package/templates/apps/api/src/lib/stripe.ts +66 -0
- package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +182 -0
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +42 -0
- package/templates/apps/api/src/middleware/rate-limit.ts +7 -1
- package/templates/apps/api/src/openapi/spec.ts +543 -2
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +48 -0
- package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +309 -0
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +123 -0
- package/templates/apps/api/src/routes/auth/transactional-email.ts +273 -0
- package/templates/apps/api/src/routes/auth/user.ts +61 -0
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +434 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +888 -0
- package/templates/apps/api/src/routes/checkout/index.ts +34 -0
- package/templates/apps/api/src/routes/checkout/session.ts +139 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +197 -0
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +554 -0
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +108 -0
- package/templates/apps/api/src/routes/content/__tests__/search.test.ts +450 -0
- package/templates/apps/api/src/routes/content/get-page.ts +94 -12
- package/templates/apps/api/src/routes/content/index.ts +13 -73
- package/templates/apps/api/src/routes/content/list-pages.ts +15 -3
- package/templates/apps/api/src/routes/content/rate-limit.ts +15 -6
- package/templates/apps/api/src/routes/content/search.ts +129 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +447 -31
- package/templates/apps/api/src/routes/leads/index.ts +100 -13
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +51 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +351 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +51 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +5 -2
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +4 -1
- package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +58 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +107 -6
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +87 -2
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +51 -0
- package/templates/apps/api/src/routes/project-listings/start.ts +5 -1
- package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +686 -0
- package/templates/apps/api/src/routes/requests/confirm.ts +601 -0
- package/templates/apps/api/src/routes/requests/index.ts +54 -0
- package/templates/apps/api/src/routes/webhooks/README.md +265 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +749 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +330 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +262 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +285 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +213 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +301 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +648 -0
- package/templates/apps/api/src/routes/webhooks/index.ts +89 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +1399 -0
- package/templates/apps/api/src/server.ts +439 -49
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +39 -0
- package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +217 -40
- package/templates/apps/api/src/services/__tests__/audit-log.test.ts +620 -0
- package/templates/apps/api/src/services/__tests__/consent.test.ts +2 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +300 -5
- package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +20 -0
- package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +368 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +160 -0
- package/templates/apps/api/src/services/__tests__/listing-config.test.ts +166 -0
- package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +154 -0
- package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +137 -0
- package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +444 -0
- package/templates/apps/api/src/services/__tests__/revalidation.test.ts +238 -0
- package/templates/apps/api/src/services/__tests__/verified-email.test.ts +78 -0
- package/templates/apps/api/src/services/abandon-email.ts +8 -2
- package/templates/apps/api/src/services/aeo-score.ts +49 -12
- package/templates/apps/api/src/services/audit-log.ts +668 -0
- package/templates/apps/api/src/services/consent.ts +18 -0
- package/templates/apps/api/src/services/default-tenant.ts +70 -31
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +141 -13
- package/templates/apps/api/src/services/dunning-policy.ts +294 -0
- package/templates/apps/api/src/services/entitlements.ts +80 -0
- package/templates/apps/api/src/services/lead-promotion.ts +13 -14
- package/templates/apps/api/src/services/lead-routing.ts +161 -2
- package/templates/apps/api/src/services/leads-inbox.ts +23 -2
- package/templates/apps/api/src/services/listing-config.ts +27 -9
- package/templates/apps/api/src/services/project-listings.ts +201 -6
- package/templates/apps/api/src/services/public-site-resolver.ts +106 -0
- package/templates/apps/api/src/services/request-confirm.ts +646 -0
- package/templates/apps/api/src/services/revalidation.ts +173 -0
- package/templates/apps/api/src/services/verified-email.ts +71 -0
- package/templates/apps/api/src/vercel-handler.ts +75 -35
- package/templates/apps/mcp/.env.example +17 -0
- package/templates/apps/mcp/CLAUDE.md +57 -24
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +6 -0
- package/templates/apps/mcp/__tests__/audit.test.ts +137 -8
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +79 -36
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +111 -2
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +82 -2
- package/templates/apps/mcp/__tests__/http-transport.test.ts +541 -2
- package/templates/apps/mcp/__tests__/index.test.ts +39 -0
- package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +143 -0
- package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +111 -0
- package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +65 -0
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +188 -0
- package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +165 -0
- package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +124 -0
- package/templates/apps/mcp/__tests__/list_pages.test.ts +116 -0
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +7 -1
- package/templates/apps/mcp/__tests__/parity.test.ts +10 -7
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +89 -22
- package/templates/apps/mcp/__tests__/read_content.test.ts +322 -1
- package/templates/apps/mcp/__tests__/search_content.test.ts +105 -2
- package/templates/apps/mcp/__tests__/server.test.ts +67 -14
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +252 -0
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +300 -123
- package/templates/apps/mcp/jest.config.cjs +13 -0
- package/templates/apps/mcp/package.json +2 -0
- package/templates/apps/mcp/src/abuse/index.ts +159 -24
- package/templates/apps/mcp/src/config/modules.ts +10 -5
- package/templates/apps/mcp/src/http-transport.ts +102 -29
- package/templates/apps/mcp/src/index.ts +73 -11
- package/templates/apps/mcp/src/lib/audit-single-page.ts +90 -3
- package/templates/apps/mcp/src/lib/commerce-claim.ts +94 -0
- package/templates/apps/mcp/src/lib/content-adapter.ts +113 -0
- package/templates/apps/mcp/src/lib/empty-content-adapter.ts +139 -0
- package/templates/apps/mcp/src/lib/prisma.ts +39 -0
- package/templates/apps/mcp/src/lib/public-workspace.ts +133 -0
- package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +59 -0
- package/templates/apps/mcp/src/server.ts +59 -35
- package/templates/apps/mcp/src/tools/audit.ts +26 -2
- package/templates/apps/mcp/src/tools/get_business_hours.ts +4 -3
- package/templates/apps/mcp/src/tools/get_faq.ts +4 -3
- package/templates/apps/mcp/src/tools/get_locations.ts +5 -3
- package/templates/apps/mcp/src/tools/get_offerings.ts +16 -4
- package/templates/apps/mcp/src/tools/get_pricing.ts +25 -6
- package/templates/apps/mcp/src/tools/get_site_info.ts +4 -3
- package/templates/apps/mcp/src/tools/index.ts +6 -4
- package/templates/apps/mcp/src/tools/list_pages.ts +4 -3
- package/templates/apps/mcp/src/tools/purchase.ts +128 -45
- package/templates/apps/mcp/src/tools/read_content.ts +20 -6
- package/templates/apps/mcp/src/tools/search_content.ts +11 -4
- package/templates/apps/web/.env.example +71 -5
- package/templates/apps/web/CLAUDE.md +44 -0
- package/templates/apps/web/PRODUCT.md +86 -0
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +18 -2
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +11 -3
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +282 -0
- package/templates/apps/web/app/[locale]/(auth)/__tests__/password-reset.test.tsx +515 -0
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +89 -0
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +109 -0
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +92 -0
- package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +135 -0
- package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +109 -0
- package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/__tests__/page.test.tsx +48 -2
- package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/page.tsx +20 -6
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +125 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +96 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +101 -0
- package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +102 -0
- package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +87 -0
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +20 -10
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +84 -0
- package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +58 -0
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +63 -8
- package/templates/apps/web/app/[locale]/(authed)/layout.tsx +18 -1
- package/templates/apps/web/app/[locale]/cancellation/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/layout.tsx +133 -87
- package/templates/apps/web/app/[locale]/purchase/__tests__/cancel.test.tsx +162 -0
- package/templates/apps/web/app/[locale]/purchase/__tests__/module-scope.test.ts +68 -0
- package/templates/apps/web/app/[locale]/purchase/__tests__/success.test.tsx +361 -0
- package/templates/apps/web/app/[locale]/purchase/cancel/page.tsx +115 -0
- package/templates/apps/web/app/[locale]/purchase/success/page.tsx +307 -0
- package/templates/apps/web/app/[locale]/returns/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/shipping/page.tsx +44 -0
- package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +670 -0
- package/templates/apps/web/app/api/revalidate/route.ts +194 -0
- package/templates/apps/web/auth.ts +407 -8
- package/templates/apps/web/jest.config.cjs +8 -4
- package/templates/apps/web/lib/__tests__/auth-email.test.ts +214 -0
- package/templates/apps/web/lib/__tests__/auth-routes.test.ts +74 -0
- package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +72 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +135 -20
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +18 -1
- package/templates/apps/web/lib/auth-email.ts +318 -0
- package/templates/apps/web/lib/auth-env.ts +85 -0
- package/templates/apps/web/lib/auth-routes.ts +55 -0
- package/templates/apps/web/lib/meeting-slugs.ts +53 -0
- package/templates/apps/web/lib/site-brand.tsx +4 -8
- package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
- package/templates/apps/web/messages/en.json +187 -0
- package/templates/apps/web/middleware.ts +1 -1
- package/templates/apps/web/package.json +2 -1
- package/templates/apps/web/src/lib/commerce-claim.ts +33 -0
- package/templates/apps/web/src/lib/commerce-sections.ts +93 -0
- package/templates/content/_site.mdx +18 -3
- package/templates/content/en/CancellationPolicyPage/cancellation.mdx +108 -0
- package/templates/content/en/ReturnsPolicyPage/returns.mdx +108 -0
- package/templates/content/en/ShippingPolicyPage/shipping.mdx +108 -0
- package/templates/database/CHANGELOG.md +149 -0
- package/templates/database/README.md +10 -3
- package/templates/database/__tests__/appointment.db.test.ts +106 -0
- package/templates/database/__tests__/artifact-content-store.db.test.ts +316 -0
- package/templates/database/__tests__/composite-fence.db.test.ts +206 -0
- package/templates/database/__tests__/fence-fan-out.db.test.ts +711 -0
- package/templates/database/__tests__/fixtures/appointment-create-probe.ts +79 -0
- package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +100 -0
- package/templates/database/__tests__/flow-workspace-key.db.test.ts +263 -0
- package/templates/database/__tests__/prefixed-ids.db.test.ts +85 -9
- package/templates/database/__tests__/project-listing-consent-at.db.test.ts +111 -0
- package/templates/database/__tests__/tenancy.test.ts +141 -0
- package/templates/database/config/schema.prisma +79 -2
- package/templates/database/content/schema.prisma +87 -11
- package/templates/database/inbox/schema.prisma +452 -9
- package/templates/database/jest.config.cjs +5 -3
- package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +15 -0
- package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +158 -0
- package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +40 -0
- package/templates/database/migrations/20260918120000_add_appointment/migration.sql +67 -0
- package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +70 -0
- package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +181 -0
- package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +172 -0
- package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +41 -0
- package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +185 -0
- package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +70 -0
- package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +57 -0
- package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +68 -0
- package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +1067 -0
- package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +210 -0
- package/templates/database/package.json +3 -2
- package/templates/database/tenancy.ts +86 -1
- package/templates/database/tsconfig.json +1 -0
- package/versions.json +34 -34
- package/templates/apps/api/src/routes/content/__tests__/create.test.ts +0 -253
- package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +0 -215
- package/templates/apps/api/src/routes/content/__tests__/update.test.ts +0 -266
- package/templates/apps/api/src/routes/content/create.ts +0 -115
- package/templates/apps/api/src/routes/content/delete.ts +0 -82
- package/templates/apps/api/src/routes/content/update.ts +0 -112
- package/templates/apps/mcp/__tests__/create_page.test.ts +0 -202
- package/templates/apps/mcp/__tests__/delete_page.test.ts +0 -177
- package/templates/apps/mcp/__tests__/update_page.test.ts +0 -196
- package/templates/apps/mcp/src/tools/create_page.ts +0 -96
- package/templates/apps/mcp/src/tools/delete_page.ts +0 -74
- package/templates/apps/mcp/src/tools/update_page.ts +0 -92
- package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +0 -123
- package/templates/apps/web/public/logo-dark.svg +0 -21
- package/templates/apps/web/public/logo-light.svg +0 -21
- /package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/__tests__/next-path.test.ts +0 -0
- /package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/next-path.ts +0 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// oss: false
|
|
2
|
+
/**
|
|
3
|
+
* /[locale]/purchase/success — the order-confirmation return page (#6084).
|
|
4
|
+
*
|
|
5
|
+
* NOTE on `// oss: false` — a DELIBERATE correction to the spec's NFR-4,
|
|
6
|
+
* which assumed this page could ship unmarked like the base-tree checkout
|
|
7
|
+
* API primitives (`routes/checkout/sessions.ts`, `tools/purchase.ts`). Those
|
|
8
|
+
* import only OSS `@working-theory/stripe-client`; THIS page renders
|
|
9
|
+
* `payment-receipt` via `registerCommerceSections()` from the PAID
|
|
10
|
+
* `@working-theory/ui-commerce` package (D5) — the same shape `/meet`
|
|
11
|
+
* already has for `@working-theory/ui-scheduling`. The architecture lint's
|
|
12
|
+
* OSS→paid boundary rule (`architecture.yaml` forbidden_patterns) requires
|
|
13
|
+
* either no marker + no paid import, or a `paths_excluded` entry PLUS this
|
|
14
|
+
* marker (the `meet/**` precedent) — never no-marker-with-a-paid-import.
|
|
15
|
+
* `create-ailk`'s scaffold is UNAFFECTED: `CORE_ROUTE_DIRS`
|
|
16
|
+
* (`packages/create-ailk/src/surfaces.ts`) governs what a scaffold carries,
|
|
17
|
+
* not this marker, so AC-4/FR-8 still hold — every scaffold gets this file
|
|
18
|
+
* regardless. Only the ai-launch-kit-internal → ai-launch-kit PUBLIC-REPO
|
|
19
|
+
* split (a different mechanism) reads this marker.
|
|
20
|
+
*
|
|
21
|
+
* READS the Checkout Session the Stripe webhook already granted (spec §1.2)
|
|
22
|
+
* — this page never writes: no Prisma call, no Stripe write, no grant, no
|
|
23
|
+
* stamp (AC-1, FR-3). It is reachable by anyone holding a `cs_…` id, with
|
|
24
|
+
* no credential at all (D8) — the design below is built around that fact.
|
|
25
|
+
*
|
|
26
|
+
* D6 — the paid render is not forgeable. `outcome: "success"` is Stripe's
|
|
27
|
+
* proof-of-payment status (a green chip, `data-outcome="success"`, and a
|
|
28
|
+
* schema.org `PaymentComplete` node — `PaymentResult.tsx`), so the
|
|
29
|
+
* `payment-receipt` section is constructed ONLY on a 2xx read with
|
|
30
|
+
* `paymentStatus === "paid"`. Every other reachable state — no
|
|
31
|
+
* `session_id`, an API failure, or a 2xx read that is not yet paid —
|
|
32
|
+
* renders a DIFFERENT chassis (`content-block` → `cta`, not a
|
|
33
|
+
* `CheckoutDeliveryPage`) with no badge, no `data-outcome` and no
|
|
34
|
+
* `PaymentComplete` string anywhere in the DOM (AC-8).
|
|
35
|
+
*
|
|
36
|
+
* D12 — base tree, request-time gate. This page ships unconditionally in
|
|
37
|
+
* every scaffold; whether it SERVES is decided per request by the
|
|
38
|
+
* `commerce` licence claim (`../../../../src/lib/commerce-claim.ts`,
|
|
39
|
+
* extracted from `.well-known/mcp.json`'s own check). `notFound()` on no
|
|
40
|
+
* claim is indistinguishable from a build without the module — before any
|
|
41
|
+
* API call, before any render.
|
|
42
|
+
*
|
|
43
|
+
* The `ui-commerce` package itself is registered LAZILY
|
|
44
|
+
* (`../../../../src/lib/commerce-sections.ts`), never via a top-level
|
|
45
|
+
* static import — a keyless scaffold carries no dependency on it by design
|
|
46
|
+
* (#5581 U6/D5), and a static import would fail every keyless build
|
|
47
|
+
* regardless of the request-time gate above. When the module genuinely is
|
|
48
|
+
* not installed, `paidSections()` below falls back to an OSS
|
|
49
|
+
* `content-block` carrying the same confirmation copy, rather than the bare
|
|
50
|
+
* `payment-receipt` section `SectionRenderer` would otherwise silently
|
|
51
|
+
* render as nothing (`ModuleAbsent` in production).
|
|
52
|
+
*
|
|
53
|
+
* `noindex`: reachable only by finishing (or trying) a Checkout, never a
|
|
54
|
+
* page a crawler should list.
|
|
55
|
+
*/
|
|
56
|
+
import { checkout } from "@working-theory/api-client";
|
|
57
|
+
import type { CheckoutSessionReadResponse } from "@working-theory/api-client";
|
|
58
|
+
import { SectionRenderer } from "@working-theory/ui/sections";
|
|
59
|
+
import type { PageSection } from "@working-theory/validation";
|
|
60
|
+
import { formatMoney } from "@working-theory/web-i18n";
|
|
61
|
+
import type { Metadata } from "next";
|
|
62
|
+
import { headers } from "next/headers";
|
|
63
|
+
import { notFound } from "next/navigation";
|
|
64
|
+
import { getTranslations } from "next-intl/server";
|
|
65
|
+
import type { ReactElement } from "react";
|
|
66
|
+
|
|
67
|
+
import { resolveCommerceClaim } from "../../../../src/lib/commerce-claim";
|
|
68
|
+
import { ensureCommerceSectionsRegistered } from "../../../../src/lib/commerce-sections";
|
|
69
|
+
|
|
70
|
+
// The success page reads `searchParams` (dynamic by construction); paired
|
|
71
|
+
// with the cancel page's explicit `force-dynamic` so a site that buys
|
|
72
|
+
// commerce after its last deploy is not stuck serving a prerendered 404
|
|
73
|
+
// (D12).
|
|
74
|
+
export const dynamic = "force-dynamic";
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* `next-intl`'s `getTranslations()` return type, so it can be passed
|
|
78
|
+
* between the section builders below (this repo has no other precedent
|
|
79
|
+
* typing it explicitly, since no other page passes `t` across functions).
|
|
80
|
+
*/
|
|
81
|
+
type PurchaseT = Awaited<ReturnType<typeof getTranslations>>;
|
|
82
|
+
|
|
83
|
+
interface Props {
|
|
84
|
+
params: Promise<{ locale: string }>;
|
|
85
|
+
searchParams?: Promise<{ session_id?: string | string[] }>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** First value only — a repeated query param must not become an array here. */
|
|
89
|
+
function firstValue(raw: string | string[] | undefined): string | undefined {
|
|
90
|
+
if (Array.isArray(raw)) return raw[0];
|
|
91
|
+
return raw;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Reads the visitor's real IP from THIS page's own incoming request —
|
|
96
|
+
* never from the query string — preferring `x-forwarded-for` and falling
|
|
97
|
+
* back to `x-real-ip`. Returns `undefined` rather than throwing on any
|
|
98
|
+
* failure. A local copy of `flows/[slug]/checkout.actions.ts`'s identical
|
|
99
|
+
* helper (#4730) — every RSC-to-API caller carries its own copy rather than
|
|
100
|
+
* a shared import, since this one crosses the OSS/paid boundary the other
|
|
101
|
+
* doesn't. Without it, `apps/api`'s rate limiter
|
|
102
|
+
* (`middleware/rate-limit.ts`) sees the Next server's own egress IP for
|
|
103
|
+
* every buyer, collapsing them into one shared bucket (security-review
|
|
104
|
+
* finding on this issue's PR — #6084).
|
|
105
|
+
*/
|
|
106
|
+
async function resolveVisitorIpInit(): Promise<
|
|
107
|
+
{ headers: Record<string, string> } | undefined
|
|
108
|
+
> {
|
|
109
|
+
try {
|
|
110
|
+
const incoming = await headers();
|
|
111
|
+
const visitorIp =
|
|
112
|
+
incoming.get("x-forwarded-for") ?? incoming.get("x-real-ip");
|
|
113
|
+
return visitorIp
|
|
114
|
+
? { headers: { "x-forwarded-for": visitorIp } }
|
|
115
|
+
: undefined;
|
|
116
|
+
} catch {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The onward `cta` section every one of D6's five rows carries (AC-7 — never a dead end). */
|
|
122
|
+
function ctaSection(t: PurchaseT): PageSection {
|
|
123
|
+
return {
|
|
124
|
+
id: "purchase-success-cta",
|
|
125
|
+
type: "cta",
|
|
126
|
+
data: {
|
|
127
|
+
headline: t("success.ctaHeadline"),
|
|
128
|
+
description: t("success.ctaDescription"),
|
|
129
|
+
primaryCta: { label: t("success.ctaLabel"), href: "/services" },
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** One card per paid line item — the D5 seam: `items`, not `payment-receipt`, carries the lines. */
|
|
135
|
+
function itemsSection(
|
|
136
|
+
lineItems: CheckoutSessionReadResponse["lineItems"],
|
|
137
|
+
t: PurchaseT,
|
|
138
|
+
locale: string,
|
|
139
|
+
): PageSection {
|
|
140
|
+
return {
|
|
141
|
+
id: "purchase-success-items",
|
|
142
|
+
type: "items",
|
|
143
|
+
data: {
|
|
144
|
+
items: lineItems.map((line) => ({
|
|
145
|
+
title: line.description,
|
|
146
|
+
description: t("success.lineItem", {
|
|
147
|
+
quantity: line.quantity,
|
|
148
|
+
amount: formatMoney(line.amountTotal, line.currency, locale),
|
|
149
|
+
}),
|
|
150
|
+
})),
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* D6's degraded-state row: no `session_id`, a shape-gate reject, an API
|
|
157
|
+
* 404/non-2xx, or a session that isn't yet paid — all render honestly
|
|
158
|
+
* rather than claiming a payment. `content-block` → `cta`; no
|
|
159
|
+
* `payment-receipt`, so no badge and no schema.org node exists to be read.
|
|
160
|
+
*/
|
|
161
|
+
function unknownSections(t: PurchaseT): PageSection[] {
|
|
162
|
+
return [
|
|
163
|
+
{
|
|
164
|
+
id: "purchase-success-unknown",
|
|
165
|
+
type: "content-block",
|
|
166
|
+
data: {
|
|
167
|
+
headline: t("success.unknownHeadline"),
|
|
168
|
+
body: t("success.unknownBody"),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
ctaSection(t),
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** 2xx, `paymentStatus` is `"unpaid"` or `"no_payment_required"` — D6 row 2. */
|
|
176
|
+
function pendingSections(
|
|
177
|
+
session: CheckoutSessionReadResponse,
|
|
178
|
+
t: PurchaseT,
|
|
179
|
+
locale: string,
|
|
180
|
+
): PageSection[] {
|
|
181
|
+
return [
|
|
182
|
+
{
|
|
183
|
+
id: "purchase-success-pending",
|
|
184
|
+
type: "content-block",
|
|
185
|
+
data: {
|
|
186
|
+
headline: t("success.pendingHeadline"),
|
|
187
|
+
body: t("success.pendingBody"),
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
itemsSection(session.lineItems, t, locale),
|
|
191
|
+
ctaSection(t),
|
|
192
|
+
];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The OSS degrade for `paidSections()` — carries the same title/message/
|
|
197
|
+
* status copy as `payment-receipt`, minus its badge/schema.org markers, for
|
|
198
|
+
* a deployment where `@working-theory/ui-commerce` is genuinely not
|
|
199
|
+
* installed (a keyless scaffold with a `commerce` licence claim but no
|
|
200
|
+
* redeploy since buying it — `ensureCommerceSectionsRegistered()`'s own
|
|
201
|
+
* doc comment).
|
|
202
|
+
*/
|
|
203
|
+
function paidFallbackSection(t: PurchaseT): PageSection {
|
|
204
|
+
return {
|
|
205
|
+
id: "purchase-success-receipt-fallback",
|
|
206
|
+
type: "content-block",
|
|
207
|
+
data: {
|
|
208
|
+
headline: t("success.title"),
|
|
209
|
+
body: `${t("success.message")} ${t("success.statusLabel")}`,
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** 2xx AND `paymentStatus === "paid"` — the ONLY row that constructs `payment-receipt` (D6). */
|
|
215
|
+
async function paidSections(
|
|
216
|
+
session: CheckoutSessionReadResponse,
|
|
217
|
+
t: PurchaseT,
|
|
218
|
+
locale: string,
|
|
219
|
+
): Promise<PageSection[]> {
|
|
220
|
+
const commerceSectionsAvailable = await ensureCommerceSectionsRegistered();
|
|
221
|
+
const receipt: PageSection = commerceSectionsAvailable
|
|
222
|
+
? {
|
|
223
|
+
id: "purchase-success-receipt",
|
|
224
|
+
type: "payment-receipt",
|
|
225
|
+
data: {
|
|
226
|
+
outcome: "success",
|
|
227
|
+
title: t("success.title"),
|
|
228
|
+
message: t("success.message"),
|
|
229
|
+
statusLabel: t("success.statusLabel"),
|
|
230
|
+
amount: {
|
|
231
|
+
amountMinor: session.amountTotal ?? 0,
|
|
232
|
+
currency: session.currency,
|
|
233
|
+
},
|
|
234
|
+
locale,
|
|
235
|
+
sessionId: session.id,
|
|
236
|
+
sessionIdLabel: t("success.sessionIdLabel"),
|
|
237
|
+
},
|
|
238
|
+
}
|
|
239
|
+
: paidFallbackSection(t);
|
|
240
|
+
return [receipt, itemsSection(session.lineItems, t, locale), ctaSection(t)];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** D6's five-row table, collapsed to the three code paths that produce distinct output. */
|
|
244
|
+
async function sectionsFor(
|
|
245
|
+
sessionId: string | undefined,
|
|
246
|
+
t: PurchaseT,
|
|
247
|
+
locale: string,
|
|
248
|
+
): Promise<PageSection[]> {
|
|
249
|
+
if (!sessionId) return unknownSections(t);
|
|
250
|
+
|
|
251
|
+
// A malformed/oversized id (D8's shape gate) or an unknown session both
|
|
252
|
+
// answer non-2xx here — the API's failure is logged server-side and never
|
|
253
|
+
// surfaced to the buyer (spec §3 D6 table). `checkout.getSession()` calls
|
|
254
|
+
// `fetch()` directly with no try/catch of its own
|
|
255
|
+
// (`packages/api-client/src/http.ts`), so a network-level failure (the API
|
|
256
|
+
// unreachable, DNS, a dropped connection) REJECTS rather than resolving
|
|
257
|
+
// `{ ok: false }` — caught here so it degrades identically to a non-2xx
|
|
258
|
+
// response instead of crashing the page (AC-7's "never a dead end",
|
|
259
|
+
// code-review finding on this issue's PR).
|
|
260
|
+
let res: Awaited<ReturnType<typeof checkout.getSession>>;
|
|
261
|
+
try {
|
|
262
|
+
res = await checkout.getSession(sessionId, await resolveVisitorIpInit());
|
|
263
|
+
} catch {
|
|
264
|
+
return unknownSections(t);
|
|
265
|
+
}
|
|
266
|
+
if (!res.ok) return unknownSections(t);
|
|
267
|
+
|
|
268
|
+
if (res.body.paymentStatus !== "paid") {
|
|
269
|
+
return pendingSections(res.body, t, locale);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return await paidSections(res.body, t, locale);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
276
|
+
const { locale } = await params;
|
|
277
|
+
const t = await getTranslations({ locale, namespace: "purchase" });
|
|
278
|
+
return {
|
|
279
|
+
title: t("success.title"),
|
|
280
|
+
description: t("success.message"),
|
|
281
|
+
robots: { index: false, follow: true },
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export default async function Page({
|
|
286
|
+
params,
|
|
287
|
+
searchParams,
|
|
288
|
+
}: Props): Promise<ReactElement> {
|
|
289
|
+
const { locale } = await params;
|
|
290
|
+
const t: PurchaseT = await getTranslations({ locale, namespace: "purchase" });
|
|
291
|
+
|
|
292
|
+
// D12 — request-time gate, before any API call and before any render.
|
|
293
|
+
if (!(await resolveCommerceClaim())) {
|
|
294
|
+
notFound();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const query = searchParams ? await searchParams : {};
|
|
298
|
+
const sessionId = firstValue(query.session_id);
|
|
299
|
+
|
|
300
|
+
const sections = await sectionsFor(sessionId, t, locale);
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<main>
|
|
304
|
+
<SectionRenderer sections={sections} locale={locale} />
|
|
305
|
+
</main>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ReturnsPolicyPage route (#5947). Reads the ReturnsPolicyPage MDX frontmatter, renders sections via
|
|
2
|
+
// SectionRenderer, and emits a JSON-LD <script>.
|
|
3
|
+
import type {
|
|
4
|
+
getMdxSource as defaultGetMdxSource,
|
|
5
|
+
getPageSections as defaultGetPageSections} from "@working-theory/page-renderer";
|
|
6
|
+
import {
|
|
7
|
+
renderPage,
|
|
8
|
+
renderPageMetadata
|
|
9
|
+
} from "@working-theory/page-renderer";
|
|
10
|
+
import type { Metadata } from "next";
|
|
11
|
+
import type { ReactElement } from "react";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
params: Promise<{ locale: string }>;
|
|
15
|
+
getMdxSource?: typeof defaultGetMdxSource;
|
|
16
|
+
getPageSections?: typeof defaultGetPageSections;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function generateMetadata({
|
|
20
|
+
params,
|
|
21
|
+
}: Pick<Props, "params">): Promise<Metadata> {
|
|
22
|
+
const { locale } = await params;
|
|
23
|
+
return renderPageMetadata({ type: "ReturnsPolicyPage", slug: "returns", locale });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default async function Page({
|
|
27
|
+
params,
|
|
28
|
+
getMdxSource,
|
|
29
|
+
getPageSections,
|
|
30
|
+
}: Props): Promise<ReactElement> {
|
|
31
|
+
const { locale } = await params;
|
|
32
|
+
return renderPage({
|
|
33
|
+
type: "ReturnsPolicyPage",
|
|
34
|
+
slug: "returns",
|
|
35
|
+
locale,
|
|
36
|
+
// Without a namespace `renderPage` 404s on a missing seed — and a scaffold
|
|
37
|
+
// IS a missing-seed environment, since `build-templates.mjs` snapshots
|
|
38
|
+
// `apps/` but deliberately not `content/`. The namespace makes this route
|
|
39
|
+
// render the #4154 authoring empty state at 200, exactly as /terms does.
|
|
40
|
+
translationsNamespace: "returns",
|
|
41
|
+
...(getMdxSource !== undefined && { getMdxSource }),
|
|
42
|
+
...(getPageSections !== undefined && { getPageSections }),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ShippingPolicyPage route (#5947). Reads the ShippingPolicyPage MDX frontmatter, renders sections via
|
|
2
|
+
// SectionRenderer, and emits a JSON-LD <script>.
|
|
3
|
+
import type {
|
|
4
|
+
getMdxSource as defaultGetMdxSource,
|
|
5
|
+
getPageSections as defaultGetPageSections} from "@working-theory/page-renderer";
|
|
6
|
+
import {
|
|
7
|
+
renderPage,
|
|
8
|
+
renderPageMetadata
|
|
9
|
+
} from "@working-theory/page-renderer";
|
|
10
|
+
import type { Metadata } from "next";
|
|
11
|
+
import type { ReactElement } from "react";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
params: Promise<{ locale: string }>;
|
|
15
|
+
getMdxSource?: typeof defaultGetMdxSource;
|
|
16
|
+
getPageSections?: typeof defaultGetPageSections;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function generateMetadata({
|
|
20
|
+
params,
|
|
21
|
+
}: Pick<Props, "params">): Promise<Metadata> {
|
|
22
|
+
const { locale } = await params;
|
|
23
|
+
return renderPageMetadata({ type: "ShippingPolicyPage", slug: "shipping", locale });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default async function Page({
|
|
27
|
+
params,
|
|
28
|
+
getMdxSource,
|
|
29
|
+
getPageSections,
|
|
30
|
+
}: Props): Promise<ReactElement> {
|
|
31
|
+
const { locale } = await params;
|
|
32
|
+
return renderPage({
|
|
33
|
+
type: "ShippingPolicyPage",
|
|
34
|
+
slug: "shipping",
|
|
35
|
+
locale,
|
|
36
|
+
// Without a namespace `renderPage` 404s on a missing seed — and a scaffold
|
|
37
|
+
// IS a missing-seed environment, since `build-templates.mjs` snapshots
|
|
38
|
+
// `apps/` but deliberately not `content/`. The namespace makes this route
|
|
39
|
+
// render the #4154 authoring empty state at 200, exactly as /terms does.
|
|
40
|
+
translationsNamespace: "shipping",
|
|
41
|
+
...(getMdxSource !== undefined && { getMdxSource }),
|
|
42
|
+
...(getPageSections !== undefined && { getPageSections }),
|
|
43
|
+
});
|
|
44
|
+
}
|