create-ailk 0.21.0 → 0.23.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/component-catalog.json +186 -8
- package/component-catalog.md +9 -7
- package/dist/add-module.js +20 -14
- package/dist/add-route.d.ts +55 -1
- package/dist/add-route.js +294 -12
- package/dist/cli.js +27 -10
- package/dist/derive-architecture.d.ts +12 -3
- package/dist/derive-architecture.js +20 -8
- package/dist/design-package.js +7 -2
- package/dist/lib/design-checks.js +4 -2
- package/dist/lib/env-catalog.js +5 -5
- package/dist/lib/npm-auth.d.ts +9 -0
- package/dist/lib/npm-auth.js +48 -0
- package/dist/lib/scaffold-render-sweep.d.ts +3 -2
- package/dist/lib/scaffold-render-sweep.js +5 -8
- package/dist/module-architecture.js +99 -9
- package/dist/paid-sections.d.ts +21 -2
- package/dist/paid-sections.js +69 -7
- package/dist/programmatic.js +19 -5
- package/dist/seed-flows.d.ts +4 -1
- package/dist/seed-flows.js +50 -4
- package/dist/site-chrome.d.ts +8 -0
- package/dist/site-chrome.js +17 -1
- package/dist/spoke-checkout.d.ts +65 -41
- package/dist/spoke-checkout.js +208 -430
- package/dist/starter-grid.d.ts +0 -3
- package/dist/starter-grid.js +24 -14
- package/dist/surfaces.js +52 -26
- package/dist/sync-routes.d.ts +38 -1
- package/dist/sync-routes.js +187 -13
- package/dist/template-record.d.ts +4 -3
- package/dist/template-record.js +8 -4
- package/dist/topology.js +25 -1
- package/dist/update.js +15 -0
- package/package.json +3 -3
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +4 -49
- package/site-templates/_base/content/en/Pricing/pricing.mdx +3 -21
- package/site-templates/designs/minimalism/DESIGN.md +1 -1
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +23 -20
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +28 -14
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +15 -39
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +38 -34
- package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/templates/.env.example +9 -7
- package/templates/.github/workflows/ci.yml +13 -0
- package/templates/README.md +1 -0
- package/templates/_gitignore +4 -0
- package/templates/apps/api/.env.example +27 -0
- package/templates/apps/api/CLAUDE.md +87 -17
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +2 -0
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +45 -0
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +185 -0
- package/templates/apps/api/src/config/index.ts +109 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
- package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +19 -0
- package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +149 -0
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +116 -0
- package/templates/apps/api/src/lib/consent-store.ts +28 -0
- package/templates/apps/api/src/lib/error-serializer.ts +74 -7
- package/templates/apps/api/src/lib/flow-completion-store.ts +136 -0
- package/templates/apps/api/src/lib/hub-sign-in-store.ts +38 -2
- package/templates/apps/api/src/lib/proposal-paid-store.ts +21 -4
- package/templates/apps/api/src/lib/stripe.ts +74 -4
- package/templates/apps/api/src/lib/webhook-idempotency.ts +66 -2
- package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +14 -3
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +218 -0
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +174 -0
- package/templates/apps/api/src/middleware/auth.ts +13 -6
- package/templates/apps/api/src/middleware/rate-limit.ts +226 -4
- package/templates/apps/api/src/openapi/spec.ts +33 -3
- package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +49 -0
- package/templates/apps/api/src/routes/auth/hub-sign-in.ts +41 -0
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +325 -0
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +1300 -0
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +49 -0
- package/templates/apps/api/src/routes/checkout/session.ts +57 -25
- package/templates/apps/api/src/routes/checkout/sessions.ts +232 -82
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +386 -0
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +160 -0
- package/templates/apps/api/src/routes/consent/account.ts +268 -0
- package/templates/apps/api/src/routes/consent/index.ts +15 -7
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +36 -0
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +731 -0
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +753 -0
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +762 -0
- package/templates/apps/api/src/routes/content/get-page.ts +4 -0
- package/templates/apps/api/src/routes/content/index.ts +16 -2
- package/templates/apps/api/src/routes/content/offerings.ts +184 -0
- package/templates/apps/api/src/routes/content/pricing.ts +176 -0
- package/templates/apps/api/src/routes/content/shown-offerings.ts +229 -0
- package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +515 -0
- package/templates/apps/api/src/routes/leads/index.ts +164 -7
- package/templates/apps/api/src/routes/webhooks/README.md +66 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +649 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +814 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +80 -68
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +5 -5
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +8 -2
- package/templates/apps/api/src/routes/webhooks/index.ts +23 -0
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +384 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +245 -36
- package/templates/apps/api/src/server.ts +163 -46
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +313 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +51 -2
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +234 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +1383 -133
- package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +389 -0
- package/templates/apps/api/src/services/__tests__/person.test.ts +232 -1
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +444 -0
- package/templates/apps/api/src/services/checkout-buyer.ts +100 -4
- package/templates/apps/api/src/services/consent.ts +95 -0
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +13 -5
- package/templates/apps/api/src/services/entitlements.ts +157 -1
- package/templates/apps/api/src/services/lead-routing.ts +431 -47
- package/templates/apps/api/src/services/magnet-completion.ts +242 -0
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +295 -0
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +268 -0
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +868 -0
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +416 -0
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +396 -0
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +681 -0
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +231 -0
- package/templates/apps/api/src/services/offerings/catalog.ts +308 -0
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +385 -0
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +192 -0
- package/templates/apps/api/src/services/offerings/connection.ts +1003 -0
- package/templates/apps/api/src/services/offerings/index.ts +614 -0
- package/templates/apps/api/src/services/offerings/source.ts +140 -0
- package/templates/apps/api/src/services/offerings/store.ts +150 -0
- package/templates/apps/api/src/services/person.ts +164 -17
- package/templates/apps/api/src/services/plan-offerings.ts +125 -0
- package/templates/apps/api/src/services/public-site-resolver.ts +27 -15
- package/templates/apps/mcp/CLAUDE.md +22 -14
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +9 -4
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +358 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +364 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +4 -4
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +2 -2
- package/templates/apps/mcp/__tests__/server.test.ts +13 -11
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +208 -12
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +11 -11
- package/templates/apps/mcp/src/lib/shown-offerings.ts +105 -0
- package/templates/apps/mcp/src/server.ts +5 -0
- package/templates/apps/mcp/src/tools/get_offerings.ts +47 -30
- package/templates/apps/mcp/src/tools/get_pricing.ts +40 -40
- package/templates/apps/mcp/src/tools/purchase.ts +30 -2
- package/templates/apps/mcp/src/workspace-server.ts +15 -0
- package/templates/apps/web/.env.example +24 -31
- package/templates/apps/web/CLAUDE.md +393 -9
- package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +6 -2
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +5 -4
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +5 -1
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +2 -0
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +3 -14
- package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +2 -0
- package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +5 -1
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +160 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/sign-in-card.test.tsx +12 -9
- package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +105 -2
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +36 -3
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +47 -1
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +60 -22
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +16 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +85 -31
- package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +18 -4
- package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +3 -1
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +7 -4
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +227 -207
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout-sign-out.test.tsx +17 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +143 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-menu.test.tsx +4 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +385 -89
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/popups.test.tsx +5 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +44 -5
- package/templates/apps/web/app/[locale]/(authed)/account/account-frame.tsx +68 -34
- package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +0 -8
- package/templates/apps/web/app/[locale]/(authed)/account/agreements-actions.ts +39 -151
- package/templates/apps/web/app/[locale]/(authed)/account/agreements-gate.ts +61 -0
- package/templates/apps/web/app/[locale]/(authed)/account/agreements-prompt.tsx +143 -140
- package/templates/apps/web/app/[locale]/(authed)/account/layout.tsx +40 -6
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +68 -54
- package/templates/apps/web/app/[locale]/(authed)/account/privacy/page.tsx +5 -1
- package/templates/apps/web/app/[locale]/careers/[slug]/[action]/page.tsx +189 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +295 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +120 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +23 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +319 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-hub.test.tsx +172 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-set.test.tsx +149 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +141 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +424 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +72 -11
- package/templates/apps/web/app/[locale]/careers/page.tsx +129 -5
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/checkout/__tests__/pages.test.tsx +139 -0
- package/templates/apps/web/app/[locale]/checkout/__tests__/thank-you-account.test.tsx +136 -0
- package/templates/apps/web/app/[locale]/checkout/thank-you/page.tsx +114 -0
- package/templates/apps/web/app/[locale]/checkout/unavailable/page.tsx +51 -0
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +17 -1
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +79 -4
- package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +160 -13
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +466 -36
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +7 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +172 -57
- package/templates/apps/web/app/[locale]/contact/intake-script.ts +26 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +99 -60
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +341 -4
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.count.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.deliverable.test.tsx +200 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.ending.test.tsx +197 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.invite.test.tsx +257 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/account-invite.actions.test.ts +69 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +430 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +21 -9
- package/templates/apps/web/app/[locale]/flows/[slug]/account-invite.actions.ts +35 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +352 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +12 -73
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +10 -31
- package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/layout.tsx +55 -4
- package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +174 -104
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +95 -58
- package/templates/apps/web/app/[locale]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap +7 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/offerings.test.tsx +599 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/page.test.tsx +216 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +236 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +367 -6
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +4 -1
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/thanks/[slug]/AccountInviteLink.tsx +89 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/AccountInviteLink.test.tsx +104 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +38 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +17 -0
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +62 -3
- package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +70 -18
- package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +30 -9
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/api/auth/hub/authorize/__tests__/route.test.ts +114 -0
- package/templates/apps/web/app/api/auth/hub/authorize/route.ts +20 -3
- package/templates/apps/web/app/api/hub-session/__tests__/routes.test.ts +44 -1
- package/templates/apps/web/app/api/hub-session/sign-in/route.ts +22 -3
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +316 -0
- package/templates/apps/web/app/api/offerings/checkout/__tests__/route.test.ts +810 -0
- package/templates/apps/web/auth.ts +28 -2
- package/templates/apps/web/lib/__tests__/account-invite.test.ts +63 -0
- package/templates/apps/web/lib/__tests__/auth-routes.test.ts +27 -1
- package/templates/apps/web/lib/__tests__/consent-policies.test.ts +23 -0
- package/templates/apps/web/lib/__tests__/deck-page.test.ts +7 -1
- package/templates/apps/web/lib/__tests__/in-page-magnet.test.ts +265 -0
- package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +57 -0
- package/templates/apps/web/lib/__tests__/newsletter.actions.test.ts +293 -0
- package/templates/apps/web/lib/__tests__/offerings-pricing.test.ts +601 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +101 -25
- package/templates/apps/web/lib/account-invite.ts +37 -0
- package/templates/apps/web/lib/auth-routes.ts +36 -2
- package/templates/apps/web/lib/checkout-config.ts +16 -0
- package/templates/apps/web/lib/consent-policies.ts +22 -0
- package/templates/apps/web/lib/deck-page.ts +7 -0
- package/templates/apps/web/lib/deliverable-grant.ts +18 -0
- package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +111 -0
- package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +88 -32
- package/templates/apps/web/lib/in-page-magnet.ts +416 -0
- package/templates/apps/web/lib/magnet-routes.ts +42 -0
- package/templates/apps/web/lib/modules.generated.ts +9 -0
- package/templates/apps/web/lib/newsletter.actions.ts +202 -0
- package/templates/apps/web/lib/offerings-pricing.ts +326 -0
- package/templates/apps/web/lib/posting-title.ts +17 -0
- package/templates/apps/web/lib/prisma-for-auth.ts +8 -0
- package/templates/apps/web/lib/sign-up-agreements.ts +449 -0
- package/templates/apps/web/lib/site-chrome.ts +2 -0
- package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
- package/templates/apps/web/messages/en.json +71 -20
- package/templates/apps/web/middleware.ts +12 -2
- package/templates/apps/web/package.json +1 -0
- package/templates/apps/web/security-headers.config.ts +17 -0
- package/templates/apps/web/src/lib/__tests__/lead-write.test.ts +187 -0
- package/templates/apps/web/src/lib/__tests__/rate-limit.test.ts +67 -0
- package/templates/apps/web/src/lib/lead-write.ts +90 -0
- package/templates/apps/web/src/lib/rate-limit.ts +79 -0
- package/templates/content/en/BlogList/blog.mdx +4 -71
- package/templates/content/en/BookCall/book-a-call.mdx +1 -41
- package/templates/content/en/BookCall/onsite-estimate.mdx +1 -17
- package/templates/content/en/BookCall/onsite-service.mdx +1 -17
- package/templates/content/en/BookCall/start-project.mdx +1 -17
- package/templates/content/en/ContactPage/contact.mdx +6 -63
- package/templates/content/en/HomePage/home.mdx +3 -21
- package/templates/database/CHANGELOG.md +69 -0
- package/templates/database/__tests__/consent-source-checkout-migration.test.ts +79 -0
- package/templates/database/__tests__/flow-completion-migration.test.ts +115 -0
- package/templates/database/__tests__/flow-completion.db.test.ts +136 -0
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +161 -0
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +270 -0
- package/templates/database/__tests__/offerings-migration.test.ts +197 -0
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +86 -0
- package/templates/database/__tests__/offerings.db.test.ts +303 -0
- package/templates/database/__tests__/seed.test.ts +64 -1
- package/templates/database/auth/schema.prisma +4 -0
- package/templates/database/config/schema.prisma +91 -0
- package/templates/database/inbox/schema.prisma +17 -2
- package/templates/database/migrations/20261018120000_flow_completion/migration.sql +52 -0
- package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +27 -0
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +146 -0
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +77 -0
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +45 -0
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +47 -0
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +16 -0
- package/templates/database/package.json +1 -1
- package/templates/database/seed.ts +62 -3
- package/versions.json +35 -35
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -199
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up.actions.ts +0 -125
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +0 -93
- package/templates/apps/web/app/[locale]/downloads/page.tsx +0 -37
- package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +0 -139
- package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +0 -93
- package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +0 -120
- package/templates/apps/web/lib/meeting-slugs.ts +0 -63
package/component-catalog.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"importPath": "@working-theory/ui/sections",
|
|
10
10
|
"rootBarrel": "@working-theory/ui",
|
|
11
11
|
"sourceRoot": "packages/ui/src/sections",
|
|
12
|
-
"count":
|
|
12
|
+
"count": 57
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": "blocks",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"importPath": "@working-theory/ui/blocks",
|
|
18
18
|
"rootBarrel": "@working-theory/ui",
|
|
19
19
|
"sourceRoot": "packages/ui/src/blocks",
|
|
20
|
-
"count":
|
|
20
|
+
"count": 107
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"name": "chrome",
|
|
@@ -485,6 +485,17 @@
|
|
|
485
485
|
"descriptionGrade": "strong",
|
|
486
486
|
"sectionType": "items"
|
|
487
487
|
},
|
|
488
|
+
{
|
|
489
|
+
"name": "ItemsFilterIsland",
|
|
490
|
+
"tier": "sections",
|
|
491
|
+
"sourcePath": "packages/ui/src/sections/ItemsFilterIsland.tsx",
|
|
492
|
+
"importPath": "@working-theory/ui/sections",
|
|
493
|
+
"exported": false,
|
|
494
|
+
"description": "A search box and facet selects over an items section's cards. Items (a Server Component) renders every card on the server and wraps each in an `ItemsFilterSlot`; the island only decides which slots show. So every card is in the server HTML, and before hydration (or with no JavaScript) every slot is visible.",
|
|
495
|
+
"descriptionSource": "doc-comment",
|
|
496
|
+
"descriptionGrade": "strong",
|
|
497
|
+
"sectionType": null
|
|
498
|
+
},
|
|
488
499
|
{
|
|
489
500
|
"name": "ItemsTileLinkIsland",
|
|
490
501
|
"tier": "sections",
|
|
@@ -837,6 +848,17 @@
|
|
|
837
848
|
"descriptionGrade": "strong",
|
|
838
849
|
"sectionType": null
|
|
839
850
|
},
|
|
851
|
+
{
|
|
852
|
+
"name": "AuthBackLink",
|
|
853
|
+
"tier": "blocks",
|
|
854
|
+
"sourcePath": "packages/ui/src/blocks/AuthBackLink.tsx",
|
|
855
|
+
"importPath": "@working-theory/ui/blocks",
|
|
856
|
+
"exported": true,
|
|
857
|
+
"description": "The auth shell's top-start \"← Back to <site>\". A hub's sign-in page renders it when the visitor arrived from a registered spoke, so the cross-domain handoff names where they came from and gives them the way back.",
|
|
858
|
+
"descriptionSource": "doc-comment",
|
|
859
|
+
"descriptionGrade": "strong",
|
|
860
|
+
"sectionType": null
|
|
861
|
+
},
|
|
840
862
|
{
|
|
841
863
|
"name": "AuthCard",
|
|
842
864
|
"tier": "blocks",
|
|
@@ -1415,7 +1437,7 @@
|
|
|
1415
1437
|
"sourcePath": "packages/ui/src/blocks/NewsletterFormInline.tsx",
|
|
1416
1438
|
"importPath": "@working-theory/ui/blocks",
|
|
1417
1439
|
"exported": true,
|
|
1418
|
-
"description": "Inline email signup form: email Input + submit Button side-by-side at
|
|
1440
|
+
"description": "Inline email signup form: email Input + submit Button side-by-side at md+, stacked on mobile (input full-width on its own row, Subscribe below). Manages its own submit state so the parent Newsletter section can remain RSC-oriented (only this block needs the client boundary).",
|
|
1419
1441
|
"descriptionSource": "doc-comment",
|
|
1420
1442
|
"descriptionGrade": "strong",
|
|
1421
1443
|
"sectionType": null
|
|
@@ -4784,6 +4806,30 @@
|
|
|
4784
4806
|
"alt"
|
|
4785
4807
|
]
|
|
4786
4808
|
},
|
|
4809
|
+
"avatar": {
|
|
4810
|
+
"type": "object",
|
|
4811
|
+
"properties": {
|
|
4812
|
+
"src": {
|
|
4813
|
+
"type": "string"
|
|
4814
|
+
},
|
|
4815
|
+
"alt": {
|
|
4816
|
+
"type": "string"
|
|
4817
|
+
},
|
|
4818
|
+
"width": {
|
|
4819
|
+
"type": "number"
|
|
4820
|
+
},
|
|
4821
|
+
"height": {
|
|
4822
|
+
"type": "number"
|
|
4823
|
+
},
|
|
4824
|
+
"blurDataURL": {
|
|
4825
|
+
"type": "string"
|
|
4826
|
+
}
|
|
4827
|
+
},
|
|
4828
|
+
"required": [
|
|
4829
|
+
"src",
|
|
4830
|
+
"alt"
|
|
4831
|
+
]
|
|
4832
|
+
},
|
|
4787
4833
|
"logoStrip": {
|
|
4788
4834
|
"type": "object",
|
|
4789
4835
|
"properties": {
|
|
@@ -5324,6 +5370,17 @@
|
|
|
5324
5370
|
"body"
|
|
5325
5371
|
]
|
|
5326
5372
|
}
|
|
5373
|
+
},
|
|
5374
|
+
"facets": {
|
|
5375
|
+
"type": "object",
|
|
5376
|
+
"propertyNames": {
|
|
5377
|
+
"type": "string"
|
|
5378
|
+
},
|
|
5379
|
+
"additionalProperties": {
|
|
5380
|
+
"type": "string",
|
|
5381
|
+
"minLength": 1,
|
|
5382
|
+
"maxLength": 80
|
|
5383
|
+
}
|
|
5327
5384
|
}
|
|
5328
5385
|
},
|
|
5329
5386
|
"required": [
|
|
@@ -5331,6 +5388,13 @@
|
|
|
5331
5388
|
]
|
|
5332
5389
|
}
|
|
5333
5390
|
},
|
|
5391
|
+
"gapAbove": {
|
|
5392
|
+
"type": "string",
|
|
5393
|
+
"enum": [
|
|
5394
|
+
"default",
|
|
5395
|
+
"tight"
|
|
5396
|
+
]
|
|
5397
|
+
},
|
|
5334
5398
|
"surface": {
|
|
5335
5399
|
"type": "string",
|
|
5336
5400
|
"enum": [
|
|
@@ -5349,6 +5413,76 @@
|
|
|
5349
5413
|
"card",
|
|
5350
5414
|
"plain"
|
|
5351
5415
|
]
|
|
5416
|
+
},
|
|
5417
|
+
"filter": {
|
|
5418
|
+
"type": "object",
|
|
5419
|
+
"properties": {
|
|
5420
|
+
"searchLabel": {
|
|
5421
|
+
"type": "string",
|
|
5422
|
+
"minLength": 1,
|
|
5423
|
+
"maxLength": 80
|
|
5424
|
+
},
|
|
5425
|
+
"facets": {
|
|
5426
|
+
"maxItems": 4,
|
|
5427
|
+
"type": "array",
|
|
5428
|
+
"items": {
|
|
5429
|
+
"type": "object",
|
|
5430
|
+
"properties": {
|
|
5431
|
+
"key": {
|
|
5432
|
+
"type": "string",
|
|
5433
|
+
"pattern": "^[a-z][a-z0-9-]{0,31}$"
|
|
5434
|
+
},
|
|
5435
|
+
"label": {
|
|
5436
|
+
"type": "string",
|
|
5437
|
+
"minLength": 1,
|
|
5438
|
+
"maxLength": 80
|
|
5439
|
+
},
|
|
5440
|
+
"allLabel": {
|
|
5441
|
+
"type": "string",
|
|
5442
|
+
"minLength": 1,
|
|
5443
|
+
"maxLength": 80
|
|
5444
|
+
}
|
|
5445
|
+
},
|
|
5446
|
+
"required": [
|
|
5447
|
+
"key",
|
|
5448
|
+
"label",
|
|
5449
|
+
"allLabel"
|
|
5450
|
+
],
|
|
5451
|
+
"additionalProperties": false
|
|
5452
|
+
}
|
|
5453
|
+
},
|
|
5454
|
+
"emptyText": {
|
|
5455
|
+
"type": "string",
|
|
5456
|
+
"minLength": 1,
|
|
5457
|
+
"maxLength": 200
|
|
5458
|
+
},
|
|
5459
|
+
"countText": {
|
|
5460
|
+
"type": "object",
|
|
5461
|
+
"properties": {
|
|
5462
|
+
"one": {
|
|
5463
|
+
"type": "string",
|
|
5464
|
+
"minLength": 1,
|
|
5465
|
+
"maxLength": 80
|
|
5466
|
+
},
|
|
5467
|
+
"other": {
|
|
5468
|
+
"type": "string",
|
|
5469
|
+
"minLength": 1,
|
|
5470
|
+
"maxLength": 80
|
|
5471
|
+
}
|
|
5472
|
+
},
|
|
5473
|
+
"required": [
|
|
5474
|
+
"one",
|
|
5475
|
+
"other"
|
|
5476
|
+
],
|
|
5477
|
+
"additionalProperties": false
|
|
5478
|
+
}
|
|
5479
|
+
},
|
|
5480
|
+
"required": [
|
|
5481
|
+
"searchLabel",
|
|
5482
|
+
"emptyText",
|
|
5483
|
+
"countText"
|
|
5484
|
+
],
|
|
5485
|
+
"additionalProperties": false
|
|
5352
5486
|
}
|
|
5353
5487
|
},
|
|
5354
5488
|
"required": [
|
|
@@ -5364,7 +5498,8 @@
|
|
|
5364
5498
|
"separation",
|
|
5365
5499
|
"gap",
|
|
5366
5500
|
"surface",
|
|
5367
|
-
"itemStyle"
|
|
5501
|
+
"itemStyle",
|
|
5502
|
+
"gapAbove"
|
|
5368
5503
|
]
|
|
5369
5504
|
},
|
|
5370
5505
|
{
|
|
@@ -5393,6 +5528,9 @@
|
|
|
5393
5528
|
"headline": {
|
|
5394
5529
|
"type": "string"
|
|
5395
5530
|
},
|
|
5531
|
+
"subtitle": {
|
|
5532
|
+
"type": "string"
|
|
5533
|
+
},
|
|
5396
5534
|
"body": {
|
|
5397
5535
|
"type": "string"
|
|
5398
5536
|
},
|
|
@@ -6753,6 +6891,9 @@
|
|
|
6753
6891
|
"annualBadge": {
|
|
6754
6892
|
"type": "string"
|
|
6755
6893
|
},
|
|
6894
|
+
"annualCtaHref": {
|
|
6895
|
+
"type": "string"
|
|
6896
|
+
},
|
|
6756
6897
|
"priceSubheadAccent": {
|
|
6757
6898
|
"type": "string"
|
|
6758
6899
|
},
|
|
@@ -6985,6 +7126,9 @@
|
|
|
6985
7126
|
"annualBadge": {
|
|
6986
7127
|
"type": "string"
|
|
6987
7128
|
},
|
|
7129
|
+
"annualCtaHref": {
|
|
7130
|
+
"type": "string"
|
|
7131
|
+
},
|
|
6988
7132
|
"priceSubheadAccent": {
|
|
6989
7133
|
"type": "string"
|
|
6990
7134
|
},
|
|
@@ -10713,6 +10857,13 @@
|
|
|
10713
10857
|
"hideEventTypeDetails": {
|
|
10714
10858
|
"type": "boolean"
|
|
10715
10859
|
},
|
|
10860
|
+
"gapAbove": {
|
|
10861
|
+
"type": "string",
|
|
10862
|
+
"enum": [
|
|
10863
|
+
"default",
|
|
10864
|
+
"tight"
|
|
10865
|
+
]
|
|
10866
|
+
},
|
|
10716
10867
|
"fallback": {
|
|
10717
10868
|
"default": "auto",
|
|
10718
10869
|
"type": "string",
|
|
@@ -10734,7 +10885,8 @@
|
|
|
10734
10885
|
"look": [
|
|
10735
10886
|
"surface",
|
|
10736
10887
|
"height",
|
|
10737
|
-
"layout"
|
|
10888
|
+
"layout",
|
|
10889
|
+
"gapAbove"
|
|
10738
10890
|
]
|
|
10739
10891
|
},
|
|
10740
10892
|
{
|
|
@@ -11522,13 +11674,19 @@
|
|
|
11522
11674
|
"no-outline",
|
|
11523
11675
|
"no-download",
|
|
11524
11676
|
"no-print",
|
|
11525
|
-
"no-share"
|
|
11677
|
+
"no-share",
|
|
11678
|
+
"no-zoom",
|
|
11679
|
+
"no-fullscreen"
|
|
11526
11680
|
]
|
|
11527
11681
|
}
|
|
11528
11682
|
},
|
|
11529
11683
|
"downloadFilename": {
|
|
11530
11684
|
"type": "string"
|
|
11531
11685
|
},
|
|
11686
|
+
"shareUrl": {
|
|
11687
|
+
"type": "string",
|
|
11688
|
+
"format": "uri"
|
|
11689
|
+
},
|
|
11532
11690
|
"surface": {
|
|
11533
11691
|
"type": "string",
|
|
11534
11692
|
"enum": [
|
|
@@ -12177,7 +12335,7 @@
|
|
|
12177
12335
|
"groups": [
|
|
12178
12336
|
{
|
|
12179
12337
|
"name": "colors",
|
|
12180
|
-
"leafCount":
|
|
12338
|
+
"leafCount": 64,
|
|
12181
12339
|
"leaves": [
|
|
12182
12340
|
{
|
|
12183
12341
|
"path": "colors.light.bg",
|
|
@@ -12199,6 +12357,11 @@
|
|
|
12199
12357
|
"type": "string",
|
|
12200
12358
|
"value": "#475569"
|
|
12201
12359
|
},
|
|
12360
|
+
{
|
|
12361
|
+
"path": "colors.light.link",
|
|
12362
|
+
"type": "string",
|
|
12363
|
+
"value": "#2563eb"
|
|
12364
|
+
},
|
|
12202
12365
|
{
|
|
12203
12366
|
"path": "colors.light.textMuted",
|
|
12204
12367
|
"type": "string",
|
|
@@ -12354,6 +12517,11 @@
|
|
|
12354
12517
|
"type": "string",
|
|
12355
12518
|
"value": "#94a3b8"
|
|
12356
12519
|
},
|
|
12520
|
+
{
|
|
12521
|
+
"path": "colors.dark.link",
|
|
12522
|
+
"type": "string",
|
|
12523
|
+
"value": "#60a5fa"
|
|
12524
|
+
},
|
|
12357
12525
|
{
|
|
12358
12526
|
"path": "colors.dark.textMuted",
|
|
12359
12527
|
"type": "string",
|
|
@@ -13187,7 +13355,7 @@
|
|
|
13187
13355
|
},
|
|
13188
13356
|
{
|
|
13189
13357
|
"name": "spacing",
|
|
13190
|
-
"leafCount":
|
|
13358
|
+
"leafCount": 15,
|
|
13191
13359
|
"leaves": [
|
|
13192
13360
|
{
|
|
13193
13361
|
"path": "spacing.controlX",
|
|
@@ -13234,6 +13402,16 @@
|
|
|
13234
13402
|
"type": "string",
|
|
13235
13403
|
"value": "1rem"
|
|
13236
13404
|
},
|
|
13405
|
+
{
|
|
13406
|
+
"path": "spacing.deckLabelLine",
|
|
13407
|
+
"type": "string",
|
|
13408
|
+
"value": "var(--spacing-section-lg)"
|
|
13409
|
+
},
|
|
13410
|
+
{
|
|
13411
|
+
"path": "spacing.deckActionLine",
|
|
13412
|
+
"type": "string",
|
|
13413
|
+
"value": "calc(2 * (var(--control-height-big) + var(--spacing-block-tight)))"
|
|
13414
|
+
},
|
|
13237
13415
|
{
|
|
13238
13416
|
"path": "spacing.paragraph",
|
|
13239
13417
|
"type": "string",
|
package/component-catalog.md
CHANGED
|
@@ -15,13 +15,13 @@ The component inventory of `@working-theory/ui` and the shells of `@working-theo
|
|
|
15
15
|
3. Check the Primitives, Panels and Shells tables too — a low-level control, a collapsible layout container, or a route-level frame lives there, not under Sections or Blocks.
|
|
16
16
|
4. Only then build. If you do build, you are declaring the capability is genuinely absent.
|
|
17
17
|
|
|
18
|
-
Inventory: **
|
|
18
|
+
Inventory: **321 component files** across 16 tiers — 57 sections, 107 blocks, 19 chrome, 79 primitives, 6 panels, 8 shells, 5 docs-blog-blocks, 1 docs-blog-chrome, 2 docs-blog-shells, 2 scheduling-sections, 6 scheduling-blocks, 5 signal-collectors-sections, 9 signal-collectors-blocks, 2 commerce-sections, 12 commerce-blocks, 1 commerce-panels. 318 distinct names: `SchedulerEmbed`, `Separator`, `Tabs` exist in more than one tier as genuinely different components, listed once per tier with its own source path.
|
|
19
19
|
|
|
20
|
-
Description coverage: **
|
|
20
|
+
Description coverage: **317/321** components carry a capability description derived from source — 44 from the section registry's hand-authored when-to-use text, 238 from the component's own doc-comment header, 35 from its tier barrel's roster line. **4** have none; they are listed under [Undescribed components](#undescribed-components) rather than given a sentence invented from their name.
|
|
21
21
|
|
|
22
|
-
Of those, **
|
|
22
|
+
Of those, **283** are *strong* — a capability sentence you could match a requirement against — and **34** are *weak*: either one short clause, or a long one that spends itself on wiring (client boundaries, class names, which primitives it composes) instead of on what the thing is for. Weak rows are marked `(weak)` and listed in full under [Weak descriptions](#weak-descriptions). Coverage is 99%, but **findable-without-luck coverage is 88%**.
|
|
23
23
|
|
|
24
|
-
Per tier, strong out of total: **Sections**
|
|
24
|
+
Per tier, strong out of total: **Sections** 56/57 · **Blocks** 99/107 · **Chrome** 10/19 · **Primitives** 64/79 (4 undescribed) · **Panels** 5/6 · **Shells** 7/8 · **Docs + Blog Blocks** 5/5 · **Docs + Blog Chrome** 1/1 · **Docs + Blog Shells** 0/2 · **Scheduling Sections** 2/2 · **Scheduling Blocks** 6/6 · **Signal-Collectors Sections** 5/5 · **Signal-Collectors Blocks** 8/9 · **Commerce Sections** 2/2 · **Commerce Blocks** 12/12 · **Commerce Panels** 1/1. A tier low on this line is a tier where a capability search is most likely to come up empty on something that exists.
|
|
25
25
|
|
|
26
26
|
That grade is **mechanical**. It counts what it can measure — how much a description adds beyond the component's own name, how much of it is spent on wiring, whether the extraction came out damaged — and it cannot tell a fluent paragraph about the wrong subject from a useful one. A person reading these tables will find more rows unusable than the weak count admits. Treat it as a floor on the problem, not a measurement of it, and read the source before concluding a capability is absent.
|
|
27
27
|
|
|
@@ -53,7 +53,7 @@ The left column is search vocabulary — how a person phrases the need. It is ha
|
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
56
|
-
## Sections (
|
|
56
|
+
## Sections (57)
|
|
57
57
|
|
|
58
58
|
Page-level content bands. Most are MDX-driven (authored by `type` in page frontmatter and dispatched by `SectionRenderer`); a few are composed directly in a route.
|
|
59
59
|
|
|
@@ -93,6 +93,7 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
|
|
|
93
93
|
| `HeroPromptCapture` | The Hero `promptCapture` opt-in's wiring. Composes the two new blocks — `PromptCaptureCard` (the chat-style card) and `SuggestionChipCarousel` (the one-expanded-slot chip row) — and owns the ONE piece of state they share: the typed text. A chip click writes into it; the card renders and edits it; submit carries it onward. | `import { HeroPromptCapture } from "@working-theory/ui/sections"` |
|
|
94
94
|
| `HeroQuickSearch` | Surfaces the existing ⌘K quick-search as an inline trigger inside the hero CTA cluster (Chassis 2). It does NOT re-roll a search input: it composes the SearchInputTrigger primitive (an input-style control at CTA height) plus the Command palette primitive, so there is ONE search mechanism. The nav's compact 24px ⌘K pill stays as-is — the hero reads as a search INPUT, matching the 44px "Get Started" CTA. | internal — compose from `packages/ui/src/sections/HeroQuickSearch.tsx` |
|
|
95
95
|
| `Items` | A general-purpose card/items grid — use for services, use cases, or any homogeneous list of cards. | MDX `type: items` · `import { Items } from "@working-theory/ui/sections"` |
|
|
96
|
+
| `ItemsFilterIsland` | A search box and facet selects over an items section's cards. Items (a Server Component) renders every card on the server and wraps each in an `ItemsFilterSlot`; the island only decides which slots show. So every card is in the server HTML, and before hydration (or with no JavaScript) every slot is visible. | internal — compose from `packages/ui/src/sections/ItemsFilterIsland.tsx` |
|
|
96
97
|
| `ItemsTileLinkIsland` | Makes a whole linked tile card its link's click target. | internal — compose from `packages/ui/src/sections/ItemsTileLinkIsland.tsx` |
|
|
97
98
|
| `LogoCloud` | A customer/partner logo wall — use for trust-by-association social proof. | MDX `type: logoCloud` · `import { LogoCloud } from "@working-theory/ui/sections"` |
|
|
98
99
|
| `MDXContent` | The keystone the docs route and blog both render their compiled MDX through. | `import { MDXContent } from "@working-theory/ui/sections"` |
|
|
@@ -120,7 +121,7 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
|
|
|
120
121
|
|
|
121
122
|
---
|
|
122
123
|
|
|
123
|
-
## Blocks (
|
|
124
|
+
## Blocks (107)
|
|
124
125
|
|
|
125
126
|
Intermediate composition tiles — the pieces sections are built from. Compose primitives and panels; never import a section.
|
|
126
127
|
|
|
@@ -136,6 +137,7 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
|
|
|
136
137
|
| `AskAiCommandGroup` | The ⌘K palette's composable "Ask AI" group; one CommandItem per provider seeding "About <entity>: <query>" (or the entity promptText when the query is empty); composed by the consumer's own CommandDialog. | `import { AskAiCommandGroup } from "@working-theory/ui/blocks"` |
|
|
137
138
|
| `AskAiProviderRow` | The ONE shared provider-link row every ask-AI placement composes — the AskAi section (band + ticker variant) and the Hero `askAi` opt-in all render THIS block, never a per-placement fork. Renders a bounded set of five measured providers, each a deep link seeded with an AUTHORED `promptText` — the prompt is always consumer-supplied data, never derived from page context (headline, entity name, etc.). | `import { AskAiProviderRow } from "@working-theory/ui/blocks"` |
|
|
138
139
|
| `AssetLightbox` | The asset detail lightbox: the image with zoom on the stage, a Details rail with in-place pencil-edit Title and Description, then Filename/Type/Size/Dimensions/Created, then Tags (from the seeded set the caller passes), then Copy link/Replace/Delete. Renders inside a ResponsiveSheet — the SAME field sequence in both layouts (: one field array, walked once, shared by both). | `import { AssetLightbox } from "@working-theory/ui/blocks"` |
|
|
140
|
+
| `AuthBackLink` | The auth shell's top-start "← Back to <site>". A hub's sign-in page renders it when the visitor arrived from a registered spoke, so the cross-domain handoff names where they came from and gives them the way back. | `import { AuthBackLink } from "@working-theory/ui/blocks"` |
|
|
139
141
|
| `AuthCard` | Multi-flow auth card: sign-in, sign-up, invitation, forgot, reset and sent, from one skeleton. One self-contained card renders every auth surface a site needs: signing in, signing up, a closed sign-up that requires an invitation, requesting a password reset, choosing a new password, and the check-your-email state that follows a magic link or a reset request. | `import { AuthCard } from "@working-theory/ui/blocks"` |
|
|
140
142
|
| `AwardBadgePlaceholder` | The labeled placeholder an Awards badge slot renders when no image has been supplied — mirrors MediaPlaceholder's role but in an award-chevron/ laurel badge silhouette rather than a generic photo frame, since an unfilled award slot should read as "an award badge goes here," not "a photo goes here." The shape (a laurel-flanked medallion over a chevron ribbon) is a hand-drawn SVG outline — never a copied G2/Capterra/Apollo asset. | internal — compose from `packages/ui/src/blocks/AwardBadgePlaceholder.tsx` |
|
|
141
143
|
| `BackgroundPattern` | Decorative SVG dot-grid / line pattern for ContactForm section. Decorative block (generalized beyond its original single consumer). Renders an absolutely-positioned decoration behind a section's content. Originally the pattern anchored behind ContactForm's form column; SpotlightPanel composes it as a full-bleed section backdrop (dimmed + blurred, behind a centered card) — same block, a second placement. | `import { BackgroundPattern } from "@working-theory/ui/blocks"` |
|
|
@@ -189,7 +191,7 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
|
|
|
189
191
|
| `NavFlyoutPanel` | Mega-menu body block (feature grid + action bar) for Nav flyouts. Renders the content of a flyout (mega-menu) panel opened by a NavigationMenu trigger in the Nav chrome component. | `import { NavFlyoutPanel } from "@working-theory/ui/blocks"` |
|
|
190
192
|
| `NavSearchTrigger` | ⌘K search trigger control for Nav desktop pill + mobile icon-only surfaces. ⌘K search trigger button for Nav, desktop + mobile. Thin domain wrapper over the ShortcutTrigger primitive: it resolves the i18n "Open search" label and passes the search specifics (Search icon, the ⌘/K shortcut, the onSearchOpen handler) to ShortcutTrigger. | `import { NavSearchTrigger } from "@working-theory/ui/blocks"` |
|
|
191
193
|
| `NewsletterDetail` | One "why subscribe" detail item: colored icon square + headline + description. Vertically arranged (icon top, heading + description below). Used in the right-column 2-up grid of the 'side-by-side-with-details' variant. | `import { NewsletterDetail } from "@working-theory/ui/blocks"` |
|
|
192
|
-
| `NewsletterFormInline` | Inline email signup form: email Input + submit Button side-by-side at
|
|
194
|
+
| `NewsletterFormInline` | Inline email signup form: email Input + submit Button side-by-side at md+, stacked on mobile (input full-width on its own row, Subscribe below). Manages its own submit state so the parent Newsletter section can remain RSC-oriented (only this block needs the client boundary). | `import { NewsletterFormInline } from "@working-theory/ui/blocks"` |
|
|
193
195
|
| `OnboardingChecklist` | Global onboarding launcher: floating "N/5" bubble expanding into a Popover (lg+) / bottom Sheet (<lg) checklist with SegmentedProgress + item rows (ploy-capture recomposition). The global onboarding launcher captured off ploy.ai's app frame (behavior spec: `post-ftu-checklist` — "global onboarding launcher (floating, all pages)"). | `import { OnboardingChecklist } from "@working-theory/ui/blocks"` |
|
|
194
196
|
| `PageHeader` | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (AdminShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. *(weak)* | `import { PageHeader } from "@working-theory/ui/blocks"` |
|
|
195
197
|
| `PageHeaderSwitcher` | Header-owned context-switcher island (DropdownMenu-backed). Header-owned segment switcher rendered inside PageHeader's `switcher` slot. Composes DropdownMenu (Radix-backed — positioning, click-outside, Escape, focus management, and roving keyboard nav all come for free). | `import { PageHeaderSwitcher } from "@working-theory/ui/blocks"` |
|
package/dist/add-module.js
CHANGED
|
@@ -35,7 +35,7 @@ import { writeAuthSecretFile } from "./lib/auth-secret-file.js";
|
|
|
35
35
|
import { appendEnvRows } from "./lib/declared-env.js";
|
|
36
36
|
import { diffTwoStrings, extractModuleBundle, } from "./lib/extract-module-bundle.js";
|
|
37
37
|
import { normalizeModules } from "./module-architecture.js";
|
|
38
|
-
import { PAID_SECTIONS_PATH, writePaidSections } from "./paid-sections.js";
|
|
38
|
+
import { MODULE_FLAGS_PATH, PAID_SECTIONS_PATH, writePaidSections } from "./paid-sections.js";
|
|
39
39
|
import { ParseError, parseModules } from "./parse-args.js";
|
|
40
40
|
import { writeSpokeFlowsReadme } from "./seed-flows.js";
|
|
41
41
|
import { SITE_ROSTER_PATH, moduleRosterRows, planRosterAppend, readSiteRoster, siteRosterProblems, } from "./site-roster.js";
|
|
@@ -168,16 +168,20 @@ export async function applyModuleToScaffold(opts) {
|
|
|
168
168
|
}
|
|
169
169
|
: {}),
|
|
170
170
|
});
|
|
171
|
-
// #7838 D8 — commerce on a spoke brings the spoke's own checkout
|
|
172
|
-
// from the
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
171
|
+
// #7838 D8 — commerce on a spoke brings the spoke's own checkout — the
|
|
172
|
+
// standard, copied from the template (#8748 D3) — stamped from the site
|
|
173
|
+
// directory's name (the `projectName` scaffold() defaults to). A file the
|
|
174
|
+
// site already has is left as it is. No record row: the record is written
|
|
175
|
+
// only at scaffold time. #8217 D8 — on a spoke that signs in through its
|
|
176
|
+
// hub, the billing action and its seam render too, so re-running
|
|
177
|
+
// add-module commerce gives an existing commerce spoke the action.
|
|
176
178
|
const spokeCommerce = spoke !== undefined && opts.moduleName === "commerce";
|
|
177
179
|
const checkoutRows = spokeCommerce
|
|
178
180
|
? writeSpokeCheckoutSlice(targetAbs, {
|
|
179
181
|
site: spokeCheckoutSite(basename(targetAbs)),
|
|
182
|
+
projectName: basename(targetAbs),
|
|
180
183
|
versions: opts.versions,
|
|
184
|
+
templatesDir: opts.templatesDir,
|
|
181
185
|
signIn: spoke.signIn,
|
|
182
186
|
})
|
|
183
187
|
: [];
|
|
@@ -205,16 +209,18 @@ export async function applyModuleToScaffold(opts) {
|
|
|
205
209
|
// #7536 D3 — the paid-sections registry follows `apps/web/package.json`,
|
|
206
210
|
// which the bundle's `patches` just edited. Generated and always
|
|
207
211
|
// overwritten, like `architecture.yaml` above.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
// #8843 D10 — its module-presence flags follow the same file, and are
|
|
213
|
+
// reported the same way when a module turns one on.
|
|
214
|
+
const generated = [PAID_SECTIONS_PATH, MODULE_FLAGS_PATH].map((path) => {
|
|
215
|
+
const abs = join(targetAbs, path);
|
|
216
|
+
return { path, abs, before: existsSync(abs) ? readFileSync(abs, "utf8") : undefined };
|
|
217
|
+
});
|
|
212
218
|
writePaidSections(targetAbs);
|
|
213
|
-
const registryChanged = existsSync(registryPath) &&
|
|
214
|
-
readFileSync(registryPath, "utf8") !== registryBefore;
|
|
215
219
|
const rows = [...report, ...checkoutRows];
|
|
216
|
-
|
|
217
|
-
|
|
220
|
+
for (const { path, abs, before } of generated) {
|
|
221
|
+
if (existsSync(abs) && readFileSync(abs, "utf8") !== before)
|
|
222
|
+
rows.push({ path, action: "written" });
|
|
223
|
+
}
|
|
218
224
|
const navRow = syncNavConfig(targetAbs, current.surfaces, surfaces);
|
|
219
225
|
if (navRow !== undefined)
|
|
220
226
|
rows.push(navRow);
|
package/dist/add-route.d.ts
CHANGED
|
@@ -40,17 +40,71 @@ export interface AddRouteResult {
|
|
|
40
40
|
export declare function addRouteToScaffold(opts: AddRouteOptions): AddRouteResult;
|
|
41
41
|
/** The report `add-route` prints. */
|
|
42
42
|
export declare function formatAddRouteReport(result: AddRouteResult): string;
|
|
43
|
+
/** The route word that selects the magnet mode. */
|
|
44
|
+
export declare const MAGNET_ROUTE = "magnet";
|
|
45
|
+
/**
|
|
46
|
+
* The header-comment marker every standard magnet page carries — the same
|
|
47
|
+
* string `flows/[slug]/magnet-page.tsx` exports, which the site's
|
|
48
|
+
* `structured-data.test.tsx` reads to exempt the pair (#8840 D13).
|
|
49
|
+
*/
|
|
50
|
+
export declare const MAGNET_PAGE_MARKER = "Standard magnet page (#8840)";
|
|
51
|
+
/** Whether `slug` passes `flowSlugSchema`'s rule. */
|
|
52
|
+
export declare function isMagnetFlowSlug(slug: string): boolean;
|
|
53
|
+
export interface AddMagnetOptions {
|
|
54
|
+
/** The already-scaffolded site. */
|
|
55
|
+
targetDir: string;
|
|
56
|
+
/** The site path the landing serves, e.g. `/diagnostic`. */
|
|
57
|
+
path: string;
|
|
58
|
+
/** The flow slug the pair is bound to. */
|
|
59
|
+
flow: string;
|
|
60
|
+
}
|
|
61
|
+
/** One page of the pair: written, or left as the site has it. */
|
|
62
|
+
export interface MagnetReportRow {
|
|
63
|
+
path: string;
|
|
64
|
+
action: "written" | "skipped";
|
|
65
|
+
}
|
|
66
|
+
export interface AddMagnetResult {
|
|
67
|
+
/** Resolved absolute path to the site. */
|
|
68
|
+
targetDir: string;
|
|
69
|
+
/** The landing's site path. */
|
|
70
|
+
path: string;
|
|
71
|
+
/** The bound flow slug. */
|
|
72
|
+
flow: string;
|
|
73
|
+
/** The landing's row, then the walk's. */
|
|
74
|
+
report: MagnetReportRow[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Write a magnet page pair — `apps/web/app/[locale]/<path>/page.tsx` (the
|
|
78
|
+
* landing) and `<path>/start/page.tsx` (the walk) — bound to one flow slug.
|
|
79
|
+
* Each page is a few lines over the factories in `flows/[slug]/magnet-page`;
|
|
80
|
+
* the copy, consent and ending come from the flow's record.
|
|
81
|
+
*
|
|
82
|
+
* Every refusal throws `AddRouteRefusedError` before the first write. A page
|
|
83
|
+
* that already exists is never overwritten: a second run reports both
|
|
84
|
+
* `skipped`. No `architecture.yaml`, nav or seed changes — the pair is the
|
|
85
|
+
* site's own, with no `ROUTE_SINCE` key or routes-map row (D13).
|
|
86
|
+
*/
|
|
87
|
+
export declare function addMagnetToScaffold(opts: AddMagnetOptions): AddMagnetResult;
|
|
88
|
+
/** The report `add-route magnet` prints. */
|
|
89
|
+
export declare function formatAddMagnetReport(result: AddMagnetResult): string;
|
|
43
90
|
export interface AddRouteArgs {
|
|
44
91
|
/** The route to add; undefined only with `help`. */
|
|
45
92
|
route: string | undefined;
|
|
46
93
|
/** Positional target directory; undefined = the caller's cwd. */
|
|
47
94
|
target: string | undefined;
|
|
48
95
|
help: boolean;
|
|
96
|
+
/** `--path`, the magnet mode's site path — set only with `magnet`. */
|
|
97
|
+
path?: string;
|
|
98
|
+
/** `--flow`, the magnet mode's flow slug — set only with `magnet`. */
|
|
99
|
+
flow?: string;
|
|
49
100
|
}
|
|
50
|
-
export declare const ADD_ROUTE_HELP = "create-ailk add-route \u2014 add a route family to an existing site.\n\nUsage:\n create-ailk add-route <route> [<target-dir>]\n\nArguments:\n <route> One route family, named as --surfaces names it,\n e.g. pricing.\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --help, -h Print this message.\n\nCopies the route's pages, writes its seed content, declares it in\narchitecture.yaml and adds its link to the generated nav \u2014 the site a fresh\nscaffold with --surfaces <route> would have been. A file the site already has\nis never overwritten: one whose content differs, a hand-edited nav included,\nis left as-is and listed for manual review with the change the route wanted.\nLike add-module, it also restores any other page route the site carries but\nlacks. A route a module delivers (blog and docs come with docs-blog) is\nrefused; add that module with create-ailk add-module. Running it again changes\nnothing.\n";
|
|
101
|
+
export declare const ADD_ROUTE_HELP = "create-ailk add-route \u2014 add a route family to an existing site.\n\nUsage:\n create-ailk add-route <route> [<target-dir>]\n create-ailk add-route magnet --path <path> --flow <slug> [<target-dir>]\n\nArguments:\n <route> One route family, named as --surfaces names it,\n e.g. pricing.\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --path <path> magnet only: the site path the landing serves,\n one to three kebab-case segments, e.g. /diagnostic.\n --flow <slug> magnet only: the flow slug the pages are bound to.\n --help, -h Print this message.\n\nCopies the route's pages, writes its seed content, declares it in\narchitecture.yaml and adds its link to the generated nav \u2014 the site a fresh\nscaffold with --surfaces <route> would have been. A file the site already has\nis never overwritten: one whose content differs, a hand-edited nav included,\nis left as-is and listed for manual review with the change the route wanted.\nLike add-module, it also restores any other page route the site carries but\nlacks. A route a module delivers (blog and docs come with docs-blog) is\nrefused; add that module with create-ailk add-module. Running it again changes\nnothing.\n\nadd-route magnet writes a magnet page pair bound to one flow: a landing at\napps/web/app/[locale]/<path>/page.tsx and a full-screen walk at\n<path>/start/page.tsx, each a few lines over the standard magnet pages, so the\ncopy, consent and ending come from the flow's record. It needs the\nsignal-collectors module, and refuses (nothing written) a path the site already\nserves, a one-segment path a LandingPage seed of the same slug owns, a path\nending in start or apply, a reserved first segment (api, v1, flows, account,\nadmin, the sign-in routes, a locale) and a slug the flow API would refuse. A\npage that exists is never overwritten: running it again skips both. It changes\nno architecture.yaml, nav or seed.\n";
|
|
51
102
|
/**
|
|
52
103
|
* Parse the argv AFTER the `add-route` word. Strict `node:util` parseArgs,
|
|
53
104
|
* like `parseAddModuleArgs`; the route itself is validated by
|
|
54
105
|
* `addRouteToScaffold`, which refuses an unknown one naming the recognized.
|
|
106
|
+
* `--path` and `--flow` belong to the `magnet` route word alone (#8840 D12):
|
|
107
|
+
* with any other route they are refused (`AddRouteRefusedError`, exit 2),
|
|
108
|
+
* and `magnet` needs both. Their values are checked by `addMagnetToScaffold`.
|
|
55
109
|
*/
|
|
56
110
|
export declare function parseAddRouteArgs(argv: string[]): AddRouteArgs;
|