create-ailk 0.4.0 → 0.6.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 +55 -8
- package/component-catalog.json +12248 -0
- package/component-catalog.md +193 -68
- package/dist/cli.js +29 -1
- package/dist/derive-architecture.js +5 -2
- 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 +50 -2
- package/dist/lib/extract-module-bundle.js +223 -15
- package/dist/lib/fetch-guard.d.ts +28 -0
- package/dist/lib/fetch-guard.js +101 -0
- package/dist/lib/fetch-module.js +4 -0
- package/dist/lib/fetch-template.js +4 -0
- package/dist/lib/import-graph.d.ts +29 -0
- package/dist/lib/import-graph.js +140 -0
- package/dist/module-architecture.d.ts +60 -8
- package/dist/module-architecture.js +587 -242
- package/dist/parse-args.js +6 -2
- package/dist/programmatic.d.ts +10 -0
- package/dist/programmatic.js +134 -19
- package/dist/site-chrome.d.ts +80 -0
- package/dist/site-chrome.js +135 -0
- package/dist/surfaces.d.ts +21 -6
- package/dist/surfaces.js +209 -36
- package/dist/template-manifest.d.ts +88 -3
- package/dist/template-manifest.js +281 -29
- package/dist/template-names.d.ts +1 -1
- package/dist/template-names.js +2 -0
- package/package.json +10 -2
- package/site-templates/_base/ailk-template.json +6 -0
- package/site-templates/_base/content/en/Pricing/pricing.mdx +169 -0
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +351 -0
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +400 -0
- package/site-templates/marketing-site/ailk-template.json +11 -0
- package/site-templates/marketing-site/content/en/blog/05-this-vc-morning-routine-will-make-you-super-annoying.mdx +36 -0
- package/site-templates/marketing-site/provenance.json +4 -0
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +288 -0
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +286 -0
- package/site-templates/marketing-site-free/ailk-template.json +2 -1
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +279 -0
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +336 -0
- package/site-templates/minimalism-site/ailk-template.json +22 -0
- package/site-templates/minimalism-site/assets/avatar-placeholder-1.svg +7 -0
- package/site-templates/minimalism-site/assets/avatar-placeholder-2.svg +7 -0
- package/site-templates/minimalism-site/assets/avatar-placeholder-3.svg +7 -0
- package/site-templates/minimalism-site/assets/avatar-placeholder-4.svg +7 -0
- package/site-templates/minimalism-site/assets/avatar-placeholder-5.svg +7 -0
- package/site-templates/minimalism-site/assets/avatar-placeholder-6.svg +7 -0
- package/site-templates/minimalism-site/assets/hero-backdrop.svg +17 -0
- package/site-templates/minimalism-site/assets/logo-placeholder-1.svg +6 -0
- package/site-templates/minimalism-site/assets/logo-placeholder-2.svg +6 -0
- package/site-templates/minimalism-site/assets/logo-placeholder-3.svg +6 -0
- package/site-templates/minimalism-site/assets/wordmark-placeholder.svg +28 -0
- package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +110 -0
- package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +68 -0
- package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +57 -0
- package/site-templates/minimalism-site/content/en/HomePage/home.mdx +244 -0
- package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +77 -0
- package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +73 -0
- package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +52 -0
- package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +52 -0
- package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +52 -0
- package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +52 -0
- package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +38 -0
- package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +38 -0
- package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +38 -0
- package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +73 -0
- package/site-templates/minimalism-site/flows/referral.flow.json +71 -0
- package/site-templates/minimalism-site/provenance.json +4 -0
- package/site-templates/saas-product/TEMPLATE-MANIFEST.md +61 -0
- package/site-templates/saas-product/ailk-template.json +16 -0
- package/site-templates/saas-product/provenance.json +10 -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/.claude/skills/README.md +16 -25
- package/templates/.env.example +102 -12
- package/templates/.github/workflows/ci.yml +48 -0
- package/templates/README.md +3 -1
- 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 +29 -2
- package/templates/apps/api/eslint.config.mjs +69 -0
- package/templates/apps/api/jest.config.cjs +3 -0
- package/templates/apps/api/package.json +7 -2
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +407 -0
- package/templates/apps/api/src/__tests__/module-exclusion.test.ts +89 -9
- package/templates/apps/api/src/__tests__/review-surface-registration.test.ts +167 -0
- 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 +10 -1
- 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 +241 -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 +521 -0
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +150 -0
- package/templates/apps/api/src/middleware/default-tenant.ts +136 -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/__tests__/list.test.ts +171 -0
- package/templates/apps/api/src/routes/leads/index.ts +100 -13
- package/templates/apps/api/src/routes/leads/list.ts +104 -0
- 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 +521 -55
- 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-promotion.test.ts +408 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +160 -0
- package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +329 -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 +300 -0
- 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 +160 -0
- package/templates/apps/api/src/services/lead-routing.ts +161 -2
- package/templates/apps/api/src/services/leads-inbox.ts +284 -0
- package/templates/apps/api/src/services/listing-config.ts +27 -9
- package/templates/apps/api/src/services/owner-workspaces.ts +132 -0
- 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 +58 -25
- 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 +12 -9
- 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/{scaffold.test.ts → create_project.test.ts} +23 -23
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +300 -123
- package/templates/apps/mcp/eslint.config.mjs +69 -0
- package/templates/apps/mcp/jest.config.cjs +13 -0
- package/templates/apps/mcp/package.json +8 -2
- 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 +61 -37
- package/templates/apps/mcp/src/tools/audit.ts +26 -2
- package/templates/apps/mcp/src/tools/{scaffold.ts → create_project.ts} +3 -3
- 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 +9 -7
- 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 +74 -8
- package/templates/apps/web/CLAUDE.md +46 -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 +67 -14
- package/templates/apps/web/app/[locale]/(authed)/layout.tsx +19 -2
- package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +181 -0
- package/templates/apps/web/app/[locale]/(authed)/leads/components/LeadsTable.tsx +137 -0
- package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +111 -0
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +1 -1
- package/templates/apps/web/app/[locale]/[slug]/__tests__/page.test.tsx +111 -0
- package/templates/apps/web/app/[locale]/[slug]/page.tsx +65 -0
- package/templates/apps/web/app/[locale]/cancellation/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +1 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +6 -5
- package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +1 -1
- package/templates/apps/web/app/[locale]/layout.tsx +308 -65
- 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/components/google-analytics.tsx +18 -1
- package/templates/apps/web/eslint.config.mjs +69 -0
- package/templates/apps/web/jest.config.cjs +15 -19
- 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__/structured-data.test.tsx +50 -6
- 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/nav-config.ts +27 -7
- package/templates/apps/web/lib/server-api.ts +1 -1
- package/templates/apps/web/lib/site-chrome.ts +29 -0
- package/templates/apps/web/lib/telemetry-scrub.ts +50 -0
- package/templates/apps/web/messages/en.json +216 -2
- package/templates/apps/web/next.config.mjs +20 -0
- package/templates/apps/web/package.json +8 -3
- package/templates/apps/web/sentry.client.config.ts +131 -0
- package/templates/apps/web/sentry.edge.config.ts +72 -0
- package/templates/apps/web/sentry.server.config.ts +72 -0
- package/templates/apps/web/src/lib/commerce-claim.ts +33 -0
- package/templates/apps/web/src/lib/commerce-sections.ts +61 -0
- package/templates/apps/web/src/lib/routes.ts +13 -18
- package/templates/brand_assets/README.md +24 -0
- package/templates/content/en/AboutPage/about.mdx +160 -15
- package/templates/content/en/CancellationPolicyPage/cancellation.mdx +108 -0
- package/templates/content/en/ContactPage/contact.mdx +90 -13
- package/templates/content/en/FAQPage/faq.mdx +62 -22
- package/templates/content/en/HomePage/home.mdx +244 -20
- package/templates/content/en/LandingPage/blog.mdx +83 -0
- package/templates/content/en/LandingPage/features.mdx +103 -0
- package/templates/content/en/LandingPage/how-it-works.mdx +143 -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__/seed.test.ts +1 -1
- 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/eslint.config.mjs +69 -0
- 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 +7 -3
- package/templates/database/seed.ts +1 -1
- package/templates/database/tenancy.ts +86 -1
- package/templates/database/tsconfig.json +1 -0
- package/templates/package.json +1 -14
- package/versions.json +52 -0
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -103
- 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/site-templates/{marketing-site-free → _base}/content/en/PrivacyPage/privacy.mdx +0 -0
- /package/site-templates/{marketing-site-free → _base}/content/en/TermsPage/terms.mdx +0 -0
- /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
- /package/templates/apps/web/{src/components → components}/SiteNav.tsx +0 -0
|
@@ -9,7 +9,17 @@
|
|
|
9
9
|
"schedule": "Book a call",
|
|
10
10
|
"signIn": "Sign in",
|
|
11
11
|
"signOut": "Sign out",
|
|
12
|
-
"account": "Account"
|
|
12
|
+
"account": "Account",
|
|
13
|
+
"product": "Product",
|
|
14
|
+
"howItWorks": "How it works",
|
|
15
|
+
"howItWorksDesc": "What happens from install to launch",
|
|
16
|
+
"features": "Features",
|
|
17
|
+
"featuresDesc": "Everything the kit ships with",
|
|
18
|
+
"faq": "FAQ",
|
|
19
|
+
"faqDesc": "Answers to the questions we get most",
|
|
20
|
+
"pricing": "Pricing",
|
|
21
|
+
"about": "About",
|
|
22
|
+
"getStarted": "Get started"
|
|
13
23
|
},
|
|
14
24
|
"consent": {
|
|
15
25
|
"title": "Cookie Preferences",
|
|
@@ -39,6 +49,10 @@
|
|
|
39
49
|
"emptyState": "No documentation yet. Add MDX files to",
|
|
40
50
|
"emptyStateTrailing": "to populate this list."
|
|
41
51
|
},
|
|
52
|
+
"cancellation": {
|
|
53
|
+
"heading": "Cancellation Policy",
|
|
54
|
+
"emptyState": "Cancellation policy content coming soon."
|
|
55
|
+
},
|
|
42
56
|
"careers": {
|
|
43
57
|
"heading": "Careers",
|
|
44
58
|
"emptyState": "Career listings coming soon."
|
|
@@ -167,6 +181,23 @@
|
|
|
167
181
|
"heading": "Launch Service",
|
|
168
182
|
"emptyState": "Launch Service page content coming soon."
|
|
169
183
|
},
|
|
184
|
+
"leadsInbox": {
|
|
185
|
+
"title": "Leads",
|
|
186
|
+
"description": "Every lead your site has captured, newest first.",
|
|
187
|
+
"forbiddenHeadline": "You don't have access",
|
|
188
|
+
"forbiddenDescription": "Sign in with the account that owns this site to see the leads it captured.",
|
|
189
|
+
"table": {
|
|
190
|
+
"caption": "Leads captured by your site",
|
|
191
|
+
"columnName": "Name",
|
|
192
|
+
"columnEmail": "Email",
|
|
193
|
+
"columnSource": "Source",
|
|
194
|
+
"columnCreated": "Captured",
|
|
195
|
+
"unavailable": "—",
|
|
196
|
+
"next": "Next page",
|
|
197
|
+
"emptyHeadline": "No leads yet",
|
|
198
|
+
"emptyDescription": "Leads captured by your site's forms will appear here."
|
|
199
|
+
}
|
|
200
|
+
},
|
|
170
201
|
"partners": {
|
|
171
202
|
"heading": "Partners",
|
|
172
203
|
"emptyState": "Partners listing coming soon."
|
|
@@ -187,10 +218,39 @@
|
|
|
187
218
|
"heading": "Projects",
|
|
188
219
|
"emptyState": "Projects listing coming soon."
|
|
189
220
|
},
|
|
221
|
+
"purchase": {
|
|
222
|
+
"success": {
|
|
223
|
+
"title": "Payment successful",
|
|
224
|
+
"message": "Thanks for your order — here's what you bought.",
|
|
225
|
+
"statusLabel": "Paid",
|
|
226
|
+
"sessionIdLabel": "Order",
|
|
227
|
+
"lineItem": "Qty {quantity} · {amount}",
|
|
228
|
+
"continueLabel": "Back to services",
|
|
229
|
+
"pendingHeadline": "We have your order",
|
|
230
|
+
"pendingBody": "Payment is still settling. This page will not update on its own — check your email for the receipt, or come back in a few minutes.",
|
|
231
|
+
"unknownHeadline": "We can't look up this order from here",
|
|
232
|
+
"unknownBody": "Check your email for the receipt from checkout — it has everything about your order.",
|
|
233
|
+
"ctaHeadline": "Keep going",
|
|
234
|
+
"ctaDescription": "Have a look at what else we offer.",
|
|
235
|
+
"ctaLabel": "Browse services"
|
|
236
|
+
},
|
|
237
|
+
"cancel": {
|
|
238
|
+
"title": "Checkout canceled",
|
|
239
|
+
"message": "Nothing was charged. Your card was not billed.",
|
|
240
|
+
"statusLabel": "Canceled",
|
|
241
|
+
"ctaHeadline": "Still interested?",
|
|
242
|
+
"ctaDescription": "Head back to the service menu whenever you're ready.",
|
|
243
|
+
"ctaLabel": "Back to services"
|
|
244
|
+
}
|
|
245
|
+
},
|
|
190
246
|
"resources": {
|
|
191
247
|
"heading": "Resources",
|
|
192
248
|
"emptyState": "Resources listing coming soon."
|
|
193
249
|
},
|
|
250
|
+
"returns": {
|
|
251
|
+
"heading": "Returns & Refunds",
|
|
252
|
+
"emptyState": "Returns and refunds content coming soon."
|
|
253
|
+
},
|
|
194
254
|
"schedule": {
|
|
195
255
|
"title": "Book a call",
|
|
196
256
|
"description": "Pick a time that works for you.",
|
|
@@ -213,6 +273,10 @@
|
|
|
213
273
|
"heading": "Services",
|
|
214
274
|
"emptyState": "Services listing coming soon."
|
|
215
275
|
},
|
|
276
|
+
"shipping": {
|
|
277
|
+
"heading": "Shipping Policy",
|
|
278
|
+
"emptyState": "Shipping policy content coming soon."
|
|
279
|
+
},
|
|
216
280
|
"software": {
|
|
217
281
|
"heading": "Software",
|
|
218
282
|
"description": "The @working-theory/* packages \u2014 typed tools for building AX-first products.",
|
|
@@ -369,6 +433,64 @@
|
|
|
369
433
|
"signInFailed": "We couldn't sign you in. Check your details and try again.",
|
|
370
434
|
"providerFailed": "We couldn't start sign-in with that provider. Try again."
|
|
371
435
|
},
|
|
436
|
+
"auth": {
|
|
437
|
+
"signUpTitle": "Create an account",
|
|
438
|
+
"signUpDescription": "Create an account on this site.",
|
|
439
|
+
"forgotTitle": "Reset your password",
|
|
440
|
+
"forgotDescription": "Request a password reset link.",
|
|
441
|
+
"resetTitle": "Choose a new password",
|
|
442
|
+
"resetDescription": "Set a new password for your account.",
|
|
443
|
+
"verifyEmailTitle": "Check your email",
|
|
444
|
+
"verifyEmailDescription": "Follow the link we sent to continue.",
|
|
445
|
+
"email": "Email address",
|
|
446
|
+
"password": "Password",
|
|
447
|
+
"confirmPassword": "Confirm password",
|
|
448
|
+
"newPassword": "New password",
|
|
449
|
+
"orContinue": "Or continue with",
|
|
450
|
+
"ssoPrefix": "Continue with",
|
|
451
|
+
"google": "Google",
|
|
452
|
+
"github": "GitHub",
|
|
453
|
+
"backToSignIn": "Back to sign in",
|
|
454
|
+
"signUpHeading": "Create your account",
|
|
455
|
+
"signUpSubhead": "Enter your details to get started.",
|
|
456
|
+
"signUpSubmit": "Create account",
|
|
457
|
+
"signUpFooterPrompt": "Already have an account?",
|
|
458
|
+
"signUpFooterLink": "Sign in",
|
|
459
|
+
"signUpNotConfiguredSubhead": "Sign-up is not configured for this site yet. Set a provider's environment variables to enable it.",
|
|
460
|
+
"signUpFailed": "We couldn't create your account. Check your details and try again.",
|
|
461
|
+
"providerFailed": "We couldn't start sign-up with that provider. Try again.",
|
|
462
|
+
"invitationHeading": "Accounts are by invitation",
|
|
463
|
+
"invitationSubhead": "This site does not offer public sign-up.",
|
|
464
|
+
"invitationBody": "If you were invited, open the link in your invitation email to create your account.",
|
|
465
|
+
"forgotHeading": "Reset your password",
|
|
466
|
+
"forgotSubhead": "Enter your email and we will send a reset link.",
|
|
467
|
+
"forgotSubmit": "Send reset link",
|
|
468
|
+
"resetHeading": "Choose a new password",
|
|
469
|
+
"resetSubhead": "Choose a new password for your account.",
|
|
470
|
+
"resetSubmit": "Set new password",
|
|
471
|
+
"forgotUnavailableHeading": "Password reset isn't available",
|
|
472
|
+
"forgotUnavailableSubhead": "This site does not offer password reset.",
|
|
473
|
+
"forgotUnavailableBody": "Sign in with one of the providers on the sign-in page, or ask the site owner for help getting back in.",
|
|
474
|
+
"resetUnavailableHeading": "Password reset isn't available",
|
|
475
|
+
"resetUnavailableSubhead": "This reset link cannot be used on this site.",
|
|
476
|
+
"resetUnavailableBody": "Password reset is not enabled here. Sign in with one of the providers on the sign-in page instead.",
|
|
477
|
+
"sentToPrefix": "We sent it to",
|
|
478
|
+
"resetRequestFailed": "We couldn't send a reset link just now. Try again in a few minutes.",
|
|
479
|
+
"resetFailed": "We couldn't set that password. The link may have expired \u2014 request a new one.",
|
|
480
|
+
"passwordMismatch": "Both passwords must match.",
|
|
481
|
+
"resetExpiredHeading": "This reset link has expired",
|
|
482
|
+
"resetExpiredSubhead": "Reset links are single-use and last one hour.",
|
|
483
|
+
"resetExpiredBody": "Request a new link from the sign-in page and follow the most recent email.",
|
|
484
|
+
"verifyExpiredHeading": "This confirmation link has expired",
|
|
485
|
+
"verifyExpiredSubhead": "Confirmation links last 24 hours.",
|
|
486
|
+
"verifyExpiredBody": "Sign in again and we'll send you a fresh confirmation email.",
|
|
487
|
+
"sentHeading": "Check your email",
|
|
488
|
+
"sentSubhead": "Follow the link we just sent to continue.",
|
|
489
|
+
"sentBody": "Check your inbox and follow the link to continue. You can close this tab once you're done.",
|
|
490
|
+
"footerPrivacy": "Privacy",
|
|
491
|
+
"footerTerms": "Terms",
|
|
492
|
+
"footerHelp": "Help"
|
|
493
|
+
},
|
|
372
494
|
"account": {
|
|
373
495
|
"title": "Your account",
|
|
374
496
|
"description": "Your profile, results, and purchases.",
|
|
@@ -406,9 +528,15 @@
|
|
|
406
528
|
"date": "Date",
|
|
407
529
|
"emptyHeadline": "No purchases yet",
|
|
408
530
|
"emptyDescription": "Purchases you complete will appear here."
|
|
531
|
+
},
|
|
532
|
+
"subscription": {
|
|
533
|
+
"headline": "Your payment didn't go through",
|
|
534
|
+
"descriptionPastDue": "Update your card to keep your subscription active.",
|
|
535
|
+
"descriptionCanceled": "Your subscription was canceled. Update your card by {date} to keep your access.",
|
|
536
|
+
"action": "Update payment method"
|
|
409
537
|
}
|
|
410
538
|
},
|
|
411
|
-
"
|
|
539
|
+
"admin": {
|
|
412
540
|
"title": "Workspace settings",
|
|
413
541
|
"description": "Your workspace name, site settings, and team.",
|
|
414
542
|
"nav": {
|
|
@@ -453,5 +581,91 @@
|
|
|
453
581
|
"emptyHeadline": "No members yet",
|
|
454
582
|
"emptyDescription": "People with access to this workspace will appear here."
|
|
455
583
|
}
|
|
584
|
+
},
|
|
585
|
+
"edit": {
|
|
586
|
+
"title": "Pages",
|
|
587
|
+
"description": "Edit your site's pages and publish changes without a deploy.",
|
|
588
|
+
"listHeading": "Pages",
|
|
589
|
+
"listDescription": "Every page on this site. Choose one to edit its content and publish your changes.",
|
|
590
|
+
"listEmptyHeadline": "No pages yet",
|
|
591
|
+
"listEmptyDescription": "Pages you create appear here, ready to edit and publish.",
|
|
592
|
+
"statusDraft": "Draft",
|
|
593
|
+
"statusPublished": "Published",
|
|
594
|
+
"statusPublishedWithDraft": "Published, with unpublished changes",
|
|
595
|
+
"licenceRequiredHeadline": "Content editing is a Pro feature",
|
|
596
|
+
"licenceRequiredDescription": "Editing pages without a deploy is part of Pro. Add a Pro licence to this site to turn it on.",
|
|
597
|
+
"notFoundHeadline": "Page not found",
|
|
598
|
+
"notFoundDescription": "There is no page at this address. It may have been renamed or removed.",
|
|
599
|
+
"editor": {
|
|
600
|
+
"tabForm": "Details",
|
|
601
|
+
"tabBody": "Body",
|
|
602
|
+
"tabPreview": "Preview",
|
|
603
|
+
"tabCode": "Code",
|
|
604
|
+
"statusDraft": "Draft",
|
|
605
|
+
"statusNotYetLive": "Not yet live",
|
|
606
|
+
"statusPublished": "Published",
|
|
607
|
+
"frontmatterHeading": "Page details",
|
|
608
|
+
"frontmatterTitle": "Title",
|
|
609
|
+
"frontmatterSlug": "Slug",
|
|
610
|
+
"frontmatterDescription": "Description",
|
|
611
|
+
"issuesHeading": "Fix these before publishing",
|
|
612
|
+
"saveButton": "Save draft",
|
|
613
|
+
"saving": "Saving\u2026",
|
|
614
|
+
"saved": "Saved",
|
|
615
|
+
"saveError": "Could not save. Try again.",
|
|
616
|
+
"publishButton": "Publish",
|
|
617
|
+
"publishing": "Publishing\u2026",
|
|
618
|
+
"published": "Published",
|
|
619
|
+
"publishError": "Could not publish. Try again.",
|
|
620
|
+
"unpublishButton": "Unpublish",
|
|
621
|
+
"unpublishing": "Unpublishing\u2026",
|
|
622
|
+
"unpublished": "Unpublished",
|
|
623
|
+
"unpublishError": "Could not unpublish. Try again.",
|
|
624
|
+
"conflictHeading": "Someone else saved this page",
|
|
625
|
+
"conflictMessage": "This page changed since you opened it. Reload to take their version, or overwrite it with yours.",
|
|
626
|
+
"conflictReload": "Reload their version",
|
|
627
|
+
"conflictOverwrite": "Overwrite with mine",
|
|
628
|
+
"imageInsertLabel": "Insert an image",
|
|
629
|
+
"imageInsertHint": "The image is uploaded and its markdown inserted at the cursor.",
|
|
630
|
+
"imageAlt": "Image",
|
|
631
|
+
"imageInsertError": "Could not upload that image. Try again.",
|
|
632
|
+
"codeHeading": "Composed MDX",
|
|
633
|
+
"diffLegendAdded": "Added",
|
|
634
|
+
"diffLegendRemoved": "Removed",
|
|
635
|
+
"diffLegendUnchanged": "Unchanged"
|
|
636
|
+
},
|
|
637
|
+
"sections": {
|
|
638
|
+
"heading": "Sections",
|
|
639
|
+
"arrayAdd": "Add",
|
|
640
|
+
"arrayRemove": "Remove",
|
|
641
|
+
"unsupportedField": "This field is edited as raw JSON",
|
|
642
|
+
"sectionLevelErrors": "Other problems with this section"
|
|
643
|
+
},
|
|
644
|
+
"body": {
|
|
645
|
+
"label": "Body",
|
|
646
|
+
"hint": "Markdown. Headings, links, lists and images all work.",
|
|
647
|
+
"machinePreambleNotice": "This page starts with imports or components. They are preserved and are not editable here."
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
"appointments": {
|
|
651
|
+
"title": "Appointments",
|
|
652
|
+
"description": "Your site's upcoming bookings, soonest first.",
|
|
653
|
+
"forbiddenHeadline": "You don't have access",
|
|
654
|
+
"forbiddenDescription": "Sign in with the account that owns this site to see its bookings.",
|
|
655
|
+
"table": {
|
|
656
|
+
"caption": "Upcoming bookings for your site",
|
|
657
|
+
"columnWhen": "When",
|
|
658
|
+
"columnWho": "Who",
|
|
659
|
+
"columnStatus": "Status",
|
|
660
|
+
"columnPaid": "Paid",
|
|
661
|
+
"statusPending": "Pending",
|
|
662
|
+
"statusConfirmed": "Confirmed",
|
|
663
|
+
"statusCancelled": "Cancelled",
|
|
664
|
+
"paidYes": "Paid",
|
|
665
|
+
"paidNo": "Unpaid",
|
|
666
|
+
"next": "Next page",
|
|
667
|
+
"emptyHeadline": "No upcoming bookings",
|
|
668
|
+
"emptyDescription": "When someone books a time with you, the appointment appears here automatically."
|
|
669
|
+
}
|
|
456
670
|
}
|
|
457
671
|
}
|
|
@@ -4,6 +4,7 @@ import { parse as parseYaml } from "yaml";
|
|
|
4
4
|
import bundleAnalyzer from "@next/bundle-analyzer";
|
|
5
5
|
import { withSentryConfig } from "@sentry/nextjs";
|
|
6
6
|
import createNextIntlPlugin from "next-intl/plugin";
|
|
7
|
+
import { legacyRedirects } from "@working-theory/templates/routes";
|
|
7
8
|
|
|
8
9
|
// @next/bundle-analyzer — enabled when ANALYZE=true (set by ci-bundle.yml).
|
|
9
10
|
// analyzerMode 'json' writes .next/analyze/client.json (and nodejs.json,
|
|
@@ -118,6 +119,10 @@ const nextConfig = {
|
|
|
118
119
|
"@working-theory/site-config",
|
|
119
120
|
"@working-theory/theme",
|
|
120
121
|
"@working-theory/ui",
|
|
122
|
+
"@working-theory/ui-commerce",
|
|
123
|
+
"@working-theory/ui-docs-blog",
|
|
124
|
+
"@working-theory/ui-scheduling",
|
|
125
|
+
"@working-theory/ui-signal-collectors",
|
|
121
126
|
"@working-theory/validation",
|
|
122
127
|
"@working-theory/web-i18n",
|
|
123
128
|
],
|
|
@@ -127,6 +132,14 @@ const nextConfig = {
|
|
|
127
132
|
// Marking better-auth as a server external prevents webpack from statically
|
|
128
133
|
// bundling it (and the unused kysely adapter) into the server chunk.
|
|
129
134
|
serverExternalPackages: ["better-auth"],
|
|
135
|
+
// Disable Next 16's auto-generated AGENTS.md / CLAUDE.md agent-rules
|
|
136
|
+
// block. Default true: `next dev`, on detecting an AI coding agent in
|
|
137
|
+
// the environment, upserts a managed `<!-- BEGIN:nextjs-agent-rules -->`
|
|
138
|
+
// block into apps/web/CLAUDE.md on every dev-server start (verified at
|
|
139
|
+
// node_modules/next/dist/server/lib/generate-agent-files.js). That
|
|
140
|
+
// mutates a tracked file as a side effect of running the dev server,
|
|
141
|
+
// which this scaffold does not want.
|
|
142
|
+
agentRules: false,
|
|
130
143
|
env: {
|
|
131
144
|
// Comma-separated locale list baked at build time — consumed by middleware
|
|
132
145
|
// and the sitemap route. NEXT_PUBLIC_ prefix makes it available in Edge
|
|
@@ -147,6 +160,13 @@ const nextConfig = {
|
|
|
147
160
|
},
|
|
148
161
|
];
|
|
149
162
|
},
|
|
163
|
+
// #5572 U2 (spec § D4 row 3) — a rename appends the old path to a row's
|
|
164
|
+
// `legacyRoutes` and this ships the 301 with no other edit here. Empty at
|
|
165
|
+
// HEAD: no row has moved yet. Proven against a FIXTURE, never the live map
|
|
166
|
+
// (apps/web/__tests__/routes/next-config-redirects.test.ts).
|
|
167
|
+
async redirects() {
|
|
168
|
+
return legacyRedirects();
|
|
169
|
+
},
|
|
150
170
|
};
|
|
151
171
|
|
|
152
172
|
// Sentry build-time plugin wrap (#894). When SENTRY_AUTH_TOKEN / SENTRY_ORG /
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
"description": "AI Launch Kit web — Next.js App Router UX surface (placeholder; MDX content adapter wires in B1).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"dev": "next dev",
|
|
8
|
+
"dev": "next dev --webpack",
|
|
9
9
|
"build": "next build --webpack",
|
|
10
10
|
"postbuild": "tsx scripts/assert-content-bundled.ts",
|
|
11
11
|
"start": "next start",
|
|
12
12
|
"type-check": "tsc --noEmit",
|
|
13
|
-
"lint": "
|
|
13
|
+
"lint": "eslint .",
|
|
14
14
|
"test": "jest",
|
|
15
15
|
"test:watch": "jest --watch"
|
|
16
16
|
},
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"@working-theory/api-client": "workspace:*",
|
|
22
22
|
"@working-theory/content-adapters": "workspace:*",
|
|
23
23
|
"@working-theory/database": "workspace:*",
|
|
24
|
+
"@working-theory/ids": "workspace:*",
|
|
24
25
|
"@working-theory/jsonld": "workspace:*",
|
|
26
|
+
"@working-theory/license": "workspace:*",
|
|
25
27
|
"@working-theory/metadata": "workspace:*",
|
|
26
28
|
"@working-theory/page-renderer": "workspace:*",
|
|
27
29
|
"@working-theory/schema": "workspace:*",
|
|
@@ -60,7 +62,10 @@
|
|
|
60
62
|
"tailwindcss": "^4.3.2",
|
|
61
63
|
"ts-jest": "^29.4.11",
|
|
62
64
|
"typescript": "^6.0.3",
|
|
63
|
-
"
|
|
65
|
+
"eslint": "^10.6.0",
|
|
66
|
+
"@eslint/js": "^10.0.1",
|
|
67
|
+
"globals": "^17.7.0",
|
|
68
|
+
"typescript-eslint": "^8.62.1",
|
|
64
69
|
"@working-theory/sections-registry": "workspace:*"
|
|
65
70
|
}
|
|
66
71
|
}
|
|
@@ -13,6 +13,80 @@
|
|
|
13
13
|
|
|
14
14
|
import * as Sentry from "@sentry/nextjs";
|
|
15
15
|
|
|
16
|
+
import { scrubTelemetryUrl } from "./lib/telemetry-scrub";
|
|
17
|
+
|
|
18
|
+
// #5613 / security review PR #5639: the report-grant token (?g=<id> on
|
|
19
|
+
// /reports/<slug>, #5562) is a bearer credential for a private customer
|
|
20
|
+
// deliverable and must never leave this app in a URL. Scrub it from every
|
|
21
|
+
// error event and transaction before it reaches Sentry — the request URL,
|
|
22
|
+
// its Referer header, the transaction name, navigation breadcrumbs, and any
|
|
23
|
+
// URL captured as span/trace data (e.g. `url.full`,
|
|
24
|
+
// `http.request.header.referer`).
|
|
25
|
+
function scrubRequestUrlAndHeaders(request?: {
|
|
26
|
+
url?: string;
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
}): void {
|
|
29
|
+
if (!request) return;
|
|
30
|
+
if (request.url) {
|
|
31
|
+
request.url = scrubTelemetryUrl(request.url);
|
|
32
|
+
}
|
|
33
|
+
if (request.headers) {
|
|
34
|
+
for (const key of ["Referer", "referer"]) {
|
|
35
|
+
const value = request.headers[key];
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
request.headers[key] = scrubTelemetryUrl(value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function scrubSpanData(data?: Record<string, unknown>): void {
|
|
44
|
+
if (!data) return;
|
|
45
|
+
for (const key of ["url.full", "http.url", "http.request.header.referer"]) {
|
|
46
|
+
const value = data[key];
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
data[key] = scrubTelemetryUrl(value);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function scrubSentryEvent<
|
|
54
|
+
T extends {
|
|
55
|
+
request?: { url?: string; headers?: Record<string, string> };
|
|
56
|
+
transaction?: string;
|
|
57
|
+
breadcrumbs?: { category?: string; data?: Record<string, unknown> }[];
|
|
58
|
+
contexts?: { trace?: { data?: Record<string, unknown> } };
|
|
59
|
+
spans?: { data?: Record<string, unknown> }[];
|
|
60
|
+
},
|
|
61
|
+
>(event: T): T {
|
|
62
|
+
scrubRequestUrlAndHeaders(event.request);
|
|
63
|
+
if (event.transaction) {
|
|
64
|
+
event.transaction = scrubTelemetryUrl(event.transaction);
|
|
65
|
+
}
|
|
66
|
+
for (const crumb of event.breadcrumbs ?? []) {
|
|
67
|
+
if (!crumb.data) continue;
|
|
68
|
+
if (crumb.category === "navigation") {
|
|
69
|
+
for (const key of ["to", "from"]) {
|
|
70
|
+
const value = crumb.data[key];
|
|
71
|
+
if (typeof value === "string") {
|
|
72
|
+
crumb.data[key] = scrubTelemetryUrl(value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// fetch/xhr breadcrumbs (and others) can carry `data.url` independent
|
|
77
|
+
// of category — scrub it regardless (security review, PR #5639).
|
|
78
|
+
const url = crumb.data["url"];
|
|
79
|
+
if (typeof url === "string") {
|
|
80
|
+
crumb.data["url"] = scrubTelemetryUrl(url);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
scrubSpanData(event.contexts?.trace?.data);
|
|
84
|
+
for (const span of event.spans ?? []) {
|
|
85
|
+
scrubSpanData(span.data);
|
|
86
|
+
}
|
|
87
|
+
return event;
|
|
88
|
+
}
|
|
89
|
+
|
|
16
90
|
Sentry.init({
|
|
17
91
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
18
92
|
enabled: !!process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -24,4 +98,61 @@ Sentry.init({
|
|
|
24
98
|
// Session replays: 10% of all sessions, 100% of sessions that hit an error.
|
|
25
99
|
replaysSessionSampleRate: 0.1,
|
|
26
100
|
replaysOnErrorSampleRate: 1.0,
|
|
101
|
+
|
|
102
|
+
beforeSend: scrubSentryEvent,
|
|
103
|
+
beforeSendTransaction: scrubSentryEvent,
|
|
104
|
+
|
|
105
|
+
integrations: [
|
|
106
|
+
Sentry.replayIntegration({
|
|
107
|
+
// Custom recording events (navigation/history frames) can be scrubbed
|
|
108
|
+
// here. Events added by the underlying DOM recording library (rrweb) —
|
|
109
|
+
// notably the initial page-load snapshot's href — can NOT be modified
|
|
110
|
+
// via this or any other documented option in @sentry/replay 10.58.0:
|
|
111
|
+
// checked ReplayPluginOptions, BeforeAddRecordingEvent, and the core
|
|
112
|
+
// Options' beforeSend/beforeSendTransaction. That snapshot href is a
|
|
113
|
+
// residual, called out in the PR body.
|
|
114
|
+
beforeAddRecordingEvent(event) {
|
|
115
|
+
const { payload } = event.data;
|
|
116
|
+
if (
|
|
117
|
+
"description" in payload &&
|
|
118
|
+
typeof payload.description === "string"
|
|
119
|
+
) {
|
|
120
|
+
payload.description = scrubTelemetryUrl(payload.description);
|
|
121
|
+
}
|
|
122
|
+
const data = "data" in payload ? payload.data : undefined;
|
|
123
|
+
if (data && typeof data === "object") {
|
|
124
|
+
const record = data as Record<string, unknown>;
|
|
125
|
+
// "url" covers click/slowClick/multiClick frames' `data.url`
|
|
126
|
+
// (security review, PR #5639), alongside history/navigation
|
|
127
|
+
// frames' `previous`/`to`/`from`.
|
|
128
|
+
for (const key of ["previous", "to", "from", "url"] as const) {
|
|
129
|
+
const value = record[key];
|
|
130
|
+
if (typeof value === "string") {
|
|
131
|
+
record[key] = scrubTelemetryUrl(value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return event;
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// beforeSend/beforeSendTransaction never see the replay envelope — @sentry/
|
|
142
|
+
// replay builds and transports it directly. It still passes through
|
|
143
|
+
// `client.getEventProcessors()` (verified in @sentry/core's prepareEvent),
|
|
144
|
+
// so this is the one hook that reaches it: the session's visited-URLs list
|
|
145
|
+
// and the request Referer it carries (security review, PR #5639).
|
|
146
|
+
Sentry.addEventProcessor((event) => {
|
|
147
|
+
const replayEvent = event as typeof event & { urls?: unknown };
|
|
148
|
+
if (replayEvent.type !== "replay_event") {
|
|
149
|
+
return event;
|
|
150
|
+
}
|
|
151
|
+
if (Array.isArray(replayEvent.urls)) {
|
|
152
|
+
replayEvent.urls = replayEvent.urls.map((url) =>
|
|
153
|
+
typeof url === "string" ? scrubTelemetryUrl(url) : url,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
scrubRequestUrlAndHeaders(event.request);
|
|
157
|
+
return event;
|
|
27
158
|
});
|
|
@@ -7,9 +7,81 @@
|
|
|
7
7
|
|
|
8
8
|
import * as Sentry from "@sentry/nextjs";
|
|
9
9
|
|
|
10
|
+
import { scrubTelemetryUrl } from "./lib/telemetry-scrub";
|
|
11
|
+
|
|
12
|
+
// #5613 / security review PR #5639: the report-grant token (?g=<id> on
|
|
13
|
+
// /reports/<slug>, #5562) is a bearer credential for a private customer
|
|
14
|
+
// deliverable and must never leave this app in a URL. The RSC render of the
|
|
15
|
+
// grant page can run in this runtime too, so scrub the request URL, its
|
|
16
|
+
// Referer header, the transaction name, navigation breadcrumbs, and any URL
|
|
17
|
+
// captured as span/trace data (e.g. `url.full`,
|
|
18
|
+
// `http.request.header.referer`) here as well.
|
|
19
|
+
function scrubSentryEvent<
|
|
20
|
+
T extends {
|
|
21
|
+
request?: { url?: string; headers?: Record<string, string> };
|
|
22
|
+
transaction?: string;
|
|
23
|
+
breadcrumbs?: { category?: string; data?: Record<string, unknown> }[];
|
|
24
|
+
contexts?: { trace?: { data?: Record<string, unknown> } };
|
|
25
|
+
spans?: { data?: Record<string, unknown> }[];
|
|
26
|
+
},
|
|
27
|
+
>(event: T): T {
|
|
28
|
+
if (event.request?.url) {
|
|
29
|
+
event.request.url = scrubTelemetryUrl(event.request.url);
|
|
30
|
+
}
|
|
31
|
+
if (event.request?.headers) {
|
|
32
|
+
for (const key of ["Referer", "referer"]) {
|
|
33
|
+
const value = event.request.headers[key];
|
|
34
|
+
if (typeof value === "string") {
|
|
35
|
+
event.request.headers[key] = scrubTelemetryUrl(value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (event.transaction) {
|
|
40
|
+
event.transaction = scrubTelemetryUrl(event.transaction);
|
|
41
|
+
}
|
|
42
|
+
for (const crumb of event.breadcrumbs ?? []) {
|
|
43
|
+
if (!crumb.data) continue;
|
|
44
|
+
if (crumb.category === "navigation") {
|
|
45
|
+
for (const key of ["to", "from"]) {
|
|
46
|
+
const value = crumb.data[key];
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
crumb.data[key] = scrubTelemetryUrl(value);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// fetch/xhr breadcrumbs (and others) can carry `data.url` independent
|
|
53
|
+
// of category — scrub it regardless (security review, PR #5639).
|
|
54
|
+
const url = crumb.data["url"];
|
|
55
|
+
if (typeof url === "string") {
|
|
56
|
+
crumb.data["url"] = scrubTelemetryUrl(url);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const scrubSpanData = (data?: Record<string, unknown>): void => {
|
|
60
|
+
if (!data) return;
|
|
61
|
+
for (const key of [
|
|
62
|
+
"url.full",
|
|
63
|
+
"http.url",
|
|
64
|
+
"http.request.header.referer",
|
|
65
|
+
]) {
|
|
66
|
+
const value = data[key];
|
|
67
|
+
if (typeof value === "string") {
|
|
68
|
+
data[key] = scrubTelemetryUrl(value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
scrubSpanData(event.contexts?.trace?.data);
|
|
73
|
+
for (const span of event.spans ?? []) {
|
|
74
|
+
scrubSpanData(span.data);
|
|
75
|
+
}
|
|
76
|
+
return event;
|
|
77
|
+
}
|
|
78
|
+
|
|
10
79
|
Sentry.init({
|
|
11
80
|
dsn: process.env.SENTRY_DSN,
|
|
12
81
|
enabled: !!process.env.SENTRY_DSN,
|
|
13
82
|
|
|
14
83
|
tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 0.1,
|
|
84
|
+
|
|
85
|
+
beforeSend: scrubSentryEvent,
|
|
86
|
+
beforeSendTransaction: scrubSentryEvent,
|
|
15
87
|
});
|
|
@@ -12,9 +12,81 @@
|
|
|
12
12
|
|
|
13
13
|
import * as Sentry from "@sentry/nextjs";
|
|
14
14
|
|
|
15
|
+
import { scrubTelemetryUrl } from "./lib/telemetry-scrub";
|
|
16
|
+
|
|
17
|
+
// #5613 / security review PR #5639: the report-grant token (?g=<id> on
|
|
18
|
+
// /reports/<slug>, #5562) is a bearer credential for a private customer
|
|
19
|
+
// deliverable and must never leave this app in a URL. The RSC render of the
|
|
20
|
+
// grant page runs in this runtime, so scrub the request URL, its Referer
|
|
21
|
+
// header, the transaction name, navigation breadcrumbs, and any URL
|
|
22
|
+
// captured as span/trace data (e.g. `url.full`,
|
|
23
|
+
// `http.request.header.referer`) here too.
|
|
24
|
+
function scrubSentryEvent<
|
|
25
|
+
T extends {
|
|
26
|
+
request?: { url?: string; headers?: Record<string, string> };
|
|
27
|
+
transaction?: string;
|
|
28
|
+
breadcrumbs?: { category?: string; data?: Record<string, unknown> }[];
|
|
29
|
+
contexts?: { trace?: { data?: Record<string, unknown> } };
|
|
30
|
+
spans?: { data?: Record<string, unknown> }[];
|
|
31
|
+
},
|
|
32
|
+
>(event: T): T {
|
|
33
|
+
if (event.request?.url) {
|
|
34
|
+
event.request.url = scrubTelemetryUrl(event.request.url);
|
|
35
|
+
}
|
|
36
|
+
if (event.request?.headers) {
|
|
37
|
+
for (const key of ["Referer", "referer"]) {
|
|
38
|
+
const value = event.request.headers[key];
|
|
39
|
+
if (typeof value === "string") {
|
|
40
|
+
event.request.headers[key] = scrubTelemetryUrl(value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (event.transaction) {
|
|
45
|
+
event.transaction = scrubTelemetryUrl(event.transaction);
|
|
46
|
+
}
|
|
47
|
+
for (const crumb of event.breadcrumbs ?? []) {
|
|
48
|
+
if (!crumb.data) continue;
|
|
49
|
+
if (crumb.category === "navigation") {
|
|
50
|
+
for (const key of ["to", "from"]) {
|
|
51
|
+
const value = crumb.data[key];
|
|
52
|
+
if (typeof value === "string") {
|
|
53
|
+
crumb.data[key] = scrubTelemetryUrl(value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// fetch/xhr breadcrumbs (and others) can carry `data.url` independent
|
|
58
|
+
// of category — scrub it regardless (security review, PR #5639).
|
|
59
|
+
const url = crumb.data["url"];
|
|
60
|
+
if (typeof url === "string") {
|
|
61
|
+
crumb.data["url"] = scrubTelemetryUrl(url);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const scrubSpanData = (data?: Record<string, unknown>): void => {
|
|
65
|
+
if (!data) return;
|
|
66
|
+
for (const key of [
|
|
67
|
+
"url.full",
|
|
68
|
+
"http.url",
|
|
69
|
+
"http.request.header.referer",
|
|
70
|
+
]) {
|
|
71
|
+
const value = data[key];
|
|
72
|
+
if (typeof value === "string") {
|
|
73
|
+
data[key] = scrubTelemetryUrl(value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
scrubSpanData(event.contexts?.trace?.data);
|
|
78
|
+
for (const span of event.spans ?? []) {
|
|
79
|
+
scrubSpanData(span.data);
|
|
80
|
+
}
|
|
81
|
+
return event;
|
|
82
|
+
}
|
|
83
|
+
|
|
15
84
|
Sentry.init({
|
|
16
85
|
dsn: process.env.SENTRY_DSN,
|
|
17
86
|
enabled: !!process.env.SENTRY_DSN,
|
|
18
87
|
|
|
19
88
|
tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 0.1,
|
|
89
|
+
|
|
90
|
+
beforeSend: scrubSentryEvent,
|
|
91
|
+
beforeSendTransaction: scrubSentryEvent,
|
|
20
92
|
});
|