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.
Files changed (342) hide show
  1. package/component-catalog.json +186 -8
  2. package/component-catalog.md +9 -7
  3. package/dist/add-module.js +20 -14
  4. package/dist/add-route.d.ts +55 -1
  5. package/dist/add-route.js +294 -12
  6. package/dist/cli.js +27 -10
  7. package/dist/derive-architecture.d.ts +12 -3
  8. package/dist/derive-architecture.js +20 -8
  9. package/dist/design-package.js +7 -2
  10. package/dist/lib/design-checks.js +4 -2
  11. package/dist/lib/env-catalog.js +5 -5
  12. package/dist/lib/npm-auth.d.ts +9 -0
  13. package/dist/lib/npm-auth.js +48 -0
  14. package/dist/lib/scaffold-render-sweep.d.ts +3 -2
  15. package/dist/lib/scaffold-render-sweep.js +5 -8
  16. package/dist/module-architecture.js +99 -9
  17. package/dist/paid-sections.d.ts +21 -2
  18. package/dist/paid-sections.js +69 -7
  19. package/dist/programmatic.js +19 -5
  20. package/dist/seed-flows.d.ts +4 -1
  21. package/dist/seed-flows.js +50 -4
  22. package/dist/site-chrome.d.ts +8 -0
  23. package/dist/site-chrome.js +17 -1
  24. package/dist/spoke-checkout.d.ts +65 -41
  25. package/dist/spoke-checkout.js +208 -430
  26. package/dist/starter-grid.d.ts +0 -3
  27. package/dist/starter-grid.js +24 -14
  28. package/dist/surfaces.js +52 -26
  29. package/dist/sync-routes.d.ts +38 -1
  30. package/dist/sync-routes.js +187 -13
  31. package/dist/template-record.d.ts +4 -3
  32. package/dist/template-record.js +8 -4
  33. package/dist/topology.js +25 -1
  34. package/dist/update.js +15 -0
  35. package/package.json +3 -3
  36. package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +4 -49
  37. package/site-templates/_base/content/en/Pricing/pricing.mdx +3 -21
  38. package/site-templates/designs/minimalism/DESIGN.md +1 -1
  39. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +23 -20
  40. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +28 -14
  41. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +15 -39
  42. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +38 -34
  43. package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +6 -43
  44. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +14 -31
  45. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -25
  46. package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
  47. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +14 -31
  48. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -25
  49. package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
  50. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +14 -31
  51. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +26 -25
  52. package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
  53. package/templates/.env.example +9 -7
  54. package/templates/.github/workflows/ci.yml +13 -0
  55. package/templates/README.md +1 -0
  56. package/templates/_gitignore +4 -0
  57. package/templates/apps/api/.env.example +27 -0
  58. package/templates/apps/api/CLAUDE.md +87 -17
  59. package/templates/apps/api/package.json +1 -0
  60. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +2 -0
  61. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +45 -0
  62. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +185 -0
  63. package/templates/apps/api/src/config/index.ts +109 -0
  64. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
  65. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +19 -0
  66. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +149 -0
  67. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +116 -0
  68. package/templates/apps/api/src/lib/consent-store.ts +28 -0
  69. package/templates/apps/api/src/lib/error-serializer.ts +74 -7
  70. package/templates/apps/api/src/lib/flow-completion-store.ts +136 -0
  71. package/templates/apps/api/src/lib/hub-sign-in-store.ts +38 -2
  72. package/templates/apps/api/src/lib/proposal-paid-store.ts +21 -4
  73. package/templates/apps/api/src/lib/stripe.ts +74 -4
  74. package/templates/apps/api/src/lib/webhook-idempotency.ts +66 -2
  75. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +14 -3
  76. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +218 -0
  77. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +174 -0
  78. package/templates/apps/api/src/middleware/auth.ts +13 -6
  79. package/templates/apps/api/src/middleware/rate-limit.ts +226 -4
  80. package/templates/apps/api/src/openapi/spec.ts +33 -3
  81. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +49 -0
  82. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +41 -0
  83. package/templates/apps/api/src/routes/billing/plan-checkout.ts +325 -0
  84. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +11 -0
  85. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +1300 -0
  86. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +11 -0
  87. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +49 -0
  88. package/templates/apps/api/src/routes/checkout/session.ts +57 -25
  89. package/templates/apps/api/src/routes/checkout/sessions.ts +232 -82
  90. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +386 -0
  91. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +160 -0
  92. package/templates/apps/api/src/routes/consent/account.ts +268 -0
  93. package/templates/apps/api/src/routes/consent/index.ts +15 -7
  94. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +36 -0
  95. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +731 -0
  96. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +753 -0
  97. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +762 -0
  98. package/templates/apps/api/src/routes/content/get-page.ts +4 -0
  99. package/templates/apps/api/src/routes/content/index.ts +16 -2
  100. package/templates/apps/api/src/routes/content/offerings.ts +184 -0
  101. package/templates/apps/api/src/routes/content/pricing.ts +176 -0
  102. package/templates/apps/api/src/routes/content/shown-offerings.ts +229 -0
  103. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +515 -0
  104. package/templates/apps/api/src/routes/leads/index.ts +164 -7
  105. package/templates/apps/api/src/routes/webhooks/README.md +66 -0
  106. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +649 -0
  107. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +814 -0
  108. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +80 -68
  109. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +5 -5
  110. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +8 -2
  111. package/templates/apps/api/src/routes/webhooks/index.ts +23 -0
  112. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +384 -0
  113. package/templates/apps/api/src/routes/webhooks/stripe.ts +245 -36
  114. package/templates/apps/api/src/server.ts +163 -46
  115. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +313 -0
  116. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +51 -2
  117. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +234 -0
  118. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +1383 -133
  119. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +389 -0
  120. package/templates/apps/api/src/services/__tests__/person.test.ts +232 -1
  121. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +444 -0
  122. package/templates/apps/api/src/services/checkout-buyer.ts +100 -4
  123. package/templates/apps/api/src/services/consent.ts +95 -0
  124. package/templates/apps/api/src/services/deliverable-fulfillment.ts +13 -5
  125. package/templates/apps/api/src/services/entitlements.ts +157 -1
  126. package/templates/apps/api/src/services/lead-routing.ts +431 -47
  127. package/templates/apps/api/src/services/magnet-completion.ts +242 -0
  128. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +295 -0
  129. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +268 -0
  130. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +868 -0
  131. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +416 -0
  132. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +396 -0
  133. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +681 -0
  134. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +231 -0
  135. package/templates/apps/api/src/services/offerings/catalog.ts +308 -0
  136. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +385 -0
  137. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +192 -0
  138. package/templates/apps/api/src/services/offerings/connection.ts +1003 -0
  139. package/templates/apps/api/src/services/offerings/index.ts +614 -0
  140. package/templates/apps/api/src/services/offerings/source.ts +140 -0
  141. package/templates/apps/api/src/services/offerings/store.ts +150 -0
  142. package/templates/apps/api/src/services/person.ts +164 -17
  143. package/templates/apps/api/src/services/plan-offerings.ts +125 -0
  144. package/templates/apps/api/src/services/public-site-resolver.ts +27 -15
  145. package/templates/apps/mcp/CLAUDE.md +22 -14
  146. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +9 -4
  147. package/templates/apps/mcp/__tests__/get_offerings.test.ts +358 -0
  148. package/templates/apps/mcp/__tests__/get_pricing.test.ts +364 -0
  149. package/templates/apps/mcp/__tests__/http-transport.test.ts +4 -4
  150. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +2 -2
  151. package/templates/apps/mcp/__tests__/server.test.ts +13 -11
  152. package/templates/apps/mcp/__tests__/start_purchase.test.ts +208 -12
  153. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +11 -11
  154. package/templates/apps/mcp/src/lib/shown-offerings.ts +105 -0
  155. package/templates/apps/mcp/src/server.ts +5 -0
  156. package/templates/apps/mcp/src/tools/get_offerings.ts +47 -30
  157. package/templates/apps/mcp/src/tools/get_pricing.ts +40 -40
  158. package/templates/apps/mcp/src/tools/purchase.ts +30 -2
  159. package/templates/apps/mcp/src/workspace-server.ts +15 -0
  160. package/templates/apps/web/.env.example +24 -31
  161. package/templates/apps/web/CLAUDE.md +393 -9
  162. package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +6 -2
  163. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +5 -4
  164. package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +5 -1
  165. package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +2 -0
  166. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +3 -14
  167. package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +2 -0
  168. package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +5 -1
  169. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +160 -8
  170. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/sign-in-card.test.tsx +12 -9
  171. package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +105 -2
  172. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +36 -3
  173. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +47 -1
  174. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +60 -22
  175. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +16 -8
  176. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +85 -31
  177. package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +18 -4
  178. package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +3 -1
  179. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +7 -4
  180. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +227 -207
  181. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout-sign-out.test.tsx +17 -1
  182. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +143 -1
  183. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-menu.test.tsx +4 -0
  184. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +385 -89
  185. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/popups.test.tsx +5 -0
  186. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +44 -5
  187. package/templates/apps/web/app/[locale]/(authed)/account/account-frame.tsx +68 -34
  188. package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +0 -8
  189. package/templates/apps/web/app/[locale]/(authed)/account/agreements-actions.ts +39 -151
  190. package/templates/apps/web/app/[locale]/(authed)/account/agreements-gate.ts +61 -0
  191. package/templates/apps/web/app/[locale]/(authed)/account/agreements-prompt.tsx +143 -140
  192. package/templates/apps/web/app/[locale]/(authed)/account/layout.tsx +40 -6
  193. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +68 -54
  194. package/templates/apps/web/app/[locale]/(authed)/account/privacy/page.tsx +5 -1
  195. package/templates/apps/web/app/[locale]/careers/[slug]/[action]/page.tsx +189 -0
  196. package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +295 -0
  197. package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +120 -0
  198. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +23 -0
  199. package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +319 -0
  200. package/templates/apps/web/app/[locale]/careers/__tests__/careers-hub.test.tsx +172 -0
  201. package/templates/apps/web/app/[locale]/careers/__tests__/careers-set.test.tsx +149 -0
  202. package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +141 -0
  203. package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +424 -0
  204. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +72 -11
  205. package/templates/apps/web/app/[locale]/careers/page.tsx +129 -5
  206. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
  207. package/templates/apps/web/app/[locale]/checkout/__tests__/pages.test.tsx +139 -0
  208. package/templates/apps/web/app/[locale]/checkout/__tests__/thank-you-account.test.tsx +136 -0
  209. package/templates/apps/web/app/[locale]/checkout/thank-you/page.tsx +114 -0
  210. package/templates/apps/web/app/[locale]/checkout/unavailable/page.tsx +51 -0
  211. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +1 -1
  212. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +17 -1
  213. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +79 -4
  214. package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +160 -13
  215. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +466 -36
  216. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +7 -0
  217. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +172 -57
  218. package/templates/apps/web/app/[locale]/contact/intake-script.ts +26 -0
  219. package/templates/apps/web/app/[locale]/contact/page.tsx +99 -60
  220. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +2 -2
  221. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +2 -2
  222. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +341 -4
  223. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.count.test.tsx +43 -0
  224. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.deliverable.test.tsx +200 -0
  225. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.ending.test.tsx +197 -0
  226. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.invite.test.tsx +257 -0
  227. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/account-invite.actions.test.ts +69 -0
  228. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +430 -0
  229. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +21 -9
  230. package/templates/apps/web/app/[locale]/flows/[slug]/account-invite.actions.ts +35 -0
  231. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +352 -0
  232. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +12 -73
  233. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +10 -31
  234. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +1 -1
  235. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  236. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +2 -2
  237. package/templates/apps/web/app/[locale]/layout.tsx +55 -4
  238. package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +174 -104
  239. package/templates/apps/web/app/[locale]/newsletter/page.tsx +95 -58
  240. package/templates/apps/web/app/[locale]/page.tsx +13 -1
  241. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
  242. package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap +7 -0
  243. package/templates/apps/web/app/[locale]/pricing/__tests__/offerings.test.tsx +599 -0
  244. package/templates/apps/web/app/[locale]/pricing/__tests__/page.test.tsx +216 -0
  245. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +236 -0
  246. package/templates/apps/web/app/[locale]/pricing/page.tsx +367 -6
  247. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +2 -2
  248. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +2 -2
  249. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +2 -2
  250. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  251. package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +4 -1
  252. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  253. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +1 -1
  254. package/templates/apps/web/app/[locale]/thanks/[slug]/AccountInviteLink.tsx +89 -0
  255. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/AccountInviteLink.test.tsx +104 -0
  256. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +38 -0
  257. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +9 -0
  258. package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +17 -0
  259. package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +62 -3
  260. package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +70 -18
  261. package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +30 -9
  262. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  263. package/templates/apps/web/app/api/auth/hub/authorize/__tests__/route.test.ts +114 -0
  264. package/templates/apps/web/app/api/auth/hub/authorize/route.ts +20 -3
  265. package/templates/apps/web/app/api/hub-session/__tests__/routes.test.ts +44 -1
  266. package/templates/apps/web/app/api/hub-session/sign-in/route.ts +22 -3
  267. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +316 -0
  268. package/templates/apps/web/app/api/offerings/checkout/__tests__/route.test.ts +810 -0
  269. package/templates/apps/web/auth.ts +28 -2
  270. package/templates/apps/web/lib/__tests__/account-invite.test.ts +63 -0
  271. package/templates/apps/web/lib/__tests__/auth-routes.test.ts +27 -1
  272. package/templates/apps/web/lib/__tests__/consent-policies.test.ts +23 -0
  273. package/templates/apps/web/lib/__tests__/deck-page.test.ts +7 -1
  274. package/templates/apps/web/lib/__tests__/in-page-magnet.test.ts +265 -0
  275. package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +57 -0
  276. package/templates/apps/web/lib/__tests__/newsletter.actions.test.ts +293 -0
  277. package/templates/apps/web/lib/__tests__/offerings-pricing.test.ts +601 -0
  278. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +101 -25
  279. package/templates/apps/web/lib/account-invite.ts +37 -0
  280. package/templates/apps/web/lib/auth-routes.ts +36 -2
  281. package/templates/apps/web/lib/checkout-config.ts +16 -0
  282. package/templates/apps/web/lib/consent-policies.ts +22 -0
  283. package/templates/apps/web/lib/deck-page.ts +7 -0
  284. package/templates/apps/web/lib/deliverable-grant.ts +18 -0
  285. package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +111 -0
  286. package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +88 -32
  287. package/templates/apps/web/lib/in-page-magnet.ts +416 -0
  288. package/templates/apps/web/lib/magnet-routes.ts +42 -0
  289. package/templates/apps/web/lib/modules.generated.ts +9 -0
  290. package/templates/apps/web/lib/newsletter.actions.ts +202 -0
  291. package/templates/apps/web/lib/offerings-pricing.ts +326 -0
  292. package/templates/apps/web/lib/posting-title.ts +17 -0
  293. package/templates/apps/web/lib/prisma-for-auth.ts +8 -0
  294. package/templates/apps/web/lib/sign-up-agreements.ts +449 -0
  295. package/templates/apps/web/lib/site-chrome.ts +2 -0
  296. package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
  297. package/templates/apps/web/messages/en.json +71 -20
  298. package/templates/apps/web/middleware.ts +12 -2
  299. package/templates/apps/web/package.json +1 -0
  300. package/templates/apps/web/security-headers.config.ts +17 -0
  301. package/templates/apps/web/src/lib/__tests__/lead-write.test.ts +187 -0
  302. package/templates/apps/web/src/lib/__tests__/rate-limit.test.ts +67 -0
  303. package/templates/apps/web/src/lib/lead-write.ts +90 -0
  304. package/templates/apps/web/src/lib/rate-limit.ts +79 -0
  305. package/templates/content/en/BlogList/blog.mdx +4 -71
  306. package/templates/content/en/BookCall/book-a-call.mdx +1 -41
  307. package/templates/content/en/BookCall/onsite-estimate.mdx +1 -17
  308. package/templates/content/en/BookCall/onsite-service.mdx +1 -17
  309. package/templates/content/en/BookCall/start-project.mdx +1 -17
  310. package/templates/content/en/ContactPage/contact.mdx +6 -63
  311. package/templates/content/en/HomePage/home.mdx +3 -21
  312. package/templates/database/CHANGELOG.md +69 -0
  313. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +79 -0
  314. package/templates/database/__tests__/flow-completion-migration.test.ts +115 -0
  315. package/templates/database/__tests__/flow-completion.db.test.ts +136 -0
  316. package/templates/database/__tests__/in-page-magnets-migration.test.ts +161 -0
  317. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +270 -0
  318. package/templates/database/__tests__/offerings-migration.test.ts +197 -0
  319. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +86 -0
  320. package/templates/database/__tests__/offerings.db.test.ts +303 -0
  321. package/templates/database/__tests__/seed.test.ts +64 -1
  322. package/templates/database/auth/schema.prisma +4 -0
  323. package/templates/database/config/schema.prisma +91 -0
  324. package/templates/database/inbox/schema.prisma +17 -2
  325. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +52 -0
  326. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +27 -0
  327. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +146 -0
  328. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +77 -0
  329. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +45 -0
  330. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +47 -0
  331. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +16 -0
  332. package/templates/database/package.json +1 -1
  333. package/templates/database/seed.ts +62 -3
  334. package/versions.json +35 -35
  335. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -199
  336. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up.actions.ts +0 -125
  337. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +0 -93
  338. package/templates/apps/web/app/[locale]/downloads/page.tsx +0 -37
  339. package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +0 -139
  340. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +0 -93
  341. package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +0 -120
  342. package/templates/apps/web/lib/meeting-slugs.ts +0 -63
