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
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* `architecture.yaml` template files — a fixed template IS the drift this
|
|
22
22
|
* removes.
|
|
23
23
|
*/
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
24
|
+
import { sep } from "node:path";
|
|
25
|
+
import { importClosure } from "./lib/import-graph.js";
|
|
26
26
|
import { PAID_MODULES } from "./lib/module-tier.js";
|
|
27
27
|
import { RECOGNIZED_MODULES } from "./parse-args.js";
|
|
28
28
|
/**
|
|
@@ -124,6 +124,31 @@ export const ARCHITECTURE_BASE = {
|
|
|
124
124
|
},
|
|
125
125
|
],
|
|
126
126
|
};
|
|
127
|
+
/**
|
|
128
|
+
* The workspace asset store (#5854), CO-OWNED by the `workspace` and
|
|
129
|
+
* `multi-tenant` slices.
|
|
130
|
+
*
|
|
131
|
+
* `server.ts` registers both of its routes under
|
|
132
|
+
* `isModuleEnabled("workspace") || isModuleEnabled("multi-tenant")`, and a file
|
|
133
|
+
* behind a two-module disjunction must be deliverable by BOTH bundles — or
|
|
134
|
+
* whichever module lacks it throws ERR_MODULE_NOT_FOUND during `build()`. One
|
|
135
|
+
* array spread into both `ownedFiles` lists makes the two copies incapable of
|
|
136
|
+
* drifting, which matters because a drift only surfaces in a scaffolded
|
|
137
|
+
* customer repo rather than here.
|
|
138
|
+
*
|
|
139
|
+
* `routes/assets/index.ts` is listed although it registers nothing: the
|
|
140
|
+
* template-exclusion closure runs over IMPORTERS, so a shared-constants module
|
|
141
|
+
* that is imported BY the routes and imports neither of them is never reached
|
|
142
|
+
* from them, and an unlisted one would ship into the keyless Free starter.
|
|
143
|
+
*/
|
|
144
|
+
const ASSET_STORE_FILES = [
|
|
145
|
+
"apps/api/src/routes/assets/index.ts",
|
|
146
|
+
"apps/api/src/routes/assets/upload.ts",
|
|
147
|
+
"apps/api/src/routes/assets/read.ts",
|
|
148
|
+
// The manage routes — list, PATCH, DELETE (#6093 D16).
|
|
149
|
+
"apps/api/src/routes/assets/manage.ts",
|
|
150
|
+
"apps/api/src/lib/asset-store.ts",
|
|
151
|
+
];
|
|
127
152
|
/**
|
|
128
153
|
* The per-module slices. Authored for every `RECOGNIZED_MODULES` value; only
|
|
129
154
|
* `marketing` (the default) is validated end-to-end against a golden.
|
|
@@ -246,6 +271,11 @@ export const MODULE_SLICES = {
|
|
|
246
271
|
// The Fumadocs source pair — both whole, both loaders (D3).
|
|
247
272
|
"apps/web/source.config.ts",
|
|
248
273
|
"apps/web/lib/source.ts",
|
|
274
|
+
// The runtime source `lib/source.ts` resolves to under
|
|
275
|
+
// CONTENT_ADAPTER=database (#5878). Listed explicitly: the exclusion
|
|
276
|
+
// closure grows over DEPENDENTS, not dependencies, so being imported by
|
|
277
|
+
// `lib/source.ts` does not pull this file into the bundle by itself.
|
|
278
|
+
"apps/web/lib/runtime-source.ts",
|
|
249
279
|
// The route adapters and the jest stub for the codegen output.
|
|
250
280
|
"apps/web/lib/blog-list-data.ts",
|
|
251
281
|
"apps/web/lib/blog-post-data.ts",
|
|
@@ -253,39 +283,46 @@ export const MODULE_SLICES = {
|
|
|
253
283
|
// The module's own /llms.txt variant; the bundle installs it onto
|
|
254
284
|
// app/llms.txt/route.ts (#5365 D9, install-path mapping owned by #5373).
|
|
255
285
|
"apps/web/lib/slices/docs-blog/llms-route.ts",
|
|
256
|
-
// The two shells and the six components
|
|
257
|
-
//
|
|
258
|
-
|
|
259
|
-
"packages/templates/src/shells/DocsShell.tsx",
|
|
260
|
-
"packages/templates/src/shells/slices/docs-blog.ts",
|
|
261
|
-
"packages/ui/src/blocks/DocsActionBar.tsx",
|
|
262
|
-
"packages/ui/src/blocks/DocsArticleHeader.tsx",
|
|
263
|
-
"packages/ui/src/blocks/DocsFeedback.tsx",
|
|
264
|
-
"packages/ui/src/blocks/DocsSearch.tsx",
|
|
265
|
-
"packages/ui/src/blocks/DocsTocButton.tsx",
|
|
266
|
-
"packages/ui/src/chrome/DocsSidebar.tsx",
|
|
267
|
-
"packages/ui/src/chrome/slices/docs-blog.ts",
|
|
286
|
+
// The two shells and the six components moved to packages-paid/ui-docs-blog
|
|
287
|
+
// (#5581) — that package is a physical part of the tree, not a listed
|
|
288
|
+
// ownedFiles entry, and is installed via this slice's `patches` block below.
|
|
268
289
|
],
|
|
269
290
|
// pageContributions (spec 5478; parent § D6 shape 1) — the two route
|
|
270
291
|
// surfaces this module mounts, each with the seed MDX it renders. The
|
|
271
|
-
//
|
|
292
|
+
// nine MDX files are exactly the nine on the tree and cannot come from
|
|
272
293
|
// the `templates/` snapshot: `apps/web/content` is in build-templates.mjs's
|
|
273
294
|
// EXCLUDE_TEMPLATE_DIRS and `template-overlay/` carries no blog or docs
|
|
274
295
|
// stub. They ride this module's own bundle, consistent with the route
|
|
275
|
-
// files above
|
|
276
|
-
//
|
|
277
|
-
//
|
|
296
|
+
// files above: `collectModuleFiles` in build-module-bundles.mjs stages
|
|
297
|
+
// every `pageContributions[].content` entry alongside `ownedFiles` and
|
|
298
|
+
// the `installMap` keys, and `copyTree` lands each at this same path.
|
|
299
|
+
//
|
|
300
|
+
// #5618 D6.2 — the module OWNS its sample content (Rule B): the blog
|
|
301
|
+
// listing, four sample posts and the three docs pages moved here out of
|
|
302
|
+
// `site-templates/marketing-site/`, so any template requiring docs-blog
|
|
303
|
+
// gets the samples and a keyed `--modules docs-blog` scaffold with no
|
|
304
|
+
// template lands them too. `launching-ailk.mdx` stays the module's fifth
|
|
305
|
+
// seed post; the Pro template maps its own post 05 ONTO that path as a
|
|
306
|
+
// copy override (D6.2a — spec § 7 finding 9 carries the seed's fate).
|
|
278
307
|
pageContributions: [
|
|
279
308
|
{
|
|
280
309
|
route: "/blog",
|
|
281
310
|
content: [
|
|
282
311
|
"apps/web/content/en/blog/index.mdx",
|
|
312
|
+
"apps/web/content/en/blog/01-8-things-that-prove-coding-skills-are-directly-linked-to-successfully-assembling-ikea-furniture.mdx",
|
|
313
|
+
"apps/web/content/en/blog/02-5-ways-to-guarantee-your-startup-goes-nowhere-fast.mdx",
|
|
314
|
+
"apps/web/content/en/blog/03-10-ideas-that-will-guarantee-1000x-growth.mdx",
|
|
315
|
+
"apps/web/content/en/blog/04-7-keys-to-saas-success-the-elite-doesnt-want-you-to-know.mdx",
|
|
283
316
|
"apps/web/content/en/blog/launching-ailk.mdx",
|
|
284
317
|
],
|
|
285
318
|
},
|
|
286
319
|
{
|
|
287
320
|
route: "/docs",
|
|
288
|
-
content: [
|
|
321
|
+
content: [
|
|
322
|
+
"apps/web/content/en/docs/getting-started.mdx",
|
|
323
|
+
"apps/web/content/en/docs/configure.mdx",
|
|
324
|
+
"apps/web/content/en/docs/deploy.mdx",
|
|
325
|
+
],
|
|
289
326
|
},
|
|
290
327
|
],
|
|
291
328
|
// patches (spec 5418 § 3 D1, Group G) — every Group G row that edits a
|
|
@@ -330,6 +367,8 @@ export const MODULE_SLICES = {
|
|
|
330
367
|
"fumadocs-core": "^16.10.4",
|
|
331
368
|
"fumadocs-mdx": "^15.0.12",
|
|
332
369
|
"@working-theory/fumadocs-schema": "workspace:*",
|
|
370
|
+
// #5581 — the docs-blog module's paid component package (D5).
|
|
371
|
+
"@working-theory/ui-docs-blog": "workspace:*",
|
|
333
372
|
},
|
|
334
373
|
},
|
|
335
374
|
{
|
|
@@ -396,13 +435,13 @@ export const MODULE_SLICES = {
|
|
|
396
435
|
//
|
|
397
436
|
// The FEAT-042 Organization → Workspace → Membership tenancy layer:
|
|
398
437
|
// schema (auth/content namespaces) + workspace-scoped API (apps/api) +
|
|
399
|
-
// the authed
|
|
438
|
+
// the authed Admin app surface (apps/admin). Single-tenant sites
|
|
400
439
|
// (module absent) ship none of this — same base apps/web, fixed scope.
|
|
401
440
|
"multi-tenant": {
|
|
402
441
|
apps: {
|
|
403
|
-
|
|
404
|
-
path: "apps/
|
|
405
|
-
description: "Next.js — authed
|
|
442
|
+
admin: {
|
|
443
|
+
path: "apps/admin",
|
|
444
|
+
description: "Next.js — authed Admin app (Organization → Workspace → Membership). Hosts the organization-plugin Better Auth handlers; imports the database only via lib/prisma-for-auth.ts (auth-adapter exception); all domain data via apps/api's workspace-scoped routes over HTTP.",
|
|
406
445
|
may_import_from: [
|
|
407
446
|
"database",
|
|
408
447
|
"packages/templates",
|
|
@@ -411,10 +450,10 @@ export const MODULE_SLICES = {
|
|
|
411
450
|
"packages/validation",
|
|
412
451
|
// The `workspace` module's shared settings components (#5371 req. 6)
|
|
413
452
|
// — the scaffolded-site twin of the root architecture.yaml grant on
|
|
414
|
-
// `apps_paid.
|
|
453
|
+
// `apps_paid.admin`. Pro Plus inherits Pro's module set, so a
|
|
415
454
|
// saas-product scaffold carries both modules and this app composes
|
|
416
455
|
// the identical panels apps/web does, with no forked copy.
|
|
417
|
-
"packages/
|
|
456
|
+
"packages/admin-ui",
|
|
418
457
|
],
|
|
419
458
|
may_not_import_from: [
|
|
420
459
|
"apps/api",
|
|
@@ -486,12 +525,12 @@ export const MODULE_SLICES = {
|
|
|
486
525
|
description: "Stripe SDK wrapper + webhook signature verification",
|
|
487
526
|
may_import_from: ["packages/validation"],
|
|
488
527
|
},
|
|
489
|
-
// apps/
|
|
528
|
+
// apps/admin presentation deps. templates is net-new here; theme/ui/
|
|
490
529
|
// validation duplicate the marketing slice's definitions VERBATIM so the
|
|
491
530
|
// Object.assign merge in deriveArchitecture is order-independent (a
|
|
492
531
|
// multi-tenant-only selection stays self-consistent).
|
|
493
532
|
templates: {
|
|
494
|
-
description: "Shell/Chrome composition — AppShell (tier-5 shell);
|
|
533
|
+
description: "Shell/Chrome composition — AppShell (tier-5 shell); AdminShell + ArtifactEditorShell ship inside this module itself, not the public package (D-45)",
|
|
495
534
|
may_import_from: ["packages/theme", "packages/ui", "packages/validation"],
|
|
496
535
|
},
|
|
497
536
|
theme: {
|
|
@@ -553,11 +592,12 @@ export const MODULE_SLICES = {
|
|
|
553
592
|
// ownedFiles (S1, #5088). Verified against the current filesystem and
|
|
554
593
|
// server.ts's module-conditional registration (isModuleEnabled('multi-tenant')).
|
|
555
594
|
//
|
|
556
|
-
// apps-paid/
|
|
595
|
+
// apps-paid/admin/** is a single glob — the whole app (43 files as of
|
|
557
596
|
// this pass, excluding __tests__/node_modules), just moved here from
|
|
558
|
-
// apps/workspace by a parallel workstream on this same branch.
|
|
559
|
-
//
|
|
560
|
-
//
|
|
597
|
+
// apps/workspace by a parallel workstream on this same branch. Later
|
|
598
|
+
// renamed in place from its former Workspace-prefixed directory name by
|
|
599
|
+
// #5637, the Admin-vocabulary rename. Unlike every other entry below,
|
|
600
|
+
// this one is intentionally a glob, not an enumeration.
|
|
561
601
|
//
|
|
562
602
|
// apps/api/src/routes/project-listings/ is MIXED (free anonymous surface
|
|
563
603
|
// + tenant dashboard sharing one directory) — only the tenant-guarded
|
|
@@ -646,6 +686,11 @@ export const MODULE_SLICES = {
|
|
|
646
686
|
"apps/api/src/routes/workspaces/index.ts",
|
|
647
687
|
"apps/api/src/routes/workspaces/sessions.ts",
|
|
648
688
|
"apps/api/src/routes/workspaces/config.ts",
|
|
689
|
+
// Co-owned with `workspace` (#5853): the content-write scope is gated on
|
|
690
|
+
// content-write AND (workspace || multi-tenant) and this file imports
|
|
691
|
+
// lib/tenant-db.ts, so each tenancy slice must deliver it.
|
|
692
|
+
"apps/api/src/routes/workspaces/content.ts",
|
|
693
|
+
...ASSET_STORE_FILES,
|
|
649
694
|
"apps/api/src/routes/billing/index.ts",
|
|
650
695
|
"apps/api/src/routes/billing/portal.ts",
|
|
651
696
|
"apps/api/src/routes/billing/read.ts",
|
|
@@ -662,8 +707,42 @@ export const MODULE_SLICES = {
|
|
|
662
707
|
"apps/api/src/middleware/tenant.ts",
|
|
663
708
|
"apps/api/src/services/tenant-context.ts",
|
|
664
709
|
"apps/api/src/services/waitlist-dashboard.ts",
|
|
710
|
+
// #6258 — the file waitlist-dashboard.ts imports for the pinned
|
|
711
|
+
// platform-operator read scope. It rides BOTH slices for the same
|
|
712
|
+
// reason its importer does: an unlisted import target breaks a
|
|
713
|
+
// signal-collectors-without-multi-tenant scaffold at build() time.
|
|
714
|
+
"apps/api/src/services/waitlist-operator-reads.ts",
|
|
715
|
+
// #6204/#6280 CI fix — `listUnhandledMessages`/`markMessageHandled`
|
|
716
|
+
// (the "Needs-you" message read/write over `tenantDb(tenant).leads`)
|
|
717
|
+
// moved here off `services/leads-inbox.ts`, a BASE-tier file every
|
|
718
|
+
// scaffold ships. Importing `lib/tenant-db.ts` from that base file
|
|
719
|
+
// walked `paidModuleTemplateExclusions()`'s companion closure
|
|
720
|
+
// (`lib/import-graph.ts`) BACKWARD into `leads-inbox.ts` itself and
|
|
721
|
+
// then into every one of `apps/api/src/{server,cli,index,
|
|
722
|
+
// vercel-handler}.ts` — all of which reach it through
|
|
723
|
+
// `routes/leads/list.ts` — dropping them from a keyless scaffold
|
|
724
|
+
// (`__tests__/paid-module-exclusions.test.ts`'s `MUST_SHIP` guard,
|
|
725
|
+
// #5678's cascade shape recurring a third time).
|
|
726
|
+
//
|
|
727
|
+
// #6216 — now reached: `routes/workspaces/messages.ts` (below)
|
|
728
|
+
// consumes `getMessage` alongside the two functions above. That route
|
|
729
|
+
// registers under `isModuleEnabled("workspace") ||
|
|
730
|
+
// isModuleEnabled("multi-tenant")` — the SAME gate
|
|
731
|
+
// `workspaces/general.ts`/`members.ts` register under, NOT the
|
|
732
|
+
// multi-tenant-only family `workspaces/meetings.ts`/`config.ts` sit
|
|
733
|
+
// in — so this file and `routes/workspaces/messages.ts` are now
|
|
734
|
+
// CO-OWNED with `workspace` too (see that slice's entry below), the
|
|
735
|
+
// asset-store precedent: a file behind an OR gate must be
|
|
736
|
+
// deliverable by BOTH bundles.
|
|
737
|
+
"apps/api/src/services/inbox-messages.ts",
|
|
738
|
+
"apps/api/src/routes/workspaces/messages.ts",
|
|
665
739
|
"apps/api/src/lib/tenant-db.ts",
|
|
666
740
|
"apps/api/src/lib/ws-token.ts",
|
|
741
|
+
// #6157 D16 — the magnet Admin authoring surface, co-owned with
|
|
742
|
+
// `signal-collectors` below for the SAME reason #5677 co-owns the
|
|
743
|
+
// review surface under both: its scope is registered under the
|
|
744
|
+
// widened `multi-tenant || signal-collectors` gate.
|
|
745
|
+
"apps/api/src/routes/magnets/index.ts",
|
|
667
746
|
"apps/web/app/[locale]/(authed)/waitlist/page.tsx",
|
|
668
747
|
"apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx",
|
|
669
748
|
"apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx",
|
|
@@ -674,15 +753,36 @@ export const MODULE_SLICES = {
|
|
|
674
753
|
"apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx",
|
|
675
754
|
"apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx",
|
|
676
755
|
"apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx",
|
|
677
|
-
"apps-paid/
|
|
756
|
+
"apps-paid/admin/**",
|
|
678
757
|
],
|
|
758
|
+
// The whole-app glob above lands its files at their REPO-relative path
|
|
759
|
+
// unless something re-roots them (`installBundleTree`'s `copyTree`
|
|
760
|
+
// excludes only `installMap` KEYS from its verbatim copy), so without a
|
|
761
|
+
// rename rule a keyed install left a stray source-tree-relative
|
|
762
|
+
// directory in the scaffold instead of the working `apps/admin` app
|
|
763
|
+
// this slice's own `apps.admin.path` (and `paid-paths.ts`'s
|
|
764
|
+
// `introducedAppPaths()`) already declares (#5626 D3/D4). The fix lives
|
|
765
|
+
// here, on the module, so `--modules multi-tenant` alone is fixed too —
|
|
766
|
+
// never as a per-template workaround.
|
|
767
|
+
//
|
|
768
|
+
// `installRoot`, not a literal `installMap` (#5644 D1): a committed
|
|
769
|
+
// 58-entry literal map — one line per staged file's proprietary source
|
|
770
|
+
// path — put every one of those paths into this OSS-shipped file's
|
|
771
|
+
// SOURCE TEXT, the exact leak class `scripts/check-oss-strip.sh` exists
|
|
772
|
+
// to catch. `build-module-bundles.mjs`'s `deriveGlobInstallMap` derives
|
|
773
|
+
// the equivalent per-file `installMap` at bundle-build time instead —
|
|
774
|
+
// one entry per file `expandEntry` yields for the glob entry above,
|
|
775
|
+
// byte-identical to the literal map it replaces — and the mock registry
|
|
776
|
+
// fixture calls the same derivation so it cannot drift from the
|
|
777
|
+
// producer's. See `installRoot`'s own doc on `ModuleSlice` above.
|
|
778
|
+
installRoot: "apps/admin/",
|
|
679
779
|
},
|
|
680
780
|
// ── workspace — Pro module: the single-workspace settings shell (D-27/D-49)
|
|
681
781
|
//
|
|
682
|
-
// `/
|
|
782
|
+
// `/admin` in apps/web's `(authed)` segment — General (rename), Site
|
|
683
783
|
// (identity / SEO / theme, over the already-shipped apps/api config routes)
|
|
684
784
|
// and Team (a read-only roster). The three panels live in the shared
|
|
685
|
-
// `packages/
|
|
785
|
+
// `packages/admin-ui` package so the multi-tenant Admin app (the
|
|
686
786
|
// Pro Plus app) composes the identical components rather than a fork.
|
|
687
787
|
//
|
|
688
788
|
// No `apps` / `namespaces` / `forbiddenPatterns` block: this module
|
|
@@ -692,14 +792,14 @@ export const MODULE_SLICES = {
|
|
|
692
792
|
// A PERMISSION, not a physical slice (#5371 D1a) — the identical shape
|
|
693
793
|
// docs-blog uses for `packages/fumadocs-schema`. `packages/` is never in
|
|
694
794
|
// SNAPSHOT_DIRS, so the package reaches a buyer as an npm/bundle
|
|
695
|
-
// dependency under `node_modules/`, never as a `packages/
|
|
795
|
+
// dependency under `node_modules/`, never as a `packages/admin-ui`
|
|
696
796
|
// source sibling; the `patches` entry below is what puts it in the
|
|
697
797
|
// buyer's apps/web/package.json.
|
|
698
|
-
webImports: ["packages/
|
|
798
|
+
webImports: ["packages/admin-ui"],
|
|
699
799
|
packages: {
|
|
700
|
-
"
|
|
701
|
-
description: "Shared
|
|
702
|
-
// packages/templates is required because
|
|
800
|
+
"admin-ui": {
|
|
801
|
+
description: "Shared Admin-settings components — the settings shell plus the General / Site / Team panels, presentational only (data + save callbacks as props)",
|
|
802
|
+
// packages/templates is required because AdminSettingsShell
|
|
703
803
|
// composes AppShell from @working-theory/templates/shells — the same
|
|
704
804
|
// composition apps/web's own account page uses.
|
|
705
805
|
may_import_from: [
|
|
@@ -713,7 +813,7 @@ export const MODULE_SLICES = {
|
|
|
713
813
|
// SOURCE files only, and only the ones this module physically owns: the
|
|
714
814
|
// three apps/web route files and the two apps/api route files.
|
|
715
815
|
//
|
|
716
|
-
// `packages/
|
|
816
|
+
// `packages/admin-ui/**` is deliberately NOT listed (D1a). It is a
|
|
717
817
|
// whole package that is paid end to end, whose strip disposition is
|
|
718
818
|
// carried by architecture.yaml's `commercial_tier_moves_to` field (its
|
|
719
819
|
// future paid-tree home) rather than by a per-file inventory —
|
|
@@ -733,11 +833,21 @@ export const MODULE_SLICES = {
|
|
|
733
833
|
// Test companions (`__tests__/`) are never listed — the SOURCE-files-only
|
|
734
834
|
// rule above.
|
|
735
835
|
ownedFiles: [
|
|
736
|
-
"apps/web/app/[locale]/(authed)/
|
|
737
|
-
"apps/web/app/[locale]/(authed)/
|
|
738
|
-
"apps/web/app/[locale]/(authed)/
|
|
836
|
+
"apps/web/app/[locale]/(authed)/admin/page.tsx",
|
|
837
|
+
"apps/web/app/[locale]/(authed)/admin/site/page.tsx",
|
|
838
|
+
"apps/web/app/[locale]/(authed)/admin/team/page.tsx",
|
|
739
839
|
"apps/api/src/routes/workspaces/general.ts",
|
|
740
840
|
"apps/api/src/routes/workspaces/members.ts",
|
|
841
|
+
// Co-owned with `multi-tenant` (#6216) — see that slice's entry: the
|
|
842
|
+
// route registers under the SAME workspace||multi-tenant gate as the
|
|
843
|
+
// two lines above, and its service function imports `lib/tenant-db.ts`
|
|
844
|
+
// (a multi-tenant-owned file), so both must be deliverable by either
|
|
845
|
+
// bundle alone.
|
|
846
|
+
"apps/api/src/routes/workspaces/messages.ts",
|
|
847
|
+
"apps/api/src/services/inbox-messages.ts",
|
|
848
|
+
// Co-owned with `multi-tenant` (#5853) — see that slice's entry.
|
|
849
|
+
"apps/api/src/routes/workspaces/content.ts",
|
|
850
|
+
...ASSET_STORE_FILES,
|
|
741
851
|
],
|
|
742
852
|
// patches — the dependency add that delivers the shared package to the
|
|
743
853
|
// buyer's apps/web, mirroring docs-blog's own fumadocs-schema merge-keys
|
|
@@ -754,7 +864,7 @@ export const MODULE_SLICES = {
|
|
|
754
864
|
op: "merge-keys",
|
|
755
865
|
path: ["dependencies"],
|
|
756
866
|
entries: {
|
|
757
|
-
"@working-theory/
|
|
867
|
+
"@working-theory/admin-ui": "workspace:*",
|
|
758
868
|
},
|
|
759
869
|
},
|
|
760
870
|
],
|
|
@@ -770,8 +880,10 @@ export const MODULE_SLICES = {
|
|
|
770
880
|
// the ONLY holder of the scheduling credential.
|
|
771
881
|
// api apps/api's own /v1/schedule/availability + /v1/schedule/book.
|
|
772
882
|
// presentation the `booker` section (packages/ui, no iframe) rendered by
|
|
773
|
-
// the `
|
|
774
|
-
// confirmation page at /
|
|
883
|
+
// the `meet` route surface, plus the per-booking-type page
|
|
884
|
+
// and the module-owned confirmation page at /meet/:slug and
|
|
885
|
+
// /meet/confirmed (renamed from the schedule/ directory by
|
|
886
|
+
// #5563).
|
|
775
887
|
//
|
|
776
888
|
// The four forbidden patterns below are the module's whole security
|
|
777
889
|
// argument, restated as boundary rules rather than left in a comment: the
|
|
@@ -864,16 +976,19 @@ export const MODULE_SLICES = {
|
|
|
864
976
|
// consumer — unlike packages/validation below, a strip tool CAN delete
|
|
865
977
|
// exactly these files without touching anything another module needs.
|
|
866
978
|
//
|
|
867
|
-
//
|
|
868
|
-
// 2026-09-11
|
|
869
|
-
//
|
|
870
|
-
//
|
|
871
|
-
//
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
//
|
|
875
|
-
//
|
|
876
|
-
//
|
|
979
|
+
// ALL THREE apps/web/app/[locale]/meet pages are listed (#5182 Q9, disposed
|
|
980
|
+
// 2026-09-11; directory renamed from schedule/ to meet/ by #5563).
|
|
981
|
+
// confirmed/page.tsx says outright in its own doc comment that "The module
|
|
982
|
+
// OWNS this page... a scaffold without the module has no such route", and
|
|
983
|
+
// its sibling page.tsx is the SOLE production constructor of a `booker`
|
|
984
|
+
// section: it builds the section literally in TypeScript (page.tsx:60,
|
|
985
|
+
// `type: "booker"`) rather than reading it from content, and its own
|
|
986
|
+
// header calls the route API-backed with "no content file that could
|
|
987
|
+
// disagree with the calendar". [slug]/page.tsx is the third — the
|
|
988
|
+
// per-booking-type page #5563 added, composing its calLink from the same
|
|
989
|
+
// configured owner rather than reading one of its own. The create-ailk
|
|
990
|
+
// scaffolder already gates the whole `meet` route surface (src/surfaces.ts),
|
|
991
|
+
// so all three pages arrive and depart together.
|
|
877
992
|
//
|
|
878
993
|
// packages/sections-registry/src/registry.ts (the `booker:` entry) and
|
|
879
994
|
// packages/validation/src/schemas/page-sections.ts (BookerSectionDataSchema,
|
|
@@ -902,39 +1017,111 @@ export const MODULE_SLICES = {
|
|
|
902
1017
|
// scheduling-specific. This is a judgment call, not covered by this
|
|
903
1018
|
// card's explicit checklist: flagged for reviewer confirmation.
|
|
904
1019
|
//
|
|
905
|
-
//
|
|
906
|
-
//
|
|
907
|
-
//
|
|
908
|
-
//
|
|
909
|
-
// files
|
|
910
|
-
// `slice-renderers.ts` and `ModuleAbsent.tsx` — are
|
|
911
|
-
// here: they ship, and listing one would take the
|
|
1020
|
+
// The Booker components and the slice's registration entry point (#5214)
|
|
1021
|
+
// moved to packages-paid/ui-scheduling (#5581 U3); that package is a
|
|
1022
|
+
// physical part of the tree, not a listed ownedFiles entry, and reaches a
|
|
1023
|
+
// keyed scaffold through this slice's `patches` block below (D5). The
|
|
1024
|
+
// three files the old in-packages/ui path added on the OSS side —
|
|
1025
|
+
// `SectionRenderer.tsx`, `slice-renderers.ts` and `ModuleAbsent.tsx` — are
|
|
1026
|
+
// deliberately NOT listed here: they ship, and listing one would take the
|
|
1027
|
+
// whole dispatch table with it.
|
|
912
1028
|
ownedFiles: [
|
|
913
1029
|
"apps/api/src/routes/schedule/index.ts",
|
|
914
1030
|
"apps/api/src/services/scheduling/index.ts",
|
|
915
1031
|
"apps/api/src/services/scheduling/cal-provider.ts",
|
|
916
1032
|
"apps/api/src/services/scheduling/types.ts",
|
|
1033
|
+
// #6182 (S9a) — the Cal adapter's own suite. Individually, never as a
|
|
1034
|
+
// glob (§ D12 above, property 1: a glob entry is a silent no-op, so
|
|
1035
|
+
// `__tests__/**` would ship no test at all to a keyed scaffold).
|
|
1036
|
+
"apps/api/src/services/scheduling/__tests__/cal-provider.test.ts",
|
|
917
1037
|
"apps/mcp/src/tools/list_availability.ts",
|
|
918
1038
|
"apps/mcp/src/tools/get_event_meta.ts",
|
|
919
1039
|
"apps/mcp/src/tools/create_booking.ts",
|
|
920
|
-
"
|
|
921
|
-
"
|
|
922
|
-
"
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
"
|
|
1040
|
+
"apps/web/app/[locale]/meet/page.tsx",
|
|
1041
|
+
"apps/web/app/[locale]/meet/[slug]/page.tsx",
|
|
1042
|
+
"apps/web/app/[locale]/meet/confirmed/page.tsx",
|
|
1043
|
+
// #6085 (brief H7) — the six files the webhook receiver + the
|
|
1044
|
+
// tenant-guarded appointments read add. Individually, never as a
|
|
1045
|
+
// glob (§ D12 / this card's own comment above, property 1: a glob
|
|
1046
|
+
// entry is a silent no-op, so __tests__/** would ship no test at all
|
|
1047
|
+
// to a keyed scaffold). `apps/api/src/routes/webhooks/index.ts` is
|
|
1048
|
+
// NOT added — it is the mixed barrel that also registers the Stripe
|
|
1049
|
+
// receiver, the same "mixed barrel is never listed" precedent this
|
|
1050
|
+
// slice already records for `routes/project-listings/index.ts`.
|
|
1051
|
+
// `apps/api/src/routes/schedule/index.ts` is already listed above and
|
|
1052
|
+
// stays (it re-exports `listAppointmentsRoute` alongside the three
|
|
1053
|
+
// anonymous routes it already re-exports).
|
|
1054
|
+
"apps/api/src/routes/webhooks/calcom.ts",
|
|
1055
|
+
"apps/api/src/routes/webhooks/__tests__/calcom.test.ts",
|
|
1056
|
+
"apps/api/src/services/scheduling/appointments.ts",
|
|
1057
|
+
"apps/api/src/services/scheduling/__tests__/appointments.test.ts",
|
|
1058
|
+
"apps/api/src/routes/schedule/appointments.ts",
|
|
1059
|
+
"apps/api/src/routes/schedule/__tests__/appointments.test.ts",
|
|
1060
|
+
// #6086 (brief H7) — the SITE's appointments page, the visible half of
|
|
1061
|
+
// the read above. The co-located suite is listed EXPLICITLY alongside
|
|
1062
|
+
// its page: `EXCLUDE_TEMPLATE_DIRS` below drops only the three
|
|
1063
|
+
// top-level `apps/web/**/__tests__` directories, and the import-graph
|
|
1064
|
+
// closure walks FORWARD from an owned file — a test that imports
|
|
1065
|
+
// `../page` is a dependent, not a companion, so it is never swept
|
|
1066
|
+
// along. Without the second entry a keyless scaffold would carry a
|
|
1067
|
+
// test for a page it does not have.
|
|
1068
|
+
"apps/web/app/[locale]/(authed)/appointments/page.tsx",
|
|
1069
|
+
"apps/web/app/[locale]/(authed)/appointments/__tests__/page.test.tsx",
|
|
1070
|
+
// #6183 S9b — the enabled-meeting-slugs gate. `meetings.ts` is its own
|
|
1071
|
+
// file (not folded into `routes/workspaces/config.ts`, which is
|
|
1072
|
+
// `workspace`/`multi-tenant`-owned) precisely because its GET reaches
|
|
1073
|
+
// `services/scheduling/` — the SAME reason `routes/schedule/
|
|
1074
|
+
// appointments.ts` above is its own file rather than a row on an
|
|
1075
|
+
// existing route. `lib/public-meetings-config.ts` is the public-read
|
|
1076
|
+
// boundary `routes/schedule/meeting-types.ts` (the anonymous read,
|
|
1077
|
+
// already reached via the already-listed `routes/schedule/index.ts`)
|
|
1078
|
+
// calls into.
|
|
1079
|
+
"apps/api/src/routes/workspaces/meetings.ts",
|
|
1080
|
+
"apps/api/src/routes/workspaces/__tests__/meetings.test.ts",
|
|
1081
|
+
"apps/api/src/lib/public-meetings-config.ts",
|
|
1082
|
+
"apps/api/src/routes/schedule/meeting-types.ts",
|
|
1083
|
+
"apps/api/src/routes/schedule/__tests__/meeting-types.test.ts",
|
|
1084
|
+
// meetings.ts is the FIRST scheduling-gated route to use the generic
|
|
1085
|
+
// tenantDb() scope layer directly (its sibling, appointments.ts, does
|
|
1086
|
+
// its own scoped read in services/scheduling/appointments.ts instead)
|
|
1087
|
+
// — and `workspaceMeetings` is now in architecture.yaml's tenant-scope
|
|
1088
|
+
// forbidden_pattern (#6183), so meetings.ts cannot bypass tenantDb()
|
|
1089
|
+
// with a raw prisma call. Co-owned with `multi-tenant` below (the
|
|
1090
|
+
// SAME two files, same reason `content.ts`'s own comment there
|
|
1091
|
+
// records: "each tenancy slice must deliver it").
|
|
1092
|
+
"apps/api/src/lib/tenant-db.ts",
|
|
1093
|
+
"apps/api/src/services/tenant-context.ts",
|
|
930
1094
|
],
|
|
931
|
-
// pageContributions (spec 5478; parent § D6 shape 1) — the booker
|
|
932
|
-
// confirmation page, whose route files
|
|
933
|
-
//
|
|
934
|
-
// routes, not from an MDX file.
|
|
1095
|
+
// pageContributions (spec 5478; parent § D6 shape 1) — the booker, the
|
|
1096
|
+
// per-booking-type page and the confirmation page, whose route files
|
|
1097
|
+
// `ownedFiles` above already carries. No row names seed content: all
|
|
1098
|
+
// three render from the /v1/schedule/* routes, not from an MDX file.
|
|
935
1099
|
pageContributions: [
|
|
936
|
-
{ route: "/
|
|
937
|
-
{ route: "/
|
|
1100
|
+
{ route: "/meet" },
|
|
1101
|
+
{ route: "/meet/[slug]" },
|
|
1102
|
+
{ route: "/meet/confirmed" },
|
|
1103
|
+
// #6086 — the authed appointments page. Bracket (roster) grammar and no
|
|
1104
|
+
// `content` key, for the same reason the three /meet rows carry none:
|
|
1105
|
+
// it renders from `/v1/schedule/appointments`, not from an MDX file.
|
|
1106
|
+
{ route: "/appointments" },
|
|
1107
|
+
],
|
|
1108
|
+
// patches (#5581 U3, D5) — delivers the extracted component package to a
|
|
1109
|
+
// keyed scaffold's apps/web, mirroring the signal-collectors slice's
|
|
1110
|
+
// identical merge-keys op below.
|
|
1111
|
+
patches: [
|
|
1112
|
+
{
|
|
1113
|
+
target: "apps/web/package.json",
|
|
1114
|
+
kind: "json",
|
|
1115
|
+
ops: [
|
|
1116
|
+
{
|
|
1117
|
+
op: "merge-keys",
|
|
1118
|
+
path: ["dependencies"],
|
|
1119
|
+
entries: {
|
|
1120
|
+
"@working-theory/ui-scheduling": "workspace:*",
|
|
1121
|
+
},
|
|
1122
|
+
},
|
|
1123
|
+
],
|
|
1124
|
+
},
|
|
938
1125
|
],
|
|
939
1126
|
},
|
|
940
1127
|
// ── signal-collectors — flows, deliverables, project listings, waitlist
|
|
@@ -1089,6 +1276,94 @@ export const MODULE_SLICES = {
|
|
|
1089
1276
|
"apps/api/src/bin/seed-waitlist-experiments.ts",
|
|
1090
1277
|
"apps/mcp/src/tools/get_flow.ts",
|
|
1091
1278
|
"apps/mcp/src/tools/submit_flow_step.ts",
|
|
1279
|
+
// ── The review surface (#5677) — CO-OWNED with multi-tenant ──────────
|
|
1280
|
+
//
|
|
1281
|
+
// Every path below is ALSO a multi-tenant `ownedFiles` entry and stays
|
|
1282
|
+
// one. Listing a file under two modules is additive, not a transfer:
|
|
1283
|
+
// `paidModuleTemplateExclusions()` unions every paid module's entries,
|
|
1284
|
+
// so the `templates/` snapshot is unchanged, and a multi-tenant scaffold
|
|
1285
|
+
// keeps receiving these from the multi-tenant bundle exactly as before.
|
|
1286
|
+
// What changes is that a signal-collectors bundle now carries them too.
|
|
1287
|
+
//
|
|
1288
|
+
// WHY THEY MUST BE HERE. #5677 widened `server.ts`'s review-surface
|
|
1289
|
+
// registration from `multi-tenant` to `multi-tenant || signal-collectors`,
|
|
1290
|
+
// because signal-collectors is the module that SELLS the instruments
|
|
1291
|
+
// these routes read back. Registration and DELIVERY are separate layers:
|
|
1292
|
+
// the widened gate calls `sliceRoutePlugin("waitlistExperimentRoutes")`
|
|
1293
|
+
// and imports `projectListingTenantRoutes`, so on a scaffold whose
|
|
1294
|
+
// `AILK_ENABLED_MODULES` names signal-collectors but whose tree lacks
|
|
1295
|
+
// these files, `loadSlice` throws ERR_MODULE_NOT_FOUND during `build()`
|
|
1296
|
+
// — construction, so EVERY route 500s rather than one. That is not a
|
|
1297
|
+
// feature gap; it is the outage shape `lib/slice-load.ts` exists to
|
|
1298
|
+
// diagnose.
|
|
1299
|
+
//
|
|
1300
|
+
// It is not hypothetical: `marketing-site` — the Pro flagship in
|
|
1301
|
+
// `template-manifest.ts` — declares
|
|
1302
|
+
// `requires: ["marketing", "docs-blog", "scheduling", "signal-collectors"]`,
|
|
1303
|
+
// i.e. signal-collectors WITHOUT multi-tenant. That is exactly the
|
|
1304
|
+
// configuration that would crash, which is why the gate and the delivery
|
|
1305
|
+
// land together rather than the delivery being deferred.
|
|
1306
|
+
//
|
|
1307
|
+
// The closure is tight, verified by grep rather than assumed: none of
|
|
1308
|
+
// these files imports `lib/tenant-db.ts` or `services/tenant-context.ts`
|
|
1309
|
+
// (both multi-tenant-only). #5677 retargeted `waitlist-dashboard.ts`'s
|
|
1310
|
+
// type import of `tenant-context.js` to the base `services/default-tenant.ts`,
|
|
1311
|
+
// which severed the one cross-slice edge that existed.
|
|
1312
|
+
//
|
|
1313
|
+
// `routes/project-listings/{start,patch-draft,submit,public,me,respond,
|
|
1314
|
+
// resume-token,patch-copy}.ts` are NOT listed — they are the free
|
|
1315
|
+
// anonymous surface and the mixed barrel, covered by the note above this
|
|
1316
|
+
// array, and they already ship unconditionally.
|
|
1317
|
+
"apps/api/src/routes/waitlist-experiments/index.ts",
|
|
1318
|
+
"apps/api/src/routes/waitlist-experiments/list.ts",
|
|
1319
|
+
"apps/api/src/routes/waitlist-experiments/comparison.ts",
|
|
1320
|
+
"apps/api/src/routes/waitlist-experiments/signup.ts",
|
|
1321
|
+
"apps/api/src/routes/waitlist-experiments/signups.ts",
|
|
1322
|
+
"apps/api/src/routes/waitlist-experiments/respond.ts",
|
|
1323
|
+
"apps/api/src/services/waitlist-dashboard.ts",
|
|
1324
|
+
// #6258 — the file waitlist-dashboard.ts imports for the pinned
|
|
1325
|
+
// platform-operator read scope. It rides BOTH slices for the same
|
|
1326
|
+
// reason its importer does: an unlisted import target breaks a
|
|
1327
|
+
// signal-collectors-without-multi-tenant scaffold at build() time.
|
|
1328
|
+
"apps/api/src/services/waitlist-operator-reads.ts",
|
|
1329
|
+
// #6157 D14/D16 — the magnet Admin authoring surface's own sibling
|
|
1330
|
+
// tenant scope is gated `multi-tenant || signal-collectors` (D4,
|
|
1331
|
+
// the SAME expression this review-surface block co-owns files
|
|
1332
|
+
// under), so both its route file AND `lib/tenant-db.ts` (the ONE
|
|
1333
|
+
// data path it reads/writes through, FR3) must be delivered here
|
|
1334
|
+
// too. `lib/tenant-db.ts` is ALSO listed under `multi-tenant` above
|
|
1335
|
+
// — additive, not a transfer (the same reasoning this array's own
|
|
1336
|
+
// header comment already states for every other file in it).
|
|
1337
|
+
//
|
|
1338
|
+
// The closure stays tight WITHOUT dragging in `tenant-context.ts` or
|
|
1339
|
+
// the multi-tenant guard assembly behind it, because `tenant-db.ts`'s
|
|
1340
|
+
// own type import was retargeted from `tenant-context.js` to the
|
|
1341
|
+
// BASE-tree `services/default-tenant.js` in this same unit (D15) —
|
|
1342
|
+
// the identical one-line class of move #5677 made for
|
|
1343
|
+
// `waitlist-dashboard.ts` two paragraphs above this one.
|
|
1344
|
+
"apps/api/src/routes/magnets/index.ts",
|
|
1345
|
+
"apps/api/src/lib/tenant-db.ts",
|
|
1346
|
+
"apps/api/src/routes/project-listings/get.ts",
|
|
1347
|
+
"apps/api/src/routes/project-listings/list.ts",
|
|
1348
|
+
"apps/api/src/routes/project-listings/patch.ts",
|
|
1349
|
+
// The dashboard itself. Without these the Pro scaffold would boot with
|
|
1350
|
+
// reachable review routes and no UI to read them through, and the two
|
|
1351
|
+
// files that DO already ship into every scaffold
|
|
1352
|
+
// (`waitlist/format.ts`, `waitlist/components/ForbiddenState.tsx` — never
|
|
1353
|
+
// owned by any module) would stay orphaned. They import only
|
|
1354
|
+
// `@working-theory/api-client`, `@working-theory/ui` and
|
|
1355
|
+
// `@working-theory/validation`, all base packages, so this pulls in no
|
|
1356
|
+
// multi-tenant dependency.
|
|
1357
|
+
"apps/web/app/[locale]/(authed)/waitlist/page.tsx",
|
|
1358
|
+
"apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx",
|
|
1359
|
+
"apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx",
|
|
1360
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx",
|
|
1361
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx",
|
|
1362
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx",
|
|
1363
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx",
|
|
1364
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx",
|
|
1365
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx",
|
|
1366
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx",
|
|
1092
1367
|
// apps/web/app/[locale]/flows/** deliberately NOT listed here (unlike
|
|
1093
1368
|
// the docs-blog precedent's own `blog`/`docs` page.tsx entries above),
|
|
1094
1369
|
// even though every file under it is signal-collectors territory and
|
|
@@ -1115,18 +1390,29 @@ export const MODULE_SLICES = {
|
|
|
1115
1390
|
// `NESTED_FOREIGN_MODULE_ENTRIES` for the companion fix that keeps its
|
|
1116
1391
|
// presence from falsely reading as "projects carried".
|
|
1117
1392
|
"apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx",
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
"
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
"
|
|
1393
|
+
// #5581 U4 — the eleven signal-collectors components + the slice's own
|
|
1394
|
+
// re-export entry point moved to packages-paid/ui-signal-collectors;
|
|
1395
|
+
// the package is delivered to a keyed scaffold via `patches` below,
|
|
1396
|
+
// not via `ownedFiles`/`installMap` (D5).
|
|
1397
|
+
// #5562 — the report reader at `/reports/<slug>`. UNLIKE the flow routes
|
|
1398
|
+
// above, this one DOES belong in `ownedFiles`, and for the same reason
|
|
1399
|
+
// `projects/apply/ListingApplicationClient.tsx` does: `/reports` is a URL
|
|
1400
|
+
// segment `MODULE_SURFACES["signal-collectors"] = ["flows"]` does not gate,
|
|
1401
|
+
// so `excludedRoutePaths()` would leave it in a keyless scaffold. It has no
|
|
1402
|
+
// upgrade-path fixture to protect either — it is net-new here, so nothing
|
|
1403
|
+
// in `templates/` can regress by its absence.
|
|
1404
|
+
"apps/web/app/[locale]/reports/[slug]/page.tsx",
|
|
1405
|
+
//
|
|
1406
|
+
// The two sections that route composes — `report-header` and
|
|
1407
|
+
// `reports-list` — are deliberately NOT owned here. They are
|
|
1408
|
+
// `SectionRenderer` DISPATCH entries with static imports, so stripping
|
|
1409
|
+
// them would leave the renderer with dangling imports in a keyless
|
|
1410
|
+
// scaffold; the escape hatch for a slice-owned dispatch entry is the
|
|
1411
|
+
// `ModuleAbsent` placeholder (`booker`, `payment-receipt`), which is
|
|
1412
|
+
// machinery neither of these needs. `document-viewer` (#5270) — the
|
|
1413
|
+
// reader this route is built around, and the section with the strongest
|
|
1414
|
+
// claim to being deliverables-only — is likewise unowned base
|
|
1415
|
+
// `packages/ui`. A section is vocabulary; the ROUTE is the module.
|
|
1130
1416
|
],
|
|
1131
1417
|
// pageContributions (spec 5478; parent § D6 shape 2) — the three flow
|
|
1132
1418
|
// routes, named exactly as `surfaces.ts`'s ROUTE_SINCE keys name them.
|
|
@@ -1146,6 +1432,61 @@ export const MODULE_SLICES = {
|
|
|
1146
1432
|
{ route: "/flows/[slug]" },
|
|
1147
1433
|
{ route: "/flows/[slug]/start" },
|
|
1148
1434
|
{ route: "/flows/[slug]/results/[payload]" },
|
|
1435
|
+
// #5562 — the report reader. Unlike the three rows above, this row's
|
|
1436
|
+
// code IS this module's own `ownedFiles` (see the note beside it), so
|
|
1437
|
+
// the contribution and the delivery shape carrying it agree here.
|
|
1438
|
+
{ route: "/reports/[slug]" },
|
|
1439
|
+
],
|
|
1440
|
+
// installMap (#5618 D6.3) — the module's ten sample files, moved here out
|
|
1441
|
+
// of `site-templates/marketing-site/` so the module OWNS its samples
|
|
1442
|
+
// (Rule B) and a keyed `--modules signal-collectors` scaffold with no
|
|
1443
|
+
// template lands them. Their in-repo home is
|
|
1444
|
+
// `packages/create-ailk/module-templates/signal-collectors/**`, mirroring
|
|
1445
|
+
// `commerce.installMap` below — the only other slice-level map — because
|
|
1446
|
+
// an `installMap` KEY is a repo-relative source the producer copies
|
|
1447
|
+
// literally, and `content/en/ProjectsList/projects.mdx` is ALSO this
|
|
1448
|
+
// repo's own live marketing copy (a different file), which
|
|
1449
|
+
// build-templates.mjs keeps out of every scaffold: under
|
|
1450
|
+
// `module-templates/` the two never meet.
|
|
1451
|
+
//
|
|
1452
|
+
// Four entries are real renames (the flow and waitlist seeds the API
|
|
1453
|
+
// reads, and the report PDF under apps/web/public/); the six MDX entries
|
|
1454
|
+
// are self-addressed because no `pageContributions` row declares
|
|
1455
|
+
// `/projects`, `/projects/[slug]` or `/thanks/[slug]` yet (spec § 7
|
|
1456
|
+
// finding 7 — declaring them changes the enabled-surface set and so the
|
|
1457
|
+
// Pro scaffold's file set, a separate decision). Once those rows exist
|
|
1458
|
+
// the six move to `pageContributions[].content` with no further
|
|
1459
|
+
// migration. `generate-sample-report.py` keeps its root-level
|
|
1460
|
+
// destination (finding 1 — AC7 forbids changing the Pro file set).
|
|
1461
|
+
installMap: {
|
|
1462
|
+
"packages/create-ailk/module-templates/signal-collectors/content/en/ProjectsList/projects.mdx": "content/en/ProjectsList/projects.mdx",
|
|
1463
|
+
"packages/create-ailk/module-templates/signal-collectors/content/en/Project/fit-check-funnel.mdx": "content/en/Project/fit-check-funnel.mdx",
|
|
1464
|
+
"packages/create-ailk/module-templates/signal-collectors/content/en/Project/launch-site-in-fourteen-days.mdx": "content/en/Project/launch-site-in-fourteen-days.mdx",
|
|
1465
|
+
"packages/create-ailk/module-templates/signal-collectors/content/en/ThankYouPage/contact.mdx": "content/en/ThankYouPage/contact.mdx",
|
|
1466
|
+
"packages/create-ailk/module-templates/signal-collectors/content/en/ThankYouPage/newsletter.mdx": "content/en/ThankYouPage/newsletter.mdx",
|
|
1467
|
+
"packages/create-ailk/module-templates/signal-collectors/content/en/ThankYouPage/apply.mdx": "content/en/ThankYouPage/apply.mdx",
|
|
1468
|
+
"packages/create-ailk/module-templates/signal-collectors/flows/fit-check.flow.json": "database/flows/fit-check.flow.json",
|
|
1469
|
+
"packages/create-ailk/module-templates/signal-collectors/waitlist/launch-waitlist.experiment.json": "database/waitlist/launch-waitlist.experiment.json",
|
|
1470
|
+
"packages/create-ailk/module-templates/signal-collectors/reports/sample-report.pdf": "apps/web/public/reports/sample-report.pdf",
|
|
1471
|
+
"packages/create-ailk/module-templates/signal-collectors/reports/generate-sample-report.py": "reports/generate-sample-report.py",
|
|
1472
|
+
},
|
|
1473
|
+
// patches (#5581 U4, D5) — delivers the extracted component package to a
|
|
1474
|
+
// keyed scaffold's apps/web, mirroring the workspace slice's identical
|
|
1475
|
+
// merge-keys op above.
|
|
1476
|
+
patches: [
|
|
1477
|
+
{
|
|
1478
|
+
target: "apps/web/package.json",
|
|
1479
|
+
kind: "json",
|
|
1480
|
+
ops: [
|
|
1481
|
+
{
|
|
1482
|
+
op: "merge-keys",
|
|
1483
|
+
path: ["dependencies"],
|
|
1484
|
+
entries: {
|
|
1485
|
+
"@working-theory/ui-signal-collectors": "workspace:*",
|
|
1486
|
+
},
|
|
1487
|
+
},
|
|
1488
|
+
],
|
|
1489
|
+
},
|
|
1149
1490
|
],
|
|
1150
1491
|
},
|
|
1151
1492
|
// ── commerce — per-site paid add-on (D-47, amending D-26) ─────────────────
|
|
@@ -1189,18 +1530,14 @@ export const MODULE_SLICES = {
|
|
|
1189
1530
|
},
|
|
1190
1531
|
},
|
|
1191
1532
|
packages: {
|
|
1192
|
-
//
|
|
1193
|
-
//
|
|
1194
|
-
//
|
|
1195
|
-
//
|
|
1196
|
-
//
|
|
1197
|
-
//
|
|
1198
|
-
// `
|
|
1199
|
-
//
|
|
1200
|
-
"stripe-client": {
|
|
1201
|
-
description: "Stripe SDK wrapper + webhook signature verification",
|
|
1202
|
-
may_import_from: ["packages/validation"],
|
|
1203
|
-
},
|
|
1533
|
+
// `stripe-client` is deliberately NOT declared here (#5823). It was,
|
|
1534
|
+
// duplicated verbatim from the multi-tenant slice, while the package was
|
|
1535
|
+
// paid and commerce-owned. Since #5810 it is `commercial_tier: oss`,
|
|
1536
|
+
// published public, and since #5812 its sole `apps/api` importer
|
|
1537
|
+
// (`lib/stripe.ts`) is a base file — so the package is base, not a
|
|
1538
|
+
// commerce slice member. The `packages/stripe-client` entries in the
|
|
1539
|
+
// `may_import_from` lists above and in the base/multi-tenant slices are
|
|
1540
|
+
// unaffected: those declare who may reach the package, not who owns it.
|
|
1204
1541
|
// Duplicated VERBATIM from the marketing slice for the same
|
|
1205
1542
|
// order-independence reason the multi-tenant/scheduling slices state.
|
|
1206
1543
|
validation: {
|
|
@@ -1221,54 +1558,40 @@ export const MODULE_SLICES = {
|
|
|
1221
1558
|
// ownedFiles (S1, #5088). SOURCE files only (#5182 D6) — no __tests__/,
|
|
1222
1559
|
// no .stories.tsx, no .text.ts... except .text.ts siblings ARE source
|
|
1223
1560
|
// (they ship as runtime copy modules, not test fixtures), so the ten
|
|
1224
|
-
// annotated below are listed.
|
|
1561
|
+
// annotated below are listed. 36 in all: 4 apps/api + 26 packages/ui
|
|
1225
1562
|
// (15 components + 10 .text.ts siblings + this slice's own
|
|
1226
1563
|
// sections/slices/commerce.ts) + 7 apps/web.
|
|
1564
|
+
//
|
|
1565
|
+
// THE PRIMITIVES LEFT THIS SLICE (D-64, epic #5770, #5796). The checkout
|
|
1566
|
+
// launcher, the Stripe webhook receiver, customer mapping and the
|
|
1567
|
+
// `lib/stripe.ts` shim are BASE TREE now: `apps/api/src/server.ts`
|
|
1568
|
+
// registers them unconditionally and gates them at CALL time on the JWT
|
|
1569
|
+
// `commerce` claim (`apps/api/src/lib/require-commerce-claim.ts`), so a
|
|
1570
|
+
// keyless scaffold must CARRY them. Claiming them here is what deleted
|
|
1571
|
+
// them from that scaffold while the server still loaded them —
|
|
1572
|
+
// ERR_MODULE_NOT_FOUND inside build(), every route 500ing, which is the
|
|
1573
|
+
// exact defect `tools/lint-slice-registration.ts` (#5701) exists to
|
|
1574
|
+
// catch. The six that left: lib/stripe.ts,
|
|
1575
|
+
// routes/checkout/{index,sessions}.ts, routes/webhooks/{index,stripe}.ts
|
|
1576
|
+
// and routes/webhooks/README.md. The four below STAY — they are commerce
|
|
1577
|
+
// OVERLAY, still registered behind `isModuleEnabled("commerce")` and
|
|
1578
|
+
// still carrying their `// oss: false` markers.
|
|
1227
1579
|
ownedFiles: [
|
|
1228
|
-
"apps/api/src/lib/stripe.ts",
|
|
1229
|
-
"apps/api/src/routes/checkout/index.ts",
|
|
1230
|
-
"apps/api/src/routes/checkout/sessions.ts",
|
|
1231
|
-
"apps/api/src/routes/webhooks/index.ts",
|
|
1232
|
-
"apps/api/src/routes/webhooks/stripe.ts",
|
|
1233
|
-
// README.md documents the Stripe webhook receiver — not a test/
|
|
1234
|
-
// generated file, and its absence is exactly what left a stray
|
|
1235
|
-
// apps/api/src/routes/webhooks/ directory in a keyless templates/
|
|
1236
|
-
// snapshot (empirically found, #5364 build pass): the import-graph
|
|
1237
|
-
// closure only scans source extensions, never markdown, so once
|
|
1238
|
-
// index.ts and stripe.ts are excluded this is the one file left
|
|
1239
|
-
// behind. Same defect class #5366 found and fixed the same way for
|
|
1240
|
-
// routes/flows/README.md — see that entry above.
|
|
1241
|
-
"apps/api/src/routes/webhooks/README.md",
|
|
1242
1580
|
"apps/api/src/routes/flow-checkouts/index.ts",
|
|
1243
1581
|
"apps/api/src/routes/flows/recommender.ts",
|
|
1244
1582
|
"apps/api/src/services/recommender-capture.ts",
|
|
1245
1583
|
"apps/api/src/services/flow-checkouts.ts",
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
"
|
|
1250
|
-
"
|
|
1251
|
-
"
|
|
1252
|
-
"
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
"packages/ui/src/blocks/InvoiceList.text.ts",
|
|
1258
|
-
"packages/ui/src/blocks/SubscriptionStatus.tsx",
|
|
1259
|
-
"packages/ui/src/blocks/SubscriptionStatus.text.ts",
|
|
1260
|
-
"packages/ui/src/blocks/StripeActionButton.tsx",
|
|
1261
|
-
"packages/ui/src/blocks/PaymentStatusBadge.tsx",
|
|
1262
|
-
"packages/ui/src/blocks/PaymentStatusBadge.text.ts",
|
|
1263
|
-
"packages/ui/src/blocks/PaymentResult.tsx",
|
|
1264
|
-
"packages/ui/src/blocks/PaymentResult.text.ts",
|
|
1265
|
-
"packages/ui/src/blocks/PortalEntry.tsx",
|
|
1266
|
-
"packages/ui/src/panels/InvoiceDetail.tsx",
|
|
1267
|
-
"packages/ui/src/panels/InvoiceDetail.text.ts",
|
|
1268
|
-
"packages/ui/src/sections/PaymentReceipt.tsx",
|
|
1269
|
-
"packages/ui/src/sections/PricingTable.tsx",
|
|
1270
|
-
"packages/ui/src/sections/PricingTable.text.ts",
|
|
1271
|
-
"packages/ui/src/sections/slices/commerce.ts",
|
|
1584
|
+
// #6038 — the buyer-scoped subscription-status route pair (the
|
|
1585
|
+
// update-your-card banner's read + portal handoff). Commerce OVERLAY,
|
|
1586
|
+
// same posture as the four flow-checkouts/recommender entries above.
|
|
1587
|
+
"apps/api/src/routes/subscription/index.ts",
|
|
1588
|
+
"apps/api/src/routes/subscription/me.ts",
|
|
1589
|
+
"apps/api/src/routes/subscription/portal.ts",
|
|
1590
|
+
"apps/api/src/services/subscription.ts",
|
|
1591
|
+
// #5581 U5 — the fifteen commerce components (+ ten .text.ts extractors
|
|
1592
|
+
// + the slice's own re-export entry point) moved to
|
|
1593
|
+
// packages-paid/ui-commerce; the package is delivered to a keyed
|
|
1594
|
+
// scaffold via `patches` below, not via `ownedFiles`/`installMap` (D5).
|
|
1272
1595
|
"apps/web/app/[locale]/flows/[slug]/checkout.actions.ts",
|
|
1273
1596
|
"apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx",
|
|
1274
1597
|
"apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx",
|
|
@@ -1298,7 +1621,32 @@ export const MODULE_SLICES = {
|
|
|
1298
1621
|
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/portal-route.template.ts": ".claude/skills/scaffold-commerce/templates/portal-route.template.ts",
|
|
1299
1622
|
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts": ".claude/skills/scaffold-commerce/templates/stripe-config.template.ts",
|
|
1300
1623
|
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts": ".claude/skills/scaffold-commerce/templates/subscription-route.template.ts",
|
|
1624
|
+
// The commerce-boundary rule (#6039/#6070, this entry #6041): ships to
|
|
1625
|
+
// a commerce-keyed scaffold's project root so an agent working there
|
|
1626
|
+
// reads the money/live-mode/personal-data classification before it
|
|
1627
|
+
// acts. One more literal entry alongside the ten scaffold-commerce
|
|
1628
|
+
// skill entries above, for the same reason — a directory source is
|
|
1629
|
+
// rejected by `validateInstallMap`.
|
|
1630
|
+
"packages/create-ailk/module-templates/commerce/.claude/rules/commerce-boundary.md": ".claude/rules/commerce-boundary.md",
|
|
1301
1631
|
},
|
|
1632
|
+
// patches (#5581 U5, D5) — delivers the extracted component package to a
|
|
1633
|
+
// keyed scaffold's apps/web, mirroring the workspace slice's identical
|
|
1634
|
+
// merge-keys op above.
|
|
1635
|
+
patches: [
|
|
1636
|
+
{
|
|
1637
|
+
target: "apps/web/package.json",
|
|
1638
|
+
kind: "json",
|
|
1639
|
+
ops: [
|
|
1640
|
+
{
|
|
1641
|
+
op: "merge-keys",
|
|
1642
|
+
path: ["dependencies"],
|
|
1643
|
+
entries: {
|
|
1644
|
+
"@working-theory/ui-commerce": "workspace:*",
|
|
1645
|
+
},
|
|
1646
|
+
},
|
|
1647
|
+
],
|
|
1648
|
+
},
|
|
1649
|
+
],
|
|
1302
1650
|
},
|
|
1303
1651
|
};
|
|
1304
1652
|
/**
|
|
@@ -1346,9 +1694,98 @@ export function normalizeModules(modules) {
|
|
|
1346
1694
|
* Passed in rather than derived from `import.meta.url`, which ts-jest cannot
|
|
1347
1695
|
* load — the same reason `sync-routes.ts` documents for staying pure.
|
|
1348
1696
|
*/
|
|
1697
|
+
/**
|
|
1698
|
+
* Scaffold destinations that MORE THAN ONE module's `ownedFiles` declares —
|
|
1699
|
+
* the co-ownership the `#5618 D4` install-time ownership registry must treat
|
|
1700
|
+
* as intentional rather than as an overwrite (#5702 follow-up).
|
|
1701
|
+
*
|
|
1702
|
+
* Co-ownership is how a file reaches a scaffold under either of two modules
|
|
1703
|
+
* without being transferred away from the other. #5677 needed it for the
|
|
1704
|
+
* submissions review surface: the routes register under
|
|
1705
|
+
* `multi-tenant || signal-collectors`, so BOTH bundles must be able to
|
|
1706
|
+
* deliver them, or the module that lacks them throws
|
|
1707
|
+
* `ERR_MODULE_NOT_FOUND` during `build()`.
|
|
1708
|
+
*
|
|
1709
|
+
* `validateLayerOwnership` (`lib/extract-module-bundle.ts`) refuses a
|
|
1710
|
+
* destination an earlier layer already wrote, because a silent
|
|
1711
|
+
* last-writer-wins between two modules that disagree is the bug `#5618 D4`
|
|
1712
|
+
* exists to catch. Two modules that both DECLARE the same repo file are not
|
|
1713
|
+
* that case: they stage the same bytes from the same source, so whichever
|
|
1714
|
+
* lands second writes what is already there. Without this allowance a
|
|
1715
|
+
* scaffold selecting both modules — `saas-product`, whose `requires` names
|
|
1716
|
+
* `signal-collectors` AND `multi-tenant` — aborts mid-install, after the
|
|
1717
|
+
* first module's files are on disk.
|
|
1718
|
+
*
|
|
1719
|
+
* Only a DECLARED overlap is allowed. A destination two layers collide on
|
|
1720
|
+
* without both naming it in `ownedFiles` is still refused, which is the
|
|
1721
|
+
* whole invariant.
|
|
1722
|
+
*/
|
|
1723
|
+
export function coOwnedModuleDestinations() {
|
|
1724
|
+
const seen = new Map();
|
|
1725
|
+
for (const slice of Object.values(MODULE_SLICES)) {
|
|
1726
|
+
// A module's own list is deduplicated first: repetition within one slice
|
|
1727
|
+
// is not co-ownership and must not license an overlap on its own.
|
|
1728
|
+
for (const file of new Set(slice.ownedFiles ?? [])) {
|
|
1729
|
+
seen.set(file, (seen.get(file) ?? 0) + 1);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
const coOwned = new Set();
|
|
1733
|
+
for (const [file, count] of seen) {
|
|
1734
|
+
if (count > 1)
|
|
1735
|
+
coOwned.add(file);
|
|
1736
|
+
}
|
|
1737
|
+
return coOwned;
|
|
1738
|
+
}
|
|
1739
|
+
// Template-relative directories excluded from the snapshot outright (#4154).
|
|
1740
|
+
// - apps/web/__tests__ — this repo's own harness tests. Several import route
|
|
1741
|
+
// modules across multiple surfaces (resources-downloads-integrations-phase2,
|
|
1742
|
+
// standalone-informational-routes, routes/blog-route, blog-dir-resolution),
|
|
1743
|
+
// so they fail outright in a scaffold whose surfaces are gated off. The
|
|
1744
|
+
// co-located app/[locale]/<surface>/__tests__ suites travel with their
|
|
1745
|
+
// surface and are unaffected.
|
|
1746
|
+
// - apps/web/app/[locale]/__tests__ — same class: page-renderer-migration
|
|
1747
|
+
// reaches across surfaces (`../launch-service/page`), so it breaks in a
|
|
1748
|
+
// scaffold that gated launch-service off. The PER-SURFACE co-located
|
|
1749
|
+
// suites (app/[locale]/<surface>/__tests__) import only their own route and
|
|
1750
|
+
// travel with their surface, so they are kept.
|
|
1751
|
+
// - apps/web/content — the blog/docs sample posts (the launching-ailk class).
|
|
1752
|
+
// Replaced by neutral stubs from template-overlay/.
|
|
1753
|
+
// - apps/web/app/[locale]/(authed)/edit — the Pro content host's editor
|
|
1754
|
+
// routes (#5977; added to apps/web by #5957, spec 5872 FR1/FR2). Both
|
|
1755
|
+
// pages are `// oss: false` and the [type]/[slug] page imports
|
|
1756
|
+
// `@working-theory/admin-ui`, which a keyless (Free) scaffold does not
|
|
1757
|
+
// carry — so shipping them puts two files importing an absent package
|
|
1758
|
+
// into the scaffold and fails both co-located `__tests__` suites under
|
|
1759
|
+
// verify-scaffold's `apps/web` jest run. The directory is taken whole,
|
|
1760
|
+
// `__tests__` with it, since a test of an excluded route has nothing to
|
|
1761
|
+
// test.
|
|
1762
|
+
//
|
|
1763
|
+
// WHY AN EXCLUSION AND NOT A MODULE SLICE. Spec 5872 D11 settled the two
|
|
1764
|
+
// constraints that rule out the alternatives, quoted rather than
|
|
1765
|
+
// re-derived:
|
|
1766
|
+
// 1. "content-write cannot be a MODULE_SLICES key"
|
|
1767
|
+
// (`module-architecture.ts:214-222` — a key would make
|
|
1768
|
+
// `--modules content-write` a valid selection).
|
|
1769
|
+
// 2. "the workspace slice is the wrong owner" (#5853 §4.2/D14 — it
|
|
1770
|
+
// would bind the Pro editor to a Pro Plus bundle).
|
|
1771
|
+
// So there is no correct `ownedFiles` owner for these files today. This
|
|
1772
|
+
// entry is the INTERIM: a flat exclusion that keeps the keyless scaffold
|
|
1773
|
+
// honest until a content-write delivery path exists, at which point the
|
|
1774
|
+
// routes move to that path's owner and this entry comes back out. The
|
|
1775
|
+
// routes stay registered in `ROUTE_SINCE` (src/surfaces.ts) meanwhile —
|
|
1776
|
+
// see that entry, and sync-routes' AC-5 coverage test, which reads this
|
|
1777
|
+
// list so the resulting ROUTE_SINCE-vs-template absence is justified
|
|
1778
|
+
// rather than reported stale.
|
|
1779
|
+
export const EXCLUDE_TEMPLATE_DIRS = [
|
|
1780
|
+
"apps/web/__tests__",
|
|
1781
|
+
"apps/web/app/__tests__",
|
|
1782
|
+
"apps/web/app/[locale]/__tests__",
|
|
1783
|
+
"apps/web/app/[locale]/(authed)/edit",
|
|
1784
|
+
"apps/web/content",
|
|
1785
|
+
];
|
|
1349
1786
|
export function paidModuleTemplateExclusions(snapshotRoots, repoRoot) {
|
|
1350
1787
|
const roots = new Set(snapshotRoots);
|
|
1351
|
-
const
|
|
1788
|
+
const seeds = new Set();
|
|
1352
1789
|
for (const moduleName of PAID_MODULES) {
|
|
1353
1790
|
for (const owned of MODULE_SLICES[moduleName]?.ownedFiles ?? []) {
|
|
1354
1791
|
const rel = owned.split(sep).join("/");
|
|
@@ -1356,103 +1793,11 @@ export function paidModuleTemplateExclusions(snapshotRoots, repoRoot) {
|
|
|
1356
1793
|
continue;
|
|
1357
1794
|
if (rel.includes("*"))
|
|
1358
1795
|
continue;
|
|
1359
|
-
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
// Companion closure by import graph, to a fixed point — never a filename
|
|
1363
|
-
// stem rule (#5182 D7), which misses eleven files and over-marks three.
|
|
1364
|
-
const candidates = listFilesUnder(repoRoot, [...roots]);
|
|
1365
|
-
for (;;) {
|
|
1366
|
-
let grew = false;
|
|
1367
|
-
for (const file of candidates) {
|
|
1368
|
-
if (excluded.has(file))
|
|
1369
|
-
continue;
|
|
1370
|
-
const imports = relativeImportsOf(join(repoRoot, file));
|
|
1371
|
-
for (const spec of imports) {
|
|
1372
|
-
const target = resolveRelativeImport(file, spec, candidates);
|
|
1373
|
-
if (target !== undefined && excluded.has(target)) {
|
|
1374
|
-
excluded.add(file);
|
|
1375
|
-
grew = true;
|
|
1376
|
-
break;
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
if (!grew)
|
|
1381
|
-
break;
|
|
1382
|
-
}
|
|
1383
|
-
return [...excluded].sort();
|
|
1384
|
-
}
|
|
1385
|
-
const SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
1386
|
-
/** Every source file under the given repo-relative roots, as "/"-joined paths. */
|
|
1387
|
-
function listFilesUnder(repoRoot, roots) {
|
|
1388
|
-
const out = new Set();
|
|
1389
|
-
const skip = new Set(["node_modules", ".next", "dist", ".turbo", ".source"]);
|
|
1390
|
-
const stack = roots.map((r) => r);
|
|
1391
|
-
while (stack.length > 0) {
|
|
1392
|
-
const rel = stack.pop();
|
|
1393
|
-
const abs = join(repoRoot, rel);
|
|
1394
|
-
let entries;
|
|
1395
|
-
try {
|
|
1396
|
-
entries = readdirSync(abs, { withFileTypes: true });
|
|
1397
|
-
}
|
|
1398
|
-
catch {
|
|
1399
|
-
continue;
|
|
1400
|
-
}
|
|
1401
|
-
for (const entry of entries) {
|
|
1402
|
-
if (skip.has(entry.name))
|
|
1403
|
-
continue;
|
|
1404
|
-
const childRel = `${rel}/${entry.name}`;
|
|
1405
|
-
if (entry.isDirectory())
|
|
1406
|
-
stack.push(childRel);
|
|
1407
|
-
else if (SOURCE_EXTS.some((e) => entry.name.endsWith(e)))
|
|
1408
|
-
out.add(childRel);
|
|
1796
|
+
seeds.add(rel);
|
|
1409
1797
|
}
|
|
1410
1798
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
let src;
|
|
1416
|
-
try {
|
|
1417
|
-
src = readFileSync(absPath, "utf8");
|
|
1418
|
-
}
|
|
1419
|
-
catch {
|
|
1420
|
-
return [];
|
|
1421
|
-
}
|
|
1422
|
-
const out = [];
|
|
1423
|
-
for (const m of src.matchAll(/(?:^|\n)\s*(?:import|export)[\s\S]{0,400}?from\s*["'](\.[^"']*)["']/g))
|
|
1424
|
-
out.push(m[1]);
|
|
1425
|
-
for (const m of src.matchAll(/\bimport\s*\(\s*["'](\.[^"']*)["']\s*\)/g))
|
|
1426
|
-
out.push(m[1]);
|
|
1427
|
-
return out;
|
|
1428
|
-
}
|
|
1429
|
-
/**
|
|
1430
|
-
* Resolve a relative specifier against the candidate set. TypeScript ESM writes
|
|
1431
|
-
* `./x.js` for `./x.ts`, so the `.js` → `.ts`/`.tsx` rewrite is the common case.
|
|
1432
|
-
*/
|
|
1433
|
-
function resolveRelativeImport(fromFile, spec, candidates) {
|
|
1434
|
-
const base = posixJoin(dirname(fromFile.split("/").join(sep)), spec);
|
|
1435
|
-
const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
|
|
1436
|
-
for (const cand of [
|
|
1437
|
-
base,
|
|
1438
|
-
...SOURCE_EXTS.map((e) => stem + e),
|
|
1439
|
-
...SOURCE_EXTS.map((e) => `${stem}/index${e}`),
|
|
1440
|
-
])
|
|
1441
|
-
if (candidates.has(cand))
|
|
1442
|
-
return cand;
|
|
1443
|
-
return undefined;
|
|
1444
|
-
}
|
|
1445
|
-
/** Join and normalize a "/"-separated path, resolving `.` and `..` segments. */
|
|
1446
|
-
function posixJoin(dir, spec) {
|
|
1447
|
-
const parts = `${dir.split(sep).join("/")}/${spec}`.split("/");
|
|
1448
|
-
const out = [];
|
|
1449
|
-
for (const part of parts) {
|
|
1450
|
-
if (part === "" || part === ".")
|
|
1451
|
-
continue;
|
|
1452
|
-
if (part === "..")
|
|
1453
|
-
out.pop();
|
|
1454
|
-
else
|
|
1455
|
-
out.push(part);
|
|
1456
|
-
}
|
|
1457
|
-
return out.join("/");
|
|
1799
|
+
// Companion closure by import graph, to a fixed point — the shared walker
|
|
1800
|
+
// (`lib/import-graph.ts`), so `tools/lint-slice-registration.ts` asks the
|
|
1801
|
+
// question with the same resolution this answer was computed with (#5701).
|
|
1802
|
+
return [...importClosure(repoRoot, [...roots], seeds)].sort();
|
|
1458
1803
|
}
|