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
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /* global process */
3
+
4
+ /**
5
+ * Shared Jest `globalSetup` — pins every jest run in the workspace to one
6
+ * timezone (#8657).
7
+ *
8
+ * Jest otherwise inherits the developer's `TZ`, so a test that renders a date
9
+ * in local time (`formatDate`, `toLocaleDateString`, `getDate()`) passes in CI,
10
+ * which runs in UTC, and fails on a laptop that does not: the #8578 shape,
11
+ * where UTC-midnight consent fixtures rendered the previous day on an MDT
12
+ * machine and failed 11 release-check rows.
13
+ *
14
+ * WHY `globalSetup` AND NOT `setupFiles`: a setup file runs inside the test
15
+ * sandbox, whose `process.env` is jest's copy of the real one, so assigning
16
+ * `TZ` there never reaches the process clock. `globalSetup` runs in jest's
17
+ * parent process before any worker is spawned: the workers inherit the pinned
18
+ * `TZ`, and Node re-reads an assigned `process.env.TZ` at once, so an in-band
19
+ * run (`--runInBand`, a single test file) is pinned in place too.
20
+ *
21
+ * Every committed `jest.config.cjs` loads this file; the guard is
22
+ * `tests/architecture/jest-timezone-pin.test.ts`, and the value is documented
23
+ * in CONVENTIONS.md § Testing. A test that needs another zone formats with an
24
+ * explicit `timeZone` option rather than changing `TZ`. The create-ailk
25
+ * scaffold ships this file at the same path (`SNAPSHOT_FILES` in
26
+ * packages/create-ailk/scripts/build-templates.mjs), so its copied configs
27
+ * load it unchanged.
28
+ */
29
+ const PINNED_TZ = "UTC";
30
+
31
+ module.exports = async function pinTimezone() {
32
+ process.env.TZ = PINNED_TZ;
33
+ };
34
+ module.exports.PINNED_TZ = PINNED_TZ;
package/versions.json CHANGED
@@ -1,53 +1,53 @@
1
1
  {
2
- "@working-theory/admin-ui": "0.41.0",
3
- "@working-theory/aeo": "0.41.0",
4
- "@working-theory/agent-context": "0.41.0",
2
+ "@working-theory/admin-ui": "0.43.0",
3
+ "@working-theory/aeo": "0.43.0",
4
+ "@working-theory/agent-context": "0.43.0",
5
5
  "@working-theory/agent-contract": "0.1.0",
6
6
  "@working-theory/agent-memory": "0.0.0",
7
7
  "@working-theory/ai": "0.1.0",
8
- "@working-theory/analytics": "0.41.0",
9
- "@working-theory/api-client": "0.41.0",
8
+ "@working-theory/analytics": "0.43.0",
9
+ "@working-theory/api-client": "0.43.0",
10
10
  "@working-theory/cda-filesystem": "0.0.0",
11
- "@working-theory/cli": "0.41.0",
12
- "@working-theory/common": "0.41.0",
11
+ "@working-theory/cli": "0.43.0",
12
+ "@working-theory/common": "0.43.0",
13
13
  "@working-theory/consent": "0.1.0",
14
- "@working-theory/content-adapters": "0.41.0",
15
- "@working-theory/content-projection": "0.41.0",
16
- "@working-theory/email": "0.41.0",
14
+ "@working-theory/content-adapters": "0.43.0",
15
+ "@working-theory/content-projection": "0.43.0",
16
+ "@working-theory/email": "0.43.0",
17
17
  "@working-theory/env": "0.0.0",
18
- "@working-theory/eslint-config": "0.41.0",
19
- "@working-theory/fumadocs-schema": "0.41.0",
18
+ "@working-theory/eslint-config": "0.43.0",
19
+ "@working-theory/fumadocs-schema": "0.43.0",
20
20
  "@working-theory/ids": "0.14.0",
21
- "@working-theory/jsonld": "0.41.0",
22
- "@working-theory/license": "0.41.0",
23
- "@working-theory/metadata": "0.41.0",
24
- "@working-theory/observability": "0.41.0",
25
- "@working-theory/page-renderer": "0.41.0",
21
+ "@working-theory/jsonld": "0.43.0",
22
+ "@working-theory/license": "0.43.0",
23
+ "@working-theory/metadata": "0.43.0",
24
+ "@working-theory/observability": "0.43.0",
25
+ "@working-theory/page-renderer": "0.43.0",
26
26
  "@working-theory/plugin-mcp": "0.1.3",
27
- "@working-theory/schema": "0.41.0",
28
- "@working-theory/schema-pack-registry": "0.41.0",
29
- "@working-theory/schema-validator": "0.41.0",
30
- "@working-theory/sections-registry": "0.41.0",
31
- "@working-theory/site-config": "0.41.0",
32
- "@working-theory/spoke-checkout": "0.5.2",
33
- "@working-theory/stripe-client": "0.41.0",
34
- "@working-theory/templates": "0.41.0",
35
- "@working-theory/theme": "0.41.0",
36
- "@working-theory/ui": "0.41.0",
37
- "@working-theory/validation": "0.41.0",
38
- "@working-theory/web-i18n": "0.41.0",
27
+ "@working-theory/schema": "0.43.0",
28
+ "@working-theory/schema-pack-registry": "0.43.0",
29
+ "@working-theory/schema-validator": "0.43.0",
30
+ "@working-theory/sections-registry": "0.43.0",
31
+ "@working-theory/site-config": "0.43.0",
32
+ "@working-theory/spoke-checkout": "0.6.0",
33
+ "@working-theory/stripe-client": "0.43.0",
34
+ "@working-theory/templates": "0.43.0",
35
+ "@working-theory/theme": "0.43.0",
36
+ "@working-theory/ui": "0.43.0",
37
+ "@working-theory/validation": "0.43.0",
38
+ "@working-theory/web-i18n": "0.43.0",
39
39
  "@working-theory/billing-client": "0.0.0",
40
40
  "@working-theory/branding": "0.0.0",
41
41
  "@working-theory/license-client": "0.0.0",
42
42
  "@working-theory/license-manifest": "0.0.0",
43
43
  "@working-theory/partner-session": "0.0.0",
44
44
  "@working-theory/preview-protocol": "0.0.0",
45
- "@working-theory/ui-commerce": "0.23.19",
46
- "@working-theory/ui-docs-blog": "0.23.19",
47
- "@working-theory/ui-scheduling": "0.23.19",
48
- "@working-theory/ui-signal-collectors": "0.25.8",
45
+ "@working-theory/ui-commerce": "0.23.21",
46
+ "@working-theory/ui-docs-blog": "0.23.21",
47
+ "@working-theory/ui-scheduling": "0.24.1",
48
+ "@working-theory/ui-signal-collectors": "0.26.0",
49
49
  "@working-theory/web": "0.0.0",
50
50
  "@working-theory/api": "1.0.0",
51
51
  "@working-theory/mcp": "0.0.0",
52
- "@working-theory/database": "0.41.0"
52
+ "@working-theory/database": "0.43.0"
53
53
  }