@@ -49,6 +49,22 @@ export class SeedFlowsRefusedError extends Error {
49
49
  this.name = "SeedFlowsRefusedError";
50
50
  }
51
51
  }
52
+ /** A starter placeholder string: one `{…}` brace pair and nothing else. */
53
+ const PLACEHOLDER_STRING = /^\{[^{}]+\}$/;
54
+ /**
55
+ * Whether a flow config carries the starter's placeholder copy (#8850 D6):
56
+ * some string value anywhere in it is a whole `{brace}` placeholder.
57
+ */
58
+ function isPlaceholderFlow(config) {
59
+ if (typeof config === "string")
60
+ return PLACEHOLDER_STRING.test(config);
61
+ if (Array.isArray(config))
62
+ return config.some(isPlaceholderFlow);
63
+ if (config !== null && typeof config === "object") {
64
+ return Object.values(config).some(isPlaceholderFlow);
65
+ }
66
+ return false;
67
+ }
52
68
  function readDeclaredFlows(flowsDir) {
53
69
  if (!existsSync(flowsDir))
54
70
  return [];
@@ -78,7 +94,12 @@ function readDeclaredFlows(flowsDir) {
78
94
  if (slug !== expected) {
79
95
  throw new SeedFlowsRefusedError(`seed-flows: flows/${file} declares slug "${slug}"; a declared flow's file is named <slug>.json. Nothing was sent.`);
80
96
  }
81
- return { slug, file, config: config };
97
+ return {
98
+ slug,
99
+ file,
100
+ config: config,
101
+ placeholder: isPlaceholderFlow(config),
102
+ };
82
103
  });
