create-ailk 0.20.0 → 0.22.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 (222) hide show
  1. package/README.md +21 -1
  2. package/component-catalog.json +220 -8
  3. package/component-catalog.md +21 -9
  4. package/dist/add-module.js +9 -5
  5. package/dist/apply-design.d.ts +9 -0
  6. package/dist/apply-design.js +78 -31
  7. package/dist/derive-architecture.d.ts +8 -1
  8. package/dist/derive-architecture.js +38 -3
  9. package/dist/design-home.d.ts +54 -11
  10. package/dist/design-home.js +160 -22
  11. package/dist/design-package.js +7 -2
  12. package/dist/lib/design-checks.d.ts +6 -1
  13. package/dist/lib/design-checks.js +23 -2
  14. package/dist/lib/env-catalog.js +5 -1
  15. package/dist/module-architecture.js +4 -2
  16. package/dist/programmatic.js +63 -25
  17. package/dist/site-chrome.d.ts +8 -0
  18. package/dist/site-chrome.js +17 -1
  19. package/dist/site-roster.d.ts +4 -2
  20. package/dist/site-roster.js +7 -5
  21. package/dist/spoke-checkout.d.ts +39 -18
  22. package/dist/spoke-checkout.js +177 -236
  23. package/dist/starter-grid.js +16 -0
  24. package/dist/surfaces.js +30 -14
  25. package/dist/sync-routes.d.ts +28 -0
  26. package/dist/sync-routes.js +124 -1
  27. package/dist/template-record.d.ts +4 -3
  28. package/dist/template-record.js +6 -3
  29. package/dist/topology.js +25 -1
  30. package/dist/update.d.ts +6 -1
  31. package/dist/update.js +125 -18
  32. package/package.json +3 -3
  33. package/site-templates/_base/ailk-template.json +2 -2
  34. package/site-templates/_base/content/en/WorkingAgreementPage/working-agreement.mdx +78 -0
  35. package/site-templates/designs/minimalism/DESIGN.md +1 -1
  36. package/site-templates/designs/minimalism/contact/local-business-service.mdx +23 -0
  37. package/site-templates/designs/minimalism/contact/organization-product.mdx +23 -0
  38. package/site-templates/designs/minimalism/contact/organization-service.mdx +23 -0
  39. package/site-templates/designs/minimalism/contact/person-service.mdx +23 -0
  40. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +18 -1
  41. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +11 -0
  42. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +18 -1
  43. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +34 -23
  44. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +18 -1
  45. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +33 -23
  46. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +18 -1
  47. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +33 -23
  48. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +18 -1
  49. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +31 -21
  50. package/templates/README.md +26 -25
  51. package/templates/apps/api/CLAUDE.md +20 -7
  52. package/templates/apps/api/jest.config.cjs +1 -0
  53. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +19 -0
  54. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +149 -0
  55. package/templates/apps/api/src/lib/consent-store.ts +28 -0
  56. package/templates/apps/api/src/lib/flow-completion-store.ts +136 -0
  57. package/templates/apps/api/src/lib/hub-sign-in-store.ts +38 -2
  58. package/templates/apps/api/src/lib/proposal-paid-store.ts +21 -4
  59. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +14 -3
  60. package/templates/apps/api/src/middleware/auth.ts +13 -6
  61. package/templates/apps/api/src/openapi/spec.ts +30 -3
  62. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +49 -0
  63. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +41 -0
  64. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +386 -0
  65. package/templates/apps/api/src/routes/consent/account.ts +266 -0
  66. package/templates/apps/api/src/routes/consent/index.ts +15 -7
  67. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +36 -0
  68. package/templates/apps/api/src/routes/content/get-page.ts +4 -0
  69. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +515 -0
  70. package/templates/apps/api/src/routes/leads/index.ts +161 -7
  71. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +26 -0
  72. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +649 -0
  73. package/templates/apps/api/src/routes/webhooks/stripe.ts +154 -19
  74. package/templates/apps/api/src/server.ts +28 -0
  75. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +1038 -118
  76. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +389 -0
  77. package/templates/apps/api/src/services/checkout-buyer.ts +100 -4
  78. package/templates/apps/api/src/services/consent.ts +95 -0
  79. package/templates/apps/api/src/services/lead-routing.ts +337 -8
  80. package/templates/apps/api/src/services/magnet-completion.ts +242 -0
  81. package/templates/apps/api/src/services/person.ts +40 -8
  82. package/templates/apps/api/src/services/plan-offerings.ts +59 -0
  83. package/templates/apps/api/src/services/project-listings.ts +6 -1
  84. package/templates/apps/api/src/services/public-site-resolver.ts +8 -1
  85. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +69 -61
  86. package/templates/apps/mcp/jest.config.cjs +1 -0
  87. package/templates/apps/web/.env.example +14 -0
  88. package/templates/apps/web/CLAUDE.md +139 -3
  89. package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +6 -2
  90. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +5 -4
  91. package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +5 -1
  92. package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +2 -0
  93. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +3 -14
  94. package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +2 -0
  95. package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +5 -1
  96. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +160 -8
  97. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/sign-in-card.test.tsx +12 -9
  98. package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +105 -2
  99. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +36 -3
  100. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +47 -1
  101. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +60 -22
  102. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +16 -8
  103. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +85 -31
  104. package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +18 -4
  105. package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +3 -1
  106. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +7 -4
  107. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +227 -207
  108. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout-sign-out.test.tsx +17 -1
  109. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +143 -1
  110. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-menu.test.tsx +4 -0
  111. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +385 -89
  112. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/popups.test.tsx +5 -0
  113. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +44 -5
  114. package/templates/apps/web/app/[locale]/(authed)/account/account-frame.tsx +68 -34
  115. package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +0 -8
  116. package/templates/apps/web/app/[locale]/(authed)/account/agreements-actions.ts +39 -151
  117. package/templates/apps/web/app/[locale]/(authed)/account/agreements-gate.ts +61 -0
  118. package/templates/apps/web/app/[locale]/(authed)/account/agreements-prompt.tsx +143 -140
  119. package/templates/apps/web/app/[locale]/(authed)/account/layout.tsx +40 -6
  120. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +68 -54
  121. package/templates/apps/web/app/[locale]/(authed)/account/privacy/page.tsx +5 -1
  122. package/templates/apps/web/app/[locale]/about/[slug]/page.tsx +46 -0
  123. package/templates/apps/web/app/[locale]/about/__tests__/about-routes.test.tsx +350 -0
  124. package/templates/apps/web/app/[locale]/about/page.tsx +83 -1
  125. package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +293 -0
  126. package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +115 -0
  127. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +146 -1
  128. package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +310 -0
  129. package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +143 -0
  130. package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +350 -0
  131. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +29 -3
  132. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
  133. package/templates/apps/web/app/[locale]/checkout/__tests__/pages.test.tsx +139 -0
  134. package/templates/apps/web/app/[locale]/checkout/__tests__/thank-you-account.test.tsx +136 -0
  135. package/templates/apps/web/app/[locale]/checkout/thank-you/page.tsx +114 -0
  136. package/templates/apps/web/app/[locale]/checkout/unavailable/page.tsx +51 -0
  137. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +1 -1
  138. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +24 -1
  139. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +79 -4
  140. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-magnet.test.ts +138 -0
  141. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +17 -0
  142. package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +386 -0
  143. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +504 -24
  144. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +12 -3
  145. package/templates/apps/web/app/[locale]/contact/contact-form-magnet.ts +77 -0
  146. package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +2 -0
  147. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +184 -41
  148. package/templates/apps/web/app/[locale]/contact/intake-script.ts +26 -0
  149. package/templates/apps/web/app/[locale]/contact/page.tsx +120 -16
  150. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +2 -2
  151. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +1 -1
  152. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +2 -2
  153. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +106 -1
  154. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.invite.test.tsx +257 -0
  155. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/account-invite.actions.test.ts +69 -0
  156. package/templates/apps/web/app/[locale]/flows/[slug]/account-invite.actions.ts +35 -0
  157. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +1 -1
  158. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  159. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +2 -2
  160. package/templates/apps/web/app/[locale]/layout.tsx +23 -2
  161. package/templates/apps/web/app/[locale]/page.tsx +13 -1
  162. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
  163. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +2 -2
  164. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +2 -2
  165. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +2 -2
  166. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  167. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  168. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +1 -1
  169. package/templates/apps/web/app/[locale]/thanks/[slug]/AccountInviteLink.tsx +89 -0
  170. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/AccountInviteLink.test.tsx +104 -0
  171. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +38 -0
  172. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +9 -0
  173. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  174. package/templates/apps/web/app/[locale]/working-agreement/__tests__/page.test.tsx +63 -0
  175. package/templates/apps/web/app/[locale]/working-agreement/page.tsx +41 -0
  176. package/templates/apps/web/app/api/auth/hub/authorize/__tests__/route.test.ts +114 -0
  177. package/templates/apps/web/app/api/auth/hub/authorize/route.ts +20 -3
  178. package/templates/apps/web/app/api/checkout/[offering]/route.ts +48 -0
  179. package/templates/apps/web/app/api/checkout/__tests__/route.test.ts +120 -0
  180. package/templates/apps/web/app/api/checkout/__tests__/success-path.test.ts +86 -0
  181. package/templates/apps/web/app/api/hub-session/__tests__/routes.test.ts +44 -1
  182. package/templates/apps/web/app/api/hub-session/sign-in/route.ts +22 -3
  183. package/templates/apps/web/app/api/webhooks/stripe/__tests__/route.test.ts +92 -0
  184. package/templates/apps/web/app/api/webhooks/stripe/route.ts +31 -0
  185. package/templates/apps/web/auth.ts +28 -2
  186. package/templates/apps/web/jest.config.cjs +1 -0
  187. package/templates/apps/web/lib/__tests__/account-invite.test.ts +63 -0
  188. package/templates/apps/web/lib/__tests__/checkout.test.ts +243 -0
  189. package/templates/apps/web/lib/__tests__/consent-policies.test.ts +23 -0
  190. package/templates/apps/web/lib/__tests__/deck-page.test.ts +249 -0
  191. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +38 -19
  192. package/templates/apps/web/lib/account-invite.ts +37 -0
  193. package/templates/apps/web/lib/checkout-config.ts +27 -0
  194. package/templates/apps/web/lib/checkout.ts +93 -0
  195. package/templates/apps/web/lib/consent-policies.ts +22 -0
  196. package/templates/apps/web/lib/deck-page.ts +192 -0
  197. package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +111 -0
  198. package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +88 -32
  199. package/templates/apps/web/lib/prisma-for-auth.ts +8 -0
  200. package/templates/apps/web/lib/sign-up-agreements.ts +447 -0
  201. package/templates/apps/web/lib/site-chrome.ts +2 -0
  202. package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
  203. package/templates/apps/web/messages/en.json +40 -12
  204. package/templates/apps/web/package.json +1 -0
  205. package/templates/apps/web/src/lib/__tests__/lead-write.test.ts +187 -0
  206. package/templates/apps/web/src/lib/__tests__/rate-limit.test.ts +67 -0
  207. package/templates/apps/web/src/lib/lead-write.ts +90 -0
  208. package/templates/apps/web/src/lib/rate-limit.ts +79 -0
  209. package/templates/database/CHANGELOG.md +47 -0
  210. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +79 -0
  211. package/templates/database/__tests__/flow-completion-migration.test.ts +115 -0
  212. package/templates/database/__tests__/flow-completion.db.test.ts +136 -0
  213. package/templates/database/__tests__/seed.test.ts +72 -2
  214. package/templates/database/inbox/schema.prisma +17 -2
  215. package/templates/database/jest.config.cjs +1 -0
  216. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +52 -0
  217. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +27 -0
  218. package/templates/database/package.json +1 -1
  219. package/templates/database/seed.ts +60 -0
  220. package/templates/tools/jest/pin-timezone.cjs +34 -0
  221. package/versions.json +34 -34
  222. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up.actions.ts +0 -125
