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
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared network-safety guards for `fetch-template.ts` / `fetch-module.ts`
|
|
3
|
+
* (issue #5514, Lows 2 and 5 — a post-merge backstop on #5510's
|
|
4
|
+
* `create-ailk --template` feature).
|
|
5
|
+
*
|
|
6
|
+
* A plain internal helper module, not a shared package: both callers already
|
|
7
|
+
* state at length (see their file docs) why `create-ailk` — the one package
|
|
8
|
+
* in this monorepo published to public npm — cannot take a runtime
|
|
9
|
+
* dependency on anything `restricted`-tier. A sibling file inside
|
|
10
|
+
* `packages/create-ailk/src/lib/` carries no such dependency and is exactly
|
|
11
|
+
* the right place for logic the two fetchers would otherwise duplicate a
|
|
12
|
+
* second time.
|
|
13
|
+
*
|
|
14
|
+
* Three guards live here:
|
|
15
|
+
* - `REQUEST_TIMEOUT_MS` / `fetchTimeoutSignal()` — neither fetcher had a
|
|
16
|
+
* request timeout before this; a hung or slow-drip response could block
|
|
17
|
+
* `create-ailk` forever.
|
|
18
|
+
* - `assertHttpsRegistryUrl()` — neither fetcher validated the scheme of
|
|
19
|
+
* the registry URL (env-var-overridable) it was about to send a bearer
|
|
20
|
+
* JWT to. Rejects any non-`https:` origin, UNLESS the test-mode seam
|
|
21
|
+
* (`NODE_ENV === "test"`) is active — the same seam
|
|
22
|
+
* `template-scaffold.test.ts`'s `run()` helper already relies on when it
|
|
23
|
+
* spreads `process.env` into the CLI subprocess it spawns against the
|
|
24
|
+
* loopback mock registry (`http://127.0.0.1:<port>`). Confirmed
|
|
25
|
+
* empirically: Jest sets `NODE_ENV=test` for its own process (and thus
|
|
26
|
+
* every child it spawns, since `run()` inherits `process.env`) whenever
|
|
27
|
+
* the ambient environment does not already set it — there is no other
|
|
28
|
+
* test-mode flag anywhere in this codebase (`AILK_ALLOW*`, `insecure`,
|
|
29
|
+
* `__TEST__`, etc. do not exist).
|
|
30
|
+
* - `assertContentLengthWithinLimit()` — neither fetcher checked a
|
|
31
|
+
* response's declared size against `MAX_TOTAL_SIZE_BYTES` before buffering
|
|
32
|
+
* the WHOLE body via `.arrayBuffer()`. That cap was previously enforced
|
|
33
|
+
* only downstream, against tar entries, in
|
|
34
|
+
* `extract-module-bundle.ts`'s `safeExtractTarGz` — too late to stop an
|
|
35
|
+
* oversized response from being held in memory first.
|
|
36
|
+
*/
|
|
37
|
+
import { MAX_TOTAL_SIZE_BYTES } from "./extract-module-bundle.js";
|
|
38
|
+
/**
|
|
39
|
+
* Per-request timeout applied to every template/module registry fetch.
|
|
40
|
+
* 30s is generous for a small tarball fetch over a real network while still
|
|
41
|
+
* bounding a hung connection or slow-drip response.
|
|
42
|
+
*/
|
|
43
|
+
export const REQUEST_TIMEOUT_MS = 30_000;
|
|
44
|
+
/** `AbortSignal.timeout(REQUEST_TIMEOUT_MS)` — one call site, one constant. */
|
|
45
|
+
export function fetchTimeoutSignal() {
|
|
46
|
+
return AbortSignal.timeout(REQUEST_TIMEOUT_MS);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `true` iff `hostname` is a loopback host — the ONLY hosts a plain `http:`
|
|
50
|
+
* registry URL is accepted for. The test suite spawns its mock registry on
|
|
51
|
+
* `127.0.0.1`; nothing else needs cleartext. (An earlier revision keyed this
|
|
52
|
+
* on `NODE_ENV=test`, an ambient variable any environment can export — a
|
|
53
|
+
* security control in a public npm package must not carry a kill switch.)
|
|
54
|
+
*/
|
|
55
|
+
function isLoopbackHost(hostname) {
|
|
56
|
+
return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "[::1]" || hostname === "::1";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reject a registry URL whose origin is not `https:`, unless its host is
|
|
60
|
+
* loopback (above) — the mock registry the test suite spawns is deliberately
|
|
61
|
+
* plain `http://127.0.0.1:<port>`. `ErrorCtor` lets each
|
|
62
|
+
* caller throw its own error class (`FetchTemplateError` / `FetchModuleError`)
|
|
63
|
+
* so this is a new FAILURE MODE, never a new error type from the caller's
|
|
64
|
+
* point of view — and never a licence error (`isLicenseError` stays false).
|
|
65
|
+
*/
|
|
66
|
+
export function assertHttpsRegistryUrl(registryUrl, ErrorCtor) {
|
|
67
|
+
let scheme;
|
|
68
|
+
let hostname;
|
|
69
|
+
try {
|
|
70
|
+
const parsed = new URL(registryUrl);
|
|
71
|
+
scheme = parsed.protocol;
|
|
72
|
+
hostname = parsed.hostname;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
throw new ErrorCtor(`refusing to use registry URL "${registryUrl}": not a valid URL`);
|
|
76
|
+
}
|
|
77
|
+
if (scheme !== "https:" && !isLoopbackHost(hostname)) {
|
|
78
|
+
throw new ErrorCtor(`refusing to use registry URL "${registryUrl}": scheme must be https:, got "${scheme}"`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Reject a `Response` whose `Content-Length` header declares a size larger
|
|
83
|
+
* than `MAX_TOTAL_SIZE_BYTES` — called by the caller right after its
|
|
84
|
+
* existing status-code checks succeed, BEFORE `.arrayBuffer()` ever runs, so
|
|
85
|
+
* an oversized body is never buffered into memory. A missing or unparseable
|
|
86
|
+
* `Content-Length` is not itself a violation (a chunked/streamed response may
|
|
87
|
+
* omit it) — this is defense in depth against a declared size, not a
|
|
88
|
+
* replacement for the tar-entry cumulative-size cap `extract-module-bundle.ts`
|
|
89
|
+
* still enforces downstream.
|
|
90
|
+
*/
|
|
91
|
+
export function assertContentLengthWithinLimit(response, ErrorCtor) {
|
|
92
|
+
const header = response.headers.get("content-length");
|
|
93
|
+
if (header === null)
|
|
94
|
+
return;
|
|
95
|
+
const declared = Number(header);
|
|
96
|
+
if (!Number.isFinite(declared))
|
|
97
|
+
return;
|
|
98
|
+
if (declared > MAX_TOTAL_SIZE_BYTES) {
|
|
99
|
+
throw new ErrorCtor(`refusing response: declared Content-Length ${declared} exceeds the ${MAX_TOTAL_SIZE_BYTES}-byte limit`);
|
|
100
|
+
}
|
|
101
|
+
}
|
package/dist/lib/fetch-module.js
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* exit uniformly.
|
|
37
37
|
*/
|
|
38
38
|
import pkg from "../../package.json" with { type: "json" };
|
|
39
|
+
import { assertContentLengthWithinLimit, assertHttpsRegistryUrl, fetchTimeoutSignal, } from "./fetch-guard.js";
|
|
39
40
|
export const DEFAULT_AILK_MODULE_REGISTRY_URL = "https://ailaunchkit.ai/api/modules";
|
|
40
41
|
/**
|
|
41
42
|
* This package's own `package.json` `"version"`. Deliberately a static JSON
|
|
@@ -79,6 +80,7 @@ export async function fetchModule(options) {
|
|
|
79
80
|
const registryUrl = options.registryUrl ??
|
|
80
81
|
process.env["AILK_MODULE_REGISTRY_URL"] ??
|
|
81
82
|
DEFAULT_AILK_MODULE_REGISTRY_URL;
|
|
83
|
+
assertHttpsRegistryUrl(registryUrl, FetchModuleError);
|
|
82
84
|
const url = buildUrl(registryUrl, moduleName, version);
|
|
83
85
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
84
86
|
let response;
|
|
@@ -90,6 +92,7 @@ export async function fetchModule(options) {
|
|
|
90
92
|
Accept: "application/gzip, application/octet-stream",
|
|
91
93
|
},
|
|
92
94
|
redirect: "error",
|
|
95
|
+
signal: fetchTimeoutSignal(),
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
catch (err) {
|
|
@@ -111,6 +114,7 @@ export async function fetchModule(options) {
|
|
|
111
114
|
const body = await safeReadBody(response);
|
|
112
115
|
throw new FetchModuleError(`module registry returned ${response.status} for "${moduleName}": ${body}`);
|
|
113
116
|
}
|
|
117
|
+
assertContentLengthWithinLimit(response, FetchModuleError);
|
|
114
118
|
const buf = await response.arrayBuffer();
|
|
115
119
|
return new Uint8Array(buf);
|
|
116
120
|
}
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* gate the paid path. The registry's own 401 IS the licence verdict.
|
|
27
27
|
*/
|
|
28
28
|
import pkg from "../../package.json" with { type: "json" };
|
|
29
|
+
import { assertContentLengthWithinLimit, assertHttpsRegistryUrl, fetchTimeoutSignal, } from "./fetch-guard.js";
|
|
29
30
|
export const DEFAULT_AILK_TEMPLATE_REGISTRY_URL = "https://ailaunchkit.ai/api/templates";
|
|
30
31
|
/**
|
|
31
32
|
* This package's own `package.json` `"version"` — a static JSON import for
|
|
@@ -66,6 +67,7 @@ export async function fetchTemplate(options) {
|
|
|
66
67
|
const registryUrl = options.registryUrl ??
|
|
67
68
|
process.env["AILK_TEMPLATE_REGISTRY_URL"] ??
|
|
68
69
|
DEFAULT_AILK_TEMPLATE_REGISTRY_URL;
|
|
70
|
+
assertHttpsRegistryUrl(registryUrl, FetchTemplateError);
|
|
69
71
|
const url = buildUrl(registryUrl, templateName, version);
|
|
70
72
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
71
73
|
let response;
|
|
@@ -77,6 +79,7 @@ export async function fetchTemplate(options) {
|
|
|
77
79
|
Accept: "application/gzip, application/octet-stream",
|
|
78
80
|
},
|
|
79
81
|
redirect: "error",
|
|
82
|
+
signal: fetchTimeoutSignal(),
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
85
|
catch (err) {
|
|
@@ -98,6 +101,7 @@ export async function fetchTemplate(options) {
|
|
|
98
101
|
const body = await safeReadBody(response);
|
|
99
102
|
throw new FetchTemplateError(`template registry returned ${response.status} for "${templateName}": ${body}`);
|
|
100
103
|
}
|
|
104
|
+
assertContentLengthWithinLimit(response, FetchTemplateError);
|
|
101
105
|
const buf = await response.arrayBuffer();
|
|
102
106
|
return new Uint8Array(buf);
|
|
103
107
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const SOURCE_EXTS: string[];
|
|
2
|
+
/** Every source file under the given repo-relative roots, as "/"-joined paths. */
|
|
3
|
+
export declare function listFilesUnder(repoRoot: string, roots: string[]): Set<string>;
|
|
4
|
+
/** The relative import specifiers a source file names (static imports + re-exports). */
|
|
5
|
+
export declare function relativeImportsOf(absPath: string): string[];
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a relative specifier against the candidate set. TypeScript ESM writes
|
|
8
|
+
* `./x.js` for `./x.ts`, so the `.js` → `.ts`/`.tsx` rewrite is the common case.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveRelativeImport(fromFile: string, spec: string, candidates: Set<string>): string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* The companion closure of `seeds` under `roots`: the seeds themselves plus
|
|
13
|
+
* every source file under `roots` that reaches one transitively through a
|
|
14
|
+
* relative import, to a fixed point.
|
|
15
|
+
*
|
|
16
|
+
* This is the shape both consumers need, and the reason the walk is shared
|
|
17
|
+
* rather than copied. `paidModuleTemplateExclusions()` seeds it with every
|
|
18
|
+
* paid module's `ownedFiles` to get the files a keyless starter must not
|
|
19
|
+
* carry; `tools/lint-slice-registration.ts` seeds it with the same set to
|
|
20
|
+
* derive, by subtraction, the files a scaffold ships UNCONDITIONALLY.
|
|
21
|
+
*
|
|
22
|
+
* Never a filename-stem rule (#5182 D7), which misses eleven files and
|
|
23
|
+
* over-marks three.
|
|
24
|
+
*
|
|
25
|
+
* @param repoRoot absolute path to the tree being walked.
|
|
26
|
+
* @param roots repo-relative roots the walk is confined to.
|
|
27
|
+
* @param seeds repo-relative, "/"-separated files the closure starts from.
|
|
28
|
+
*/
|
|
29
|
+
export declare function importClosure(repoRoot: string, roots: readonly string[], seeds: Iterable<string>): Set<string>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The relative-import graph walker over a repo-relative source tree.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `module-architecture.ts` (#5701) so the two consumers that
|
|
5
|
+
* need this resolution share ONE implementation rather than two that can
|
|
6
|
+
* disagree:
|
|
7
|
+
*
|
|
8
|
+
* - `paidModuleTemplateExclusions()` (module-architecture.ts) walks it to take
|
|
9
|
+
* the companion closure of every paid module's `ownedFiles` — the files that
|
|
10
|
+
* would ship dangling into a keyless starter.
|
|
11
|
+
* - `tools/lint-slice-registration.ts` walks it to close over the specifiers an
|
|
12
|
+
* `isModuleEnabled("X")` branch in `apps/api/src/server.ts` loads, and to
|
|
13
|
+
* check every reached file against what module X's slice delivers.
|
|
14
|
+
*
|
|
15
|
+
* Both questions are "which files does this one reach through relative
|
|
16
|
+
* imports", and the answer must be the same function in both mouths: a lint
|
|
17
|
+
* that resolved specifiers differently from the exclusion set it checks
|
|
18
|
+
* against would pass on a tree the scaffold cannot boot.
|
|
19
|
+
*
|
|
20
|
+
* The resolution is deliberately TEXTUAL — a regex over import/export
|
|
21
|
+
* specifiers plus a candidate-set lookup, no type-checker and no bundler — so
|
|
22
|
+
* it runs inside `pnpm preflight`'s memory budget.
|
|
23
|
+
*/
|
|
24
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
25
|
+
import { dirname, join, sep } from "node:path";
|
|
26
|
+
export const SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
27
|
+
/** Every source file under the given repo-relative roots, as "/"-joined paths. */
|
|
28
|
+
export function listFilesUnder(repoRoot, roots) {
|
|
29
|
+
const out = new Set();
|
|
30
|
+
const skip = new Set(["node_modules", ".next", "dist", ".turbo", ".source"]);
|
|
31
|
+
const stack = roots.map((r) => r);
|
|
32
|
+
while (stack.length > 0) {
|
|
33
|
+
const rel = stack.pop();
|
|
34
|
+
const abs = join(repoRoot, rel);
|
|
35
|
+
let entries;
|
|
36
|
+
try {
|
|
37
|
+
entries = readdirSync(abs, { withFileTypes: true });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (skip.has(entry.name))
|
|
44
|
+
continue;
|
|
45
|
+
const childRel = `${rel}/${entry.name}`;
|
|
46
|
+
if (entry.isDirectory())
|
|
47
|
+
stack.push(childRel);
|
|
48
|
+
else if (SOURCE_EXTS.some((e) => entry.name.endsWith(e)))
|
|
49
|
+
out.add(childRel);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/** The relative import specifiers a source file names (static imports + re-exports). */
|
|
55
|
+
export function relativeImportsOf(absPath) {
|
|
56
|
+
let src;
|
|
57
|
+
try {
|
|
58
|
+
src = readFileSync(absPath, "utf8");
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const out = [];
|
|
64
|
+
for (const m of src.matchAll(/(?:^|\n)\s*(?:import|export)[\s\S]{0,400}?from\s*["'](\.[^"']*)["']/g))
|
|
65
|
+
out.push(m[1]);
|
|
66
|
+
for (const m of src.matchAll(/\bimport\s*\(\s*["'](\.[^"']*)["']\s*\)/g))
|
|
67
|
+
out.push(m[1]);
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a relative specifier against the candidate set. TypeScript ESM writes
|
|
72
|
+
* `./x.js` for `./x.ts`, so the `.js` → `.ts`/`.tsx` rewrite is the common case.
|
|
73
|
+
*/
|
|
74
|
+
export function resolveRelativeImport(fromFile, spec, candidates) {
|
|
75
|
+
const base = posixJoin(dirname(fromFile.split("/").join(sep)), spec);
|
|
76
|
+
const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
|
|
77
|
+
for (const cand of [
|
|
78
|
+
base,
|
|
79
|
+
...SOURCE_EXTS.map((e) => stem + e),
|
|
80
|
+
...SOURCE_EXTS.map((e) => `${stem}/index${e}`),
|
|
81
|
+
])
|
|
82
|
+
if (candidates.has(cand))
|
|
83
|
+
return cand;
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
/** Join and normalize a "/"-separated path, resolving `.` and `..` segments. */
|
|
87
|
+
function posixJoin(dir, spec) {
|
|
88
|
+
const parts = `${dir.split(sep).join("/")}/${spec}`.split("/");
|
|
89
|
+
const out = [];
|
|
90
|
+
for (const part of parts) {
|
|
91
|
+
if (part === "" || part === ".")
|
|
92
|
+
continue;
|
|
93
|
+
if (part === "..")
|
|
94
|
+
out.pop();
|
|
95
|
+
else
|
|
96
|
+
out.push(part);
|
|
97
|
+
}
|
|
98
|
+
return out.join("/");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The companion closure of `seeds` under `roots`: the seeds themselves plus
|
|
102
|
+
* every source file under `roots` that reaches one transitively through a
|
|
103
|
+
* relative import, to a fixed point.
|
|
104
|
+
*
|
|
105
|
+
* This is the shape both consumers need, and the reason the walk is shared
|
|
106
|
+
* rather than copied. `paidModuleTemplateExclusions()` seeds it with every
|
|
107
|
+
* paid module's `ownedFiles` to get the files a keyless starter must not
|
|
108
|
+
* carry; `tools/lint-slice-registration.ts` seeds it with the same set to
|
|
109
|
+
* derive, by subtraction, the files a scaffold ships UNCONDITIONALLY.
|
|
110
|
+
*
|
|
111
|
+
* Never a filename-stem rule (#5182 D7), which misses eleven files and
|
|
112
|
+
* over-marks three.
|
|
113
|
+
*
|
|
114
|
+
* @param repoRoot absolute path to the tree being walked.
|
|
115
|
+
* @param roots repo-relative roots the walk is confined to.
|
|
116
|
+
* @param seeds repo-relative, "/"-separated files the closure starts from.
|
|
117
|
+
*/
|
|
118
|
+
export function importClosure(repoRoot, roots, seeds) {
|
|
119
|
+
const closed = new Set(seeds);
|
|
120
|
+
const candidates = listFilesUnder(repoRoot, [...roots]);
|
|
121
|
+
for (;;) {
|
|
122
|
+
let grew = false;
|
|
123
|
+
for (const file of candidates) {
|
|
124
|
+
if (closed.has(file))
|
|
125
|
+
continue;
|
|
126
|
+
const imports = relativeImportsOf(join(repoRoot, file));
|
|
127
|
+
for (const spec of imports) {
|
|
128
|
+
const target = resolveRelativeImport(file, spec, candidates);
|
|
129
|
+
if (target !== undefined && closed.has(target)) {
|
|
130
|
+
closed.add(file);
|
|
131
|
+
grew = true;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!grew)
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
return closed;
|
|
140
|
+
}
|
|
@@ -58,7 +58,7 @@ export interface PageRosterRow {
|
|
|
58
58
|
route: string;
|
|
59
59
|
/**
|
|
60
60
|
* Repo-relative seed content this row renders. Absent for an API-backed row
|
|
61
|
-
* (`/
|
|
61
|
+
* (`/meet` renders from the scheduling API, not from an MDX file).
|
|
62
62
|
*/
|
|
63
63
|
content?: readonly string[];
|
|
64
64
|
}
|
|
@@ -105,7 +105,7 @@ export interface ModuleSlice {
|
|
|
105
105
|
* disappears just because one module's slice of it does).
|
|
106
106
|
*
|
|
107
107
|
* One entry in the arrays below is deliberately a GLOB
|
|
108
|
-
* (`"apps-paid/
|
|
108
|
+
* (`"apps-paid/admin/**"`) rather than enumerated file-by-file — a
|
|
109
109
|
* whole app with dozens of files, owned outright by one module; every other
|
|
110
110
|
* entry is a literal file
|
|
111
111
|
* path. A file that a module's own docs mention but that lives inside a
|
|
@@ -128,7 +128,7 @@ export interface ModuleSlice {
|
|
|
128
128
|
* app, never a customer opt-in (see `apps/api/src/config/modules.ts`).
|
|
129
129
|
* - Two are this-list-only and the manifest simply never recorded them:
|
|
130
130
|
* `apps/web/app/[locale]/docs/[[...slug]]/page.tsx` and
|
|
131
|
-
* `apps/web/app/[locale]/
|
|
131
|
+
* `apps/web/app/[locale]/meet/confirmed/page.tsx`.
|
|
132
132
|
*
|
|
133
133
|
* A file's TEST and STORY companions are never listed here (the
|
|
134
134
|
* SOURCE-files-only rule above still holds) but DO carry the marker. They
|
|
@@ -167,13 +167,37 @@ export interface ModuleSlice {
|
|
|
167
167
|
* Every source must be a file the validated tar extraction produced in the
|
|
168
168
|
* bundle producer's staging directory — repo-relative, coinciding with the
|
|
169
169
|
* `ownedFiles`/`installMap`-source paths this module's producer step
|
|
170
|
-
* stages at, by construction. `
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
170
|
+
* stages at, by construction. ONE exception: `build-module-bundles.mjs`
|
|
171
|
+
* also stages the proprietary licence-client LICENSE at the archive root
|
|
172
|
+
* as `LICENSE` and adds its own `installMap["LICENSE"]` entry (never a
|
|
173
|
+
* slice field — the producer adds it uniformly, #5552 D1), so a slice's
|
|
174
|
+
* own `installMap` must not declare a `"LICENSE"` key. `extractModuleBundle`
|
|
175
|
+
* applies this map after the tar entries are validated: an absolute path, a
|
|
176
|
+
* `..` segment, or a path absent from staging rejects the whole bundle, as
|
|
177
|
+
* does a destination that resolves outside the scaffold. A mapped source is
|
|
178
|
+
* copied to its destination only, never also to its original path.
|
|
175
179
|
*/
|
|
176
180
|
installMap?: Record<string, string>;
|
|
181
|
+
/**
|
|
182
|
+
* Rename root for this slice's whole-app glob `ownedFiles` entry(ies)
|
|
183
|
+
* (a `"<dir>/**"` entry — see `ownedFiles`'s own doc above) — the glob
|
|
184
|
+
* sibling of `installMap` (#5644 D1). Every file `expandEntry` yields
|
|
185
|
+
* under `<dir>/` installs at `installRoot + <rel-path-under-dir>` instead
|
|
186
|
+
* of its repo-relative path. `build-module-bundles.mjs`'s
|
|
187
|
+
* `deriveGlobInstallMap` derives one `installMap` entry per file from this
|
|
188
|
+
* rule at bundle-build time, and the mock registry fixture
|
|
189
|
+
* (`__tests__/fixtures/mock-module-registry-server.mjs`) calls the SAME
|
|
190
|
+
* function so its served manifest cannot drift from the producer's.
|
|
191
|
+
* Undefined for a slice with no glob `ownedFiles` entry, or one whose glob
|
|
192
|
+
* files install unchanged at their repo-relative path.
|
|
193
|
+
*
|
|
194
|
+
* `installMap` above stays the mechanism for hand-enumerated, non-glob
|
|
195
|
+
* remaps (see `commerce.installMap`) — a literal map is fine there because
|
|
196
|
+
* enumerating ten skill files costs ten lines; a whole app's worth of
|
|
197
|
+
* files committed one line per file into this OSS-shipped source is the
|
|
198
|
+
* leak class `scripts/check-oss-strip.sh` exists to catch (#5644).
|
|
199
|
+
*/
|
|
200
|
+
installRoot?: string;
|
|
177
201
|
/**
|
|
178
202
|
* Plain text `extractModuleBundle` prints to stdout after a successful
|
|
179
203
|
* merge, with C0/C1 control characters (other than newline) stripped
|
|
@@ -346,4 +370,32 @@ export declare function normalizeModules(modules: string[]): ModuleName[];
|
|
|
346
370
|
* Passed in rather than derived from `import.meta.url`, which ts-jest cannot
|
|
347
371
|
* load — the same reason `sync-routes.ts` documents for staying pure.
|
|
348
372
|
*/
|
|
373
|
+
/**
|
|
374
|
+
* Scaffold destinations that MORE THAN ONE module's `ownedFiles` declares —
|
|
375
|
+
* the co-ownership the `#5618 D4` install-time ownership registry must treat
|
|
376
|
+
* as intentional rather than as an overwrite (#5702 follow-up).
|
|
377
|
+
*
|
|
378
|
+
* Co-ownership is how a file reaches a scaffold under either of two modules
|
|
379
|
+
* without being transferred away from the other. #5677 needed it for the
|
|
380
|
+
* submissions review surface: the routes register under
|
|
381
|
+
* `multi-tenant || signal-collectors`, so BOTH bundles must be able to
|
|
382
|
+
* deliver them, or the module that lacks them throws
|
|
383
|
+
* `ERR_MODULE_NOT_FOUND` during `build()`.
|
|
384
|
+
*
|
|
385
|
+
* `validateLayerOwnership` (`lib/extract-module-bundle.ts`) refuses a
|
|
386
|
+
* destination an earlier layer already wrote, because a silent
|
|
387
|
+
* last-writer-wins between two modules that disagree is the bug `#5618 D4`
|
|
388
|
+
* exists to catch. Two modules that both DECLARE the same repo file are not
|
|
389
|
+
* that case: they stage the same bytes from the same source, so whichever
|
|
390
|
+
* lands second writes what is already there. Without this allowance a
|
|
391
|
+
* scaffold selecting both modules — `saas-product`, whose `requires` names
|
|
392
|
+
* `signal-collectors` AND `multi-tenant` — aborts mid-install, after the
|
|
393
|
+
* first module's files are on disk.
|
|
394
|
+
*
|
|
395
|
+
* Only a DECLARED overlap is allowed. A destination two layers collide on
|
|
396
|
+
* without both naming it in `ownedFiles` is still refused, which is the
|
|
397
|
+
* whole invariant.
|
|
398
|
+
*/
|
|
399
|
+
export declare function coOwnedModuleDestinations(): ReadonlySet<string>;
|
|
400
|
+
export declare const EXCLUDE_TEMPLATE_DIRS: readonly string[];
|
|
349
401
|
export declare function paidModuleTemplateExclusions(snapshotRoots: readonly string[], repoRoot: string): string[];
|