83
104
  }
84
105
  // ── The hub origin ──────────────────────────────────────────────────────────
@@ -158,6 +179,7 @@ async function sendFlow(fetchImpl, origin, key, flow) {
158
179
  ok: true,
159
180
  result,
160
181
  status: safeCode(envelope.data?.status),
182
+ ...(flow.placeholder && { placeholder: true }),
161
183
  };
162
184
  }
163
185
  return { slug: flow.slug, ok: false, failure: "200 unknown" };
@@ -175,12 +197,15 @@ function hubLine(hub) {
175
197
  : `hub: ${hub.origin} (from ${hub.source})`;
176
198
  }
177
199
  function flowLine(outcome) {
178
- if (outcome.ok === "dry-run")
179
- return `${outcome.slug}: would send`;
180
200
  if (outcome.ok === false)
181
201
  return `${outcome.slug}: failed — ${outcome.failure}`;
202
+ const placeholder = outcome.placeholder === true
203
+ ? ` — placeholder copy: replace every {brace} in flows/${outcome.slug}.json`
204
+ : "";
205
+ if (outcome.ok === "dry-run")
206
+ return `${outcome.slug}: would send${placeholder}`;
182
207
  const draft = outcome.status === "draft" ? " (status draft — not shown to visitors)" : "";
183
- return `${outcome.slug}: ${outcome.result}${draft}`;
208
+ return `${outcome.slug}: ${outcome.result}${draft}${placeholder}`;
184
209
  }