@@ -1,125 +0,0 @@
1
- "use server";
2
-
3
- /**
4
- * sign-up.actions.ts — mints the sign-up card's carried-agreement cookie
5
- * (#8438 D13, spec
6
- * docs/specs/8438-consent-registry-and-ledger-step-spec.md C6).
7
- *
8
- * `apps/web` never touches the database (the ledger writer is `apps/api`),
9
- * and Better Auth creates the user from THIS app before any Person exists to
10
- * record a grant against. So the card remembers which agreements the person
11
- * ticked, in a short-lived, signed, email-bound cookie — the account home's
12
- * first signed-in visit (`(authed)/account/actions.ts`'s
13
- * `acceptCarriedAgreementsAction`) consumes it, one write per agreement,
14
- * then deletes it either way (single-use).
15
- *
16
- * The CONSUME side lives in the account area, not here, deliberately:
17
- * `(auth)/**` is one of the sign-in seeds a sign-in-less spoke drops
18
- * (`SPOKE_REMOVAL_SEEDS`, `packages/create-ailk/src/topology.ts` D4), so a
19
- * file OUTSIDE `(auth)` (the account home's `agreements-prompt.tsx`) must
20
- * never import FROM here — doing so once failed the scaffolder's own
21
- * dangling-import check (`spokeExclusions`) for exactly this reason. This
22
- * file is reached only from `sign-up-card.tsx`, its own directory sibling,
23
- * so it carries no such obligation. The two files duplicate the small
24
- * cookie codec (encode here, decode there) rather than share a module,
25
- * precisely so each side's dependencies stay native to where it lives.
26
- *
27
- * Cookie value: `<id>@<version>,…|<issuedAtMs>|<sha256(lowercased email)>|
28
- * <HMAC-SHA256 over the rest>`, keyed by `BETTER_AUTH_SECRET` — the same
29
- * dev fallback `apps/web/auth.ts`'s own `resolveSecret()` publishes when it
30
- * is unset; production refuses to mint without one. That secret is read
31
- * directly HERE rather than importing `resolveSecret` from `auth.ts`: that
32
- * module statically imports the `better-auth` ESM package, which every
33
- * broad page-level test suite that renders `/sign-up` would then have to
34
- * add to its `../../../../auth` mock. `__Host-` prefixed, httpOnly,
35
- * `Secure`, one hour, `SameSite=Lax` — the `__Host-` prefix needs `Secure`,
36
- * so development over plain `http://localhost` uses the unprefixed name
37
- * instead (SEC-8438-5).
38
- */
39
-
40
- import { createHash, createHmac } from "node:crypto";
41
-
42
- import { consentPurposeById, SITE_CONSENT_CONFIG_DEFAULTS } from "@working-theory/validation";
43
- import { cookies } from "next/headers";
44
-
45
- const SECURE_COOKIE_NAME = "__Host-ailk-signup-agreements";
46
- const DEV_COOKIE_NAME = "ailk-signup-agreements";
47
- const MAX_AGE_SECONDS = 60 * 60;
48
-
49
- /** The string `auth.ts`'s own `resolveSecret()` publishes — see file header. */
50
- const DEV_FALLBACK_SECRET =
51
- "ailk-dev-fallback-secret-published-in-this-repo-never-use-in-production";
52
-
53
- /** Mirrors `auth.ts`'s `resolveSecret()` exactly, without importing it. */
54
- function signUpAgreementsSecret(): string {
55
- const configured = process.env.BETTER_AUTH_SECRET;
56
- if (configured) return configured;
57
- const isBuildPhase = process.env.NEXT_PHASE === "phase-production-build";
58
- if (process.env.NODE_ENV === "production" && !isBuildPhase) {
59
- throw new Error(
60
- "BETTER_AUTH_SECRET is required in production: it signs the carried sign-up-agreement cookie.",
61
- );
62
- }
63
- return DEV_FALLBACK_SECRET;
64
- }
65
-
66
- function cookieName(): string {
67
- return process.env.NODE_ENV === "production" ? SECURE_COOKIE_NAME : DEV_COOKIE_NAME;
68
- }
69
-
70
- function emailHash(email: string): string {
71
- return createHash("sha256").update(email.trim().toLowerCase()).digest("hex");
72
- }
73
-
74
- function sign(payload: string): string {
75
- return createHmac("sha256", signUpAgreementsSecret()).update(payload).digest("hex");
76
- }
77
-
78
- interface CarriedPurpose {
79
- id: string;
80
- version: number;
81
- }
82
-
83
- function encodeCarriedAgreements(
84
- purposes: CarriedPurpose[],
85
- email: string,
86
- issuedAtMs: number,
87
- ): string {
88
- const purposesPart = purposes.map((p) => `${p.id}@${p.version}`).join(",");
89
- const payload = `${purposesPart}|${issuedAtMs}|${emailHash(email)}`;
90
- return `${payload}|${sign(payload)}`;
91
- }
92
-
93
- /**
94
- * Mints the carried-agreement cookie from the ticked `signUp` agreements,
95
- * read back from the registry for their CURRENT version — never trusting a
96
- * version the client might assert. Purposes the registry no longer marks
97
- * `signUp` are dropped. Never throws: a failed mint just means the account
98
- * home's first visit asks explicitly instead (D13's "Otherwise" card).
99
- */
100
- export async function rememberSignUpAgreementsAction(
101
- email: string,
102
- purposeIds: string[],
103
- ): Promise<void> {
104
- try {
105
- const config = SITE_CONSENT_CONFIG_DEFAULTS;
106
- const purposes: CarriedPurpose[] = [];
107
- for (const id of purposeIds) {
108
- const purpose = consentPurposeById(config, id);
109
- if (purpose?.signUp) purposes.push({ id: purpose.id, version: purpose.policyVersion });
110
- }
111
- if (purposes.length === 0) return;
112
-
113
- const value = encodeCarriedAgreements(purposes, email, Date.now());
114
- const cookieStore = await cookies();
115
- cookieStore.set(cookieName(), value, {
116
- httpOnly: true,
117
- secure: process.env.NODE_ENV === "production",
118
- sameSite: "lax",
119
- path: "/",
120
- maxAge: MAX_AGE_SECONDS,
121
- });
122
- } catch {
123
- // Convenience only — see file header.
124
- }
125
- }