@@ -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
  }
@@ -1,4 +1,5 @@
1
1
  import type { CompiledDesignTheme } from "./design-compile.js";
2
+ import { type DesignSeedPage } from "./design-home.js";
2
3
  import { type SectionLookCatalog } from "./design-presets.js";
3
4
  import { type PageRosterRow } from "./module-architecture.js";
4
5
  import type { ModuleName } from "./parse-args.js";
@@ -102,9 +103,10 @@ export declare const MANIFEST_OPTION_KEYS: readonly ["itemStyle", "actionsPositi
102
103
  * `MANIFEST_OPTION_KEYS` values, as the generator writes them. `undefined`
103
104
  * when the record already says so, or the manifest has no `/` row with a
104
105
  * `sections` key. The value is spliced in place at its own depth; no other
105
- * byte moves.
106
+ * byte moves. `page: "contact"` records the `/contact` row from the contact
107
+ * page instead (#8661 D11).
106
108
  */
107
- export declare function planHomeRecord(manifestText: string, homeText: string, catalog: SectionLookCatalog): string | undefined;
109
+ export declare function planHomeRecord(manifestText: string, homeText: string, catalog: SectionLookCatalog, page?: DesignSeedPage): string | undefined;
108
110
  /**
109
111
  * The generator's row for each of a module's `pageContributions`, in
110
112
  * declaration order — read from the committed manifest of the first
@@ -28,7 +28,7 @@ import { existsSync, readFileSync, readdirSync } from "node:fs";
28
28
  import { join, relative, sep } from "node:path";
29
29
  import { isDeepStrictEqual } from "node:util";
30
30
  import { AddModuleRefusedError, readArchitectureHeader, } from "./add-module-core.js";
31
- import { HOME_PAGE_PATH } from "./design-home.js";
31
+ import { DESIGN_SEED_PAGES } from "./design-home.js";
32
32
  import { locatePageSections } from "./design-presets.js";
33
33
  import { diffTwoStrings } from "./lib/extract-module-bundle.js";
34
34
  import { MODULE_SLICES, normalizeModules, } from "./module-architecture.js";
@@ -296,14 +296,16 @@ function scalarValue(raw) {
296
296
  * `MANIFEST_OPTION_KEYS` values, as the generator writes them. `undefined`
297
297
  * when the record already says so, or the manifest has no `/` row with a
298
298
  * `sections` key. The value is spliced in place at its own depth; no other
299
- * byte moves.
299
+ * byte moves. `page: "contact"` records the `/contact` row from the contact
300
+ * page instead (#8661 D11).
300
301
  */
301
- export function planHomeRecord(manifestText, homeText, catalog) {
302
+ export function planHomeRecord(manifestText, homeText, catalog, page = "home") {
303
+ const { route, path } = DESIGN_SEED_PAGES[page];
302
304
  const file = parseRosterFile(manifestText, SITE_ROSTER_PATH);
303
- const row = file.rows.find((r) => r.value["route"] === "/");
305
+ const row = file.rows.find((r) => r.value["route"] === route);
304
306
  if (row === undefined || !("sections" in row.value))
305
307
  return undefined;
306
- const sections = (locatePageSections(homeText, HOME_PAGE_PATH) ?? []).map((section) => {
308
+ const sections = (locatePageSections(homeText, path) ?? []).map((section) => {
307
309
  const options = {};
308
310
  for (const key of MANIFEST_OPTION_KEYS) {
309
311
  const entry = section.entries.find((e) => e.key === key);
@@ -4,17 +4,17 @@ import { type WorkspaceVersionMap } from "./substitute.js";
4
4
  import { type SignInMode } from "./topology.js";
5
5
  /** The checkout package a spoke's two route files 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 data — 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
9
  /** The two return pages: Stripe's success URL and every refused buy's target. */
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 standard spoke checkout's template paths, scaffold-relative (#8748 D3).
13
+ * A directory entry covers every file under it, so the tests that sit beside
14
+ * the routes and pages travel with them. `copyTemplate` skips all of them for
15
+ * every scaffold; `writeSpokeCheckoutSlice` copies them into a commerce spoke.
16
16
  */
17
- export declare const SPOKE_CHECKOUT_PAGE_MARKER = "GENERATED by create-ailk (#7838)";
17
+ export declare const SPOKE_CHECKOUT_TEMPLATE_PATHS: readonly string[];
18
18
  /** The variables a commerce spoke depends on (D9). The package reads three of them. */
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). */
@@ -54,29 +54,50 @@ export declare const E2E_ACTION_PINS: Readonly<Record<string, string>>;
54
54
  */
55
55
  export declare const CHECKOUT_E2E_WORKFLOW: string;
56
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).
57
+ * The rendered part of the slice for `site` (#8748 D3): with `signIn: "hub"`
58
+ * the billing action (#8217 D8), then the checkout e2e workflow (#7839 D8).
59
+ * Neither depends on `site`. The rest of the slice is template source,
60
+ * copied by `writeSpokeCheckoutSlice`. Throws `TopologyError` for an invalid
61
+ * stamp (SEC-7838-10).
62
62
  */
63
63
  export declare function renderSpokeCheckoutFiles(site: string, opts?: {
64
64
  signIn?: SignInMode | undefined;
65
65
  }): [string, string][];
66
66
  /**
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
67
+ * Write the slice into `targetDir` (#7838 D3, #8748 D3). The standard's
68
+ * template files (`SPOKE_CHECKOUT_TEMPLATE_PATHS`) are copied from
69
+ * `templatesDir`, each rendered with `copyTemplate`'s own renderer and
70
+ * markers, so a recorded hash equals what `create-ailk update` renders; the
71
+ * config's one `const SITE` line is stamped with `site`. `onWrite` is called
72
+ * once per template file written, as `copyTemplate` calls it. Then come the
73
+ * rendered files (`renderSpokeCheckoutFiles`). A file that already exists is
74
+ * left byte-for-byte and reported `skipped` — the config is the site's once
69
75
  * written. With `signIn: "hub"` (#8217 D8) the slice carries the billing
70
76
  * 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.
77
+ * billing render: reported `patched` when it changed, not at all when equal.
78
+ * Adds the package to `apps/web/package.json` when absent, and raises a plain
79
+ * pin older than the one it writes (#7839): the generated checkout e2e
80
+ * workflow runs a command a `^0.2.0` pin never reaches. Any other range —
81
+ * newer, `workspace:`, a tag — is the site's and is kept.
75
82
  * 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.
83
+ * missing or malformed `apps/web/package.json`, a template missing any
84
+ * `SPOKE_CHECKOUT_TEMPLATE_PATHS` entry, a template config without exactly
85
+ * one `const SITE` line, a destination to write that resolves outside
86
+ * `targetDir`) throws before the first write.
77
87
  */
78
88
  export declare function writeSpokeCheckoutSlice(targetDir: string, opts: {
79
89
  site: string;
90
+ projectName: string;
80
91
  versions: WorkspaceVersionMap;
92
+ templatesDir: string;
81
93
  signIn?: SignInMode | undefined;
94
+ onWrite?: (relPath: string, bytes: Uint8Array) => void;
82
95
  }): InstallReportRow[];
96
+ /**
97
+ * Drop the checkout package from a scaffold that does not get the slice — a
98
+ * hub, or a spoke without `commerce` (#8748 D3). The template's
99
+ * `apps/web/package.json` depends on it because the monorepo's `apps/web`
100
+ * carries the standard. Every other key is kept in place; a site without the
101
+ * dependency, or without `apps/web/package.json`, is left as it is.
102
+ */
103
+ export declare function dropSpokeCheckoutDependency(targetDir: string): void;