185
210
  /** The whole report, one line per row — what `seedFlows` printed as it went. */
186
211
  export function formatSeedFlowsReport(result) {
@@ -224,6 +249,7 @@ export async function seedFlows(opts) {
224
249
  const outcomes = flows.map((flow) => ({
225
250
  slug: flow.slug,
226
251
  ok: "dry-run",
252
+ ...(flow.placeholder && { placeholder: true }),
227
253
  }));
228
254
  onLine(hubLine(hub));
229
255
  outcomes.forEach((outcome) => onLine(flowLine(outcome)));
@@ -282,6 +308,26 @@ The hub's operator must first turn seeding on (\`AILK_SPOKE_FLOW_SEED=true\`
282
308
  on the hub). Until it is on and this command has run, links to these flows
283
309
  (\`/flows/<slug>\`) reach no flow.
284
310
 
311
+ ## The starter's placeholder flows
312
+
313
+ The \`signal-collectors\` module ships two declared flows here:
314
+ \`flows/diagnostic.json\` (an email step, then two questions) and
315
+ \`flows/join-waitlist.json\` (an email and an optional name). Every visible
316
+ string in both is a \`{brace}\` placeholder: replace each one with your own
317
+ copy. Both go live on the hub with the first seed, so each line this command
318
+ prints for them says they still carry placeholder copy.
319
+
320
+ A flow is reached at \`/flows/<slug>\`. To give one its own page pair, run:
321
+
322
+ npx create-ailk add-route magnet --path /diagnostic --flow diagnostic
323
+ npx create-ailk add-route magnet --path /waitlist --flow join-waitlist
324
+
325
+ A job application comes with the \`careers\` surface. Contact, newsletter and
326
+ job application are the hub's own standard magnets: the hub seeds them in
327
+ every workspace and refuses a spoke's copy of each, so they need no file
328
+ here. If the hub's Admin already owns a magnet under one of these two slugs,
329
+ the hub refuses the seed (\`slug_owned\`); rename the file and its \`slug\`.
330
+
285
331
  ## Who owns what
286
332
 
287
333
  The next seed that differs overwrites the hub's copy of a flow's config, so
@@ -41,6 +41,10 @@ export type SiteChromeHome = "default" | "deck";
41
41
  /** The `innerPages` knob's vocabulary (#7721). `bare` → every non-home page
42
42
  * gets the bare header and the one-bar footer. */
43
43
  export type SiteChromeInnerPages = "default" | "bare";
44
+ /** The `deckAnchors` knob's vocabulary (#8773). `bare` → the deck home names
45
+ * its slides `#<id>` instead of `#slide-<id>`, keeping the `slide-` name only
46
+ * where the bare id would collide (the page renderer's `deckSlideAnchors`). */
47
+ export type SiteChromeDeckAnchors = "prefixed" | "bare";
44
48
  /** The `colorMode` knob's vocabulary (#7742). `light` pins the site to light
45
49
  * and removes every theme switch; dark then appears only as a deck ground. */
46
50
  export type SiteChromeColorMode = "user" | "light";
@@ -72,6 +76,8 @@ export interface TemplateLayout {
72
76
  innerPages?: SiteChromeInnerPages;
73
77
  /** #7740 D1 — `true`: the deck home presents slide by slide (a deck home only). */
74
78
  deckPresentation?: boolean;
79
+ /** #8773 — `bare`: a presenting deck names its slides `#<id>` (a presenting deck home only). */
80
+ deckAnchors?: SiteChromeDeckAnchors;
75
81
  /** #7742 D1 — `light`: the site is pinned to light, with no theme switch. */
76
82
  colorMode?: SiteChromeColorMode;
77
83
  /** #7742 D1 — `minimal`: the minimal closing slide, consent bar and themed 404. */
@@ -91,6 +97,8 @@ export interface ResolvedSiteChrome {
91
97
  innerPages?: "bare";
92
98
  /** Present only when it resolves to `true` AND `home` is `deck` (#7740 D1) — never `false`. */
93
99
  deckPresentation?: true;
100
+ /** Present only when it resolves to "bare" on a presenting deck home (#8773) — never "prefixed". */
101
+ deckAnchors?: "bare";
94
102
  /** Present only when it resolves to "light" — never "user" (#7742 D1). */
95
103
  colorMode?: "light";
96
104
  /** Present only when it resolves to "minimal" — never "default" (#7742 D1). */
@@ -64,6 +64,7 @@ const NAV_VALUES = ["full", "mark-only"];
64
64
  const FOOTER_VALUES = ["columns", "centered"];
65
65
  const HOME_VALUES = ["default", "deck"];
66
66
  const INNER_PAGES_VALUES = ["default", "bare"];
67
+ const DECK_ANCHORS_VALUES = ["prefixed", "bare"];
67
68
  const COLOR_MODE_VALUES = ["user", "light"];
68
69
  const CHROME_STYLE_VALUES = ["default", "minimal"];
69
70
  /**
@@ -140,6 +141,12 @@ export function validateTemplateLayout(value, subject) {
140
141
  }
141
142
  result.deckPresentation = raw.deckPresentation;
142
143
  }
144
+ if ("deckAnchors" in raw && raw.deckAnchors !== undefined) {
145
+ if (!DECK_ANCHORS_VALUES.includes(raw.deckAnchors)) {
146
+ throw new TemplateLayoutError(`${subject}: layout.deckAnchors must be one of ${DECK_ANCHORS_VALUES.join(", ")} — got ${JSON.stringify(raw.deckAnchors)}`);
147
+ }
148
+ result.deckAnchors = raw.deckAnchors;
149
+ }
143
150
  if ("colorMode" in raw && raw.colorMode !== undefined) {
144
151
  if (!COLOR_MODE_VALUES.includes(raw.colorMode)) {
145
152
  throw new TemplateLayoutError(`${subject}: layout.colorMode must be one of ${COLOR_MODE_VALUES.join(", ")} — got ${JSON.stringify(raw.colorMode)}`);
@@ -206,6 +213,11 @@ export function resolveSiteChrome(layout, designLayout) {
206
213
  if ((layout?.deckPresentation ?? fromDesign.deckPresentation) === true && resolved.home === "deck") {
207
214
  resolved.deckPresentation = true;
208
215
  }
216
+ // #8773 — only "bare" is ever a key, and only where the deck presents: the
217
+ // slide anchors it names exist only under the presentation dial.
218
+ if ((layout?.deckAnchors ?? fromDesign.deckAnchors) === "bare" && resolved.deckPresentation === true) {
219
+ resolved.deckAnchors = "bare";
220
+ }
209
221
  // #7742 D1 — as with `innerPages`, only the opt-in value is ever a key.
210
222
  if ((layout?.colorMode ?? fromDesign.colorMode) === "light") {
211
223
  resolved.colorMode = "light";
@@ -245,6 +257,8 @@ export function renderSiteChrome(resolved) {
245
257
  // #7740 D1 — `innerPages`' form: the member and bullet always, the value
246
258
  // line only when the chrome presents.
247
259
  const presentationValue = resolved.deckPresentation === true ? "\n deckPresentation: true," : "";
260
+ // #8773 — the same form: member and bullet always, the value line only for "bare".
261
+ const deckAnchorsValue = resolved.deckAnchors === "bare" ? '\n deckAnchors: "bare",' : "";
248
262
  // #7742 D1 — the same form again: member and bullet always, value lines
249
263
  // only for the opt-in values.
250
264
  const colorModeValue = resolved.colorMode === "light" ? '\n colorMode: "light",' : "";
@@ -271,6 +285,7 @@ export function renderSiteChrome(resolved) {
271
285
  // - innerPages: "bare" → every non-home page renders the bare header and
272
286
  // the one-bar footer.
273
287
  // - deckPresentation → the deck home presents slide by slide: fitted slides, slide anchors, the mark follows the ground
288
+ // - deckAnchors: "bare" → the presenting deck names its slides #<id> instead of #slide-<id>
274
289
  // - colorMode: "light" → the site is pinned to light and shows no theme
275
290
  // switch; dark appears only as a deck ground.
276
291
  // - chromeStyle: "minimal" → the deck's closing slide is the wordmark,
@@ -286,6 +301,7 @@ export interface SiteChrome {
286
301
  home: "default" | "deck";
287
302
  innerPages?: "bare";
288
303
  deckPresentation?: true;
304
+ deckAnchors?: "bare";
289
305
  colorMode?: "light";
290
306
  chromeStyle?: "minimal";
291
307
  closingFooterPaths?: readonly string[];${groundsMember}
@@ -295,7 +311,7 @@ export const siteChrome: SiteChrome = {
295
311
  nav: ${JSON.stringify(resolved.nav)},
296
312
  footer: ${JSON.stringify(resolved.footer)},
297
313
  announcementBanner: ${JSON.stringify(resolved.announcementBanner)},
298
- home: ${JSON.stringify(resolved.home)},${groundsValue}${innerPagesValue}${presentationValue}${colorModeValue}${chromeStyleValue}${closingFooterPathsValue}
314
+ home: ${JSON.stringify(resolved.home)},${groundsValue}${innerPagesValue}${presentationValue}${deckAnchorsValue}${colorModeValue}${chromeStyleValue}${closingFooterPathsValue}
299
315
  };
300
316
  `;
301
317
  }
@@ -2,26 +2,26 @@ import type { EnvCatalogEntry, PlanEnvRowsOptions } from "./lib/declared-env.js"
2
2
  import { type InstallReportRow } from "./lib/extract-module-bundle.js";
3
3
  import { type WorkspaceVersionMap } from "./substitute.js";
4
4
  import { type SignInMode } from "./topology.js";
5
- /** The checkout package a spoke's two route files import. */
5
+ /** The checkout package a spoke's billing action and thank-you page import. */
6
6
  export declare const SPOKE_CHECKOUT_PACKAGE = "@working-theory/spoke-checkout";
7
- /** The site's checkout data — written once, the site's from then on. */
7
+ /** The site's checkout stamp — written once, the site's from then on (#8748 D2). */
8
8
  export declare const SPOKE_CHECKOUT_CONFIG_PATH = "apps/web/lib/checkout-config.ts";
9
- /** The two return pages: Stripe's success URL and every refused buy's target. */
9
+ /** The two return pages a commerce spoke still carries (#8748 D5). */
10
10
  export declare const SPOKE_CHECKOUT_PAGE_FILES: readonly string[];
11
11
  /**
12
- * The marker `renderPage()` stamps into both generated return pages' header
13
- * comment (D3). `apps/web`'s structured-data test cannot import create-ailk
14
- * (the import boundary), so it carries this text as a literal, kept in sync
15
- * by `packages/create-ailk/__tests__/spoke-checkout.test.ts` (#8513 AC-5).
12
+ * The spoke checkout's template paths, scaffold-relative (#8748 D3). A
13
+ * directory entry covers every file under it, so the tests that sit beside
14
+ * the pages travel with them. `copyTemplate` skips all of them for every
15
+ * scaffold; `writeSpokeCheckoutSlice` copies them into a commerce spoke.
16
16
  */
17
- export declare const SPOKE_CHECKOUT_PAGE_MARKER = "GENERATED by create-ailk (#7838)";
18
- /** The variables a commerce spoke depends on (D9). The package reads three of them. */
17
+ export declare const SPOKE_CHECKOUT_TEMPLATE_PATHS: readonly string[];
18
+ /** The variables a commerce spoke depends on (D9): the package reads both. */
19
19
  export declare const SPOKE_CHECKOUT_ENV_CATALOG: Readonly<Record<string, EnvCatalogEntry>>;
20
20
  /** The names a commerce spoke declares although only the package reads them (D9). */
21
21
  export declare const SPOKE_CHECKOUT_DECLARED_ENV: readonly string[];
22
22
  /**
23
23
  * The catalog (and declared names) a spoke's `appendEnvRows` call passes: a
24
- * commerce spoke adds the checkout's four rows (D9). `ENV_CATALOG` itself is
24
+ * commerce spoke adds the package's two rows (D9). `ENV_CATALOG` itself is
25
25
  * unchanged — its test fails on an entry the monorepo's apps never read.
26
26
  */
27
27
  export declare function spokeEnvRowOptions(commerce: boolean): Pick<PlanEnvRowsOptions, "catalog" | "declare">;
@@ -32,51 +32,75 @@ export declare function spokeEnvRowOptions(commerce: boolean): Pick<PlanEnvRowsO
32
32
  * `site-` and the first 8 hex characters of its SHA-256. Never `AILK_SITE_ID`.
33
33
  */
34
34
  export declare function spokeCheckoutSite(projectName: string): string;
35
- /** Where a commerce spoke's end-to-end checkout workflow lives. */
36
- export declare const SPOKE_CHECKOUT_E2E_WORKFLOW_PATH = ".github/workflows/checkout-e2e.yml";
35
+ /** The billing action's first line, which marks the file as create-ailk's to rewrite. */
36
+ export declare const BILLING_ACTION_MARKER = "// The spoke billing action \u2014 GENERATED by create-ailk (#8217). Do not edit:";
37
37
  /**
38
- * The Stripe CLI release the workflow installs, and the SHA-256 of its
39
- * `stripe_<v>_linux_x86_64.tar.gz` from that release's own
40
- * `stripe-linux-checksums.txt`. Never bump one without re-reading the other.
38
+ * The spoke billing action (#8217 D6): wiring only, byte-identical across
39
+ * sites, so every guarantee arrives by a package bump. A plain server module
40
+ * (C2): its two exports take no argument, and the hub's read is its only
41
+ * source of customer ids. It builds its config from the site's stamp and the
42
+ * site's own origin (#9142: no longer from `lib/checkout.ts`).
41
43
  */
42
- export declare const STRIPE_CLI_VERSION = "1.51.1";
43
- export declare const STRIPE_CLI_LINUX_X64_SHA256 = "38c8de73a8cab810a4aab8a4015cd4e3398b7b87aa42b6944d09d89ed524ac53";
44
- /** The Playwright the workflow installs — the monorepo's own pinned version. */
45
- export declare const E2E_PLAYWRIGHT_VERSION = "1.61.1";
44
+ export declare const BILLING_ACTION: string;
46
45
  /**
47
- * Every action the workflow uses, pinned to the commit its `v4` tag named
48
- * when this was written (SEC-7839-2): `gh api repos/<action>/commits/v4`.
49
- */
50
- export declare const E2E_ACTION_PINS: Readonly<Record<string, string>>;
51
- /**
52
- * The workflow text (D8). Identical for every spoke at one create-ailk
53
- * version. Every `${{ … }}` sits in an env-style value, never in a script.
54
- */
55
- export declare const CHECKOUT_E2E_WORKFLOW: string;
56
- /**
57
- * The slice for `site`, in order: the two route files, the config, the two
58
- * pages (D3), then the checkout e2e workflow (#7839 D8), which does not
59
- * depend on `site`. With `signIn: "hub"` the billing action is the third
60
- * pair, so the first three paths are `SPOKE_CHECKOUT_ROUTE_FILES` (#8217 D8).
61
- * Throws `TopologyError` for an invalid stamp (SEC-7838-10).
46
+ * The rendered part of the slice for `site` (#8748 D3): with `signIn: "hub"`
47
+ * the billing action (#8217 D8), else nothing. It does not depend on `site`.
48
+ * The rest of the slice is template source, copied by
49
+ * `writeSpokeCheckoutSlice`. Throws `TopologyError` for an invalid stamp
50
+ * (SEC-7838-10).
62
51
  */
63
52
  export declare function renderSpokeCheckoutFiles(site: string, opts?: {
64
53
  signIn?: SignInMode | undefined;
65
54
  }): [string, string][];
66
55
  /**
67
- * Write the slice into `targetDir` (D3). A file that already exists is left
68
- * byte-for-byte and reported `skipped` — the config is the site's once
56
+ * Write the slice into `targetDir` (#7838 D3, #8748 D3). The standard's
57
+ * template files (`SPOKE_CHECKOUT_TEMPLATE_PATHS`) are copied from
58
+ * `templatesDir`, each rendered with `copyTemplate`'s own renderer and
59
+ * markers, so a recorded hash equals what `create-ailk update` renders; the
60
+ * config's one `const SITE` line is stamped with `site`. `onWrite` is called
61
+ * once per template file written, as `copyTemplate` calls it. Then come the
62
+ * rendered files (`renderSpokeCheckoutFiles`). A file that already exists is
63
+ * left byte-for-byte and reported `skipped` — the config is the site's once
69
64
  * written. With `signIn: "hub"` (#8217 D8) the slice carries the billing
70
65
  * action, and the web seam — generated, so always rewritten — becomes the
71
- * billing render: reported `patched` when it changed, not at all when equal. Adds the package to `apps/web/package.json` when absent, and
72
- * raises a plain pin older than the one it writes (#7839): the generated
73
- * checkout e2e workflow runs a command a `^0.2.0` pin never reaches. Any
74
- * other range — newer, `workspace:`, a tag — is the site's and is kept.
66
+ * billing render: reported `patched` when it changed, not at all when equal.
67
+ * Adds the package to `apps/web/package.json` when absent, and raises a plain
68
+ * pin older than the one it writes (#7839): the rendered billing action
69
+ * calls the package's current `createSpokeCheckout` shape, which an older
70
+ * pin does not take (#9142). Any other range — newer, `workspace:`, a tag —
71
+ * is the site's and is kept.
75
72
  * Every refusal (an invalid stamp, a version map without the package, a
76
- * missing or malformed `apps/web/package.json`) throws before the first write.
73
+ * missing or malformed `apps/web/package.json`, a template missing any
74
+ * `SPOKE_CHECKOUT_TEMPLATE_PATHS` entry, a template config without exactly
75
+ * one `const SITE` line, a destination to write that resolves outside
76
+ * `targetDir`) throws before the first write.
77
77
  */
78
78
  export declare function writeSpokeCheckoutSlice(targetDir: string, opts: {
79
79
  site: string;
80
+ projectName: string;
80
81
  versions: WorkspaceVersionMap;
82
+ templatesDir: string;
81
83
  signIn?: SignInMode | undefined;
84
+ onWrite?: (relPath: string, bytes: Uint8Array) => void;
82
85
  }): InstallReportRow[];
86
+ /**
87
+ * Drop the checkout package from a scaffold that does not get the slice — a
88
+ * hub, or a spoke without `commerce` (#8748 D3). The template's
89
+ * `apps/web/package.json` depends on it because the monorepo's `apps/web`
90
+ * carries the standard. Every other key is kept in place; a site without the
91
+ * dependency, or without `apps/web/package.json`, is left as it is.
92
+ */
93
+ export declare function dropSpokeCheckoutDependency(targetDir: string): void;
94
+ /**
95
+ * What the legacy env-key checkout left in a spoke, scaffold-relative: the
96
+ * buy route and the Stripe webhook route (a directory entry covers the tests
97
+ * beside each), `lib/checkout.ts` (the fulfilment) and its test. Each was a
98
+ * template copy create-ailk recorded in `.ailk-template-files.json`;
99
+ * `create-ailk sync-routes --apply` removes the ones still byte-identical to
100
+ * that record.
101
+ */
102
+ export declare const RETIRED_SPOKE_CHECKOUT_PATHS: readonly string[];
103
+ /** The retired checkout e2e workflow — rendered, never recorded (#7839 D8). */
104
+ export declare const RETIRED_CHECKOUT_E2E_WORKFLOW_PATH = ".github/workflows/checkout-e2e.yml";
105
+ /** The workflow's first line, which marks it as create-ailk's to remove. */
106
+ export declare const RETIRED_CHECKOUT_E2E_MARKER = "# Checkout e2e \u2014 GENERATED by create-ailk (#7839). Do not edit: it changes";