create-ailk 0.23.0 → 0.25.1

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 (604) hide show
  1. package/README.md +68 -33
  2. package/component-catalog.json +3 -3
  3. package/component-catalog.md +3 -3
  4. package/dist/add-module.js +10 -3
  5. package/dist/add-route.d.ts +12 -1
  6. package/dist/add-route.js +38 -4
  7. package/dist/cli.js +12 -7
  8. package/dist/derive-architecture.d.ts +3 -4
  9. package/dist/derive-architecture.js +75 -22
  10. package/dist/lib/design-checks.d.ts +9 -4
  11. package/dist/lib/design-checks.js +13 -7
  12. package/dist/lib/extract-module-bundle.js +29 -2
  13. package/dist/lib/fetch-template-snapshot.d.ts +1 -1
  14. package/dist/lib/fetch-template-snapshot.js +7 -3
  15. package/dist/lib/import-graph.d.ts +1 -1
  16. package/dist/lib/import-graph.js +4 -4
  17. package/dist/lib/module-license-gate.d.ts +12 -1
  18. package/dist/lib/module-license-gate.js +34 -12
  19. package/dist/lib/scaffold-render-sweep.d.ts +33 -0
  20. package/dist/lib/scaffold-render-sweep.js +45 -0
  21. package/dist/module-architecture.d.ts +20 -3
  22. package/dist/module-architecture.js +122 -538
  23. package/dist/paid-sections.d.ts +25 -1
  24. package/dist/paid-sections.js +88 -3
  25. package/dist/surfaces.js +10 -2
  26. package/dist/sync-routes.d.ts +30 -4
  27. package/dist/sync-routes.js +271 -18
  28. package/dist/template-record.d.ts +14 -4
  29. package/dist/template-record.js +23 -5
  30. package/dist/topology.d.ts +16 -3
  31. package/dist/topology.js +31 -19
  32. package/dist/update.d.ts +10 -1
  33. package/dist/update.js +540 -16
  34. package/package.json +3 -3
  35. package/release-scope.json +1 -1
  36. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  37. package/templates/.claude/hooks/template-guard.sh +137 -0
  38. package/templates/.claude/rules/extending.md +106 -0
  39. package/templates/.claude/rules/loop-contract.md +2 -2
  40. package/templates/.claude/settings.json +11 -0
  41. package/templates/.env.example +9 -5
  42. package/templates/.github/workflows/ci.yml +7 -4
  43. package/templates/CLAUDE.md +15 -3
  44. package/templates/CONVENTIONS.md +8 -10
  45. package/templates/README.md +14 -13
  46. package/templates/apps/api/.env.example +9 -2
  47. package/templates/apps/api/CLAUDE.md +122 -82
  48. package/templates/apps/api/jest.config.cjs +15 -5
  49. package/templates/apps/api/package.json +16 -20
  50. package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
  51. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
  52. package/templates/apps/api/src/index.ts +1 -1
  53. package/templates/apps/api/src/lib/__mocks__/prisma.ts +7 -4
  54. package/templates/apps/api/src/modules/commerce.ts +10 -0
  55. package/templates/apps/api/src/modules/content-write.ts +10 -0
  56. package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
  57. package/templates/apps/api/src/modules/scheduling.ts +10 -0
  58. package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
  59. package/templates/apps/api/src/modules/workspace.ts +10 -0
  60. package/templates/apps/api/src/server.ts +117 -1857
  61. package/templates/apps/api/vercel.json +2 -2
  62. package/templates/apps/mcp/CLAUDE.md +77 -24
  63. package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
  64. package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
  65. package/templates/apps/mcp/jest.config.cjs +6 -1
  66. package/templates/apps/mcp/package.json +5 -12
  67. package/templates/apps/mcp/src/app.ts +8 -7
  68. package/templates/apps/mcp/src/index.ts +6 -34
  69. package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
  70. package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
  71. package/templates/apps/mcp/src/site.ts +12 -0
  72. package/templates/apps/web/.env.example +1 -1
  73. package/templates/apps/web/CLAUDE.md +21 -5
  74. package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
  75. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +1 -1
  76. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +14 -4
  77. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
  78. package/templates/apps/web/app/[locale]/contact/intake-script.ts +1 -1
  79. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
  80. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +28 -7
  81. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
  82. package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
  83. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
  84. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
  85. package/templates/apps/web/app/api/revalidate/route.ts +3 -3
  86. package/templates/apps/web/auth.ts +2 -2
  87. package/templates/apps/web/jest.config.cjs +1 -0
  88. package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +7 -0
  89. package/templates/apps/web/lib/auth-email.ts +1 -1
  90. package/templates/apps/web/lib/magnet-routes.ts +3 -1
  91. package/templates/apps/web/lib/newsletter.actions.ts +9 -6
  92. package/templates/apps/web/lib/relay.ts +2 -2
  93. package/templates/apps/web/lib/release-scope.ts +47 -0
  94. package/templates/apps/web/lib/server-api.ts +1 -1
  95. package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
  96. package/templates/customizations.yaml +37 -0
  97. package/templates/database/prisma.config.ts +10 -14
  98. package/templates/database/seed-test.ts +2 -2
  99. package/templates/database/seed.ts +32 -5
  100. package/templates/package.json +12 -6
  101. package/templates/pnpm-workspace.yaml +0 -1
  102. package/templates/project.yaml +16 -8
  103. package/templates/tools/jest/reporters.cjs +65 -0
  104. package/templates/tools/lint-architecture.ts +757 -7
  105. package/templates/tsconfig.json +1 -2
  106. package/versions.json +48 -35
  107. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
  108. package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
  109. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
  110. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
  111. package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
  112. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
  113. package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
  114. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
  115. package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
  116. package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
  117. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
  118. package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
  119. package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
  120. package/templates/apps/api/src/bin/spokes.ts +0 -198
  121. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
  122. package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
  123. package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
  124. package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
  125. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
  126. package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
  127. package/templates/apps/api/src/config/index.ts +0 -596
  128. package/templates/apps/api/src/config/modules.ts +0 -83
  129. package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
  130. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
  131. package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
  132. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
  133. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
  134. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
  135. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
  136. package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
  137. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
  138. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
  139. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
  140. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
  141. package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
  142. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
  143. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
  144. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
  145. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
  146. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
  147. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
  148. package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -292
  149. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
  150. package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
  151. package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
  152. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
  153. package/templates/apps/api/src/lib/agent-store.ts +0 -613
  154. package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
  155. package/templates/apps/api/src/lib/consent-store.ts +0 -363
  156. package/templates/apps/api/src/lib/content-adapter.ts +0 -112
  157. package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
  158. package/templates/apps/api/src/lib/error-serializer.ts +0 -164
  159. package/templates/apps/api/src/lib/errors.ts +0 -95
  160. package/templates/apps/api/src/lib/file-fallback.ts +0 -87
  161. package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
  162. package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
  163. package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
  164. package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
  165. package/templates/apps/api/src/lib/license-key-store.ts +0 -45
  166. package/templates/apps/api/src/lib/locales.ts +0 -201
  167. package/templates/apps/api/src/lib/outbound-http.ts +0 -127
  168. package/templates/apps/api/src/lib/prisma.ts +0 -21
  169. package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
  170. package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
  171. package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
  172. package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
  173. package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
  174. package/templates/apps/api/src/lib/site.ts +0 -254
  175. package/templates/apps/api/src/lib/slice-load.ts +0 -90
  176. package/templates/apps/api/src/lib/spoke-store.ts +0 -180
  177. package/templates/apps/api/src/lib/stripe.ts +0 -318
  178. package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
  179. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
  180. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
  181. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
  182. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
  183. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
  184. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
  185. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
  186. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
  187. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
  188. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
  189. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
  190. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
  191. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
  192. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
  193. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
  194. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
  195. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
  196. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
  197. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
  198. package/templates/apps/api/src/middleware/auth.ts +0 -864
  199. package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
  200. package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
  201. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -264
  202. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
  203. package/templates/apps/api/src/openapi/index.ts +0 -18
  204. package/templates/apps/api/src/openapi/spec.ts +0 -1815
  205. package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
  206. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
  207. package/templates/apps/api/src/routes/aeo/index.ts +0 -107
  208. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
  209. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
  210. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
  211. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
  212. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
  213. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
  214. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
  215. package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
  216. package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
  217. package/templates/apps/api/src/routes/auth/user.ts +0 -305
  218. package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -325
  219. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
  220. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1300
  221. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
  222. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
  223. package/templates/apps/api/src/routes/checkout/index.ts +0 -34
  224. package/templates/apps/api/src/routes/checkout/session.ts +0 -171
  225. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
  226. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
  227. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
  228. package/templates/apps/api/src/routes/consent/account.ts +0 -268
  229. package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
  230. package/templates/apps/api/src/routes/consent/index.ts +0 -26
  231. package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
  232. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
  233. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
  234. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
  235. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
  236. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
  237. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
  238. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
  239. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
  240. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
  241. package/templates/apps/api/src/routes/content/get-page.ts +0 -268
  242. package/templates/apps/api/src/routes/content/index.ts +0 -49
  243. package/templates/apps/api/src/routes/content/list-pages.ts +0 -95
  244. package/templates/apps/api/src/routes/content/list-types.ts +0 -19
  245. package/templates/apps/api/src/routes/content/offerings.ts +0 -184
  246. package/templates/apps/api/src/routes/content/pricing.ts +0 -176
  247. package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
  248. package/templates/apps/api/src/routes/content/search.ts +0 -129
  249. package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
  250. package/templates/apps/api/src/routes/content/slug.ts +0 -9
  251. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
  252. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
  253. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
  254. package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
  255. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
  256. package/templates/apps/api/src/routes/leads/index.ts +0 -573
  257. package/templates/apps/api/src/routes/leads/list.ts +0 -104
  258. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
  259. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
  260. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
  261. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -480
  262. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -465
  263. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
  264. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
  265. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
  266. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
  267. package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
  268. package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
  269. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
  270. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
  271. package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
  272. package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
  273. package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
  274. package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
  275. package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
  276. package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
  277. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
  278. package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
  279. package/templates/apps/api/src/routes/requests/index.ts +0 -54
  280. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
  281. package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
  282. package/templates/apps/api/src/routes/webhooks/README.md +0 -398
  283. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
  284. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
  285. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -448
  286. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
  287. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
  288. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
  289. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
  290. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
  291. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
  292. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
  293. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
  294. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -808
  295. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
  296. package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
  297. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
  298. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2026
  299. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -528
  300. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
  301. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
  302. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
  303. package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
  304. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
  305. package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
  306. package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
  307. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -867
  308. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
  309. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
  310. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
  311. package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
  312. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
  313. package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
  314. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
  315. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
  316. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
  317. package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1176
  318. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -444
  319. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -154
  320. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
  321. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
  322. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
  323. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
  324. package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
  325. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
  326. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
  327. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
  328. package/templates/apps/api/src/services/abandon-email.ts +0 -313
  329. package/templates/apps/api/src/services/aeo-score.ts +0 -325
  330. package/templates/apps/api/src/services/answer-distributions.ts +0 -138
  331. package/templates/apps/api/src/services/audit-log.ts +0 -961
  332. package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
  333. package/templates/apps/api/src/services/consent.ts +0 -834
  334. package/templates/apps/api/src/services/default-tenant.ts +0 -416
  335. package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -755
  336. package/templates/apps/api/src/services/dunning-policy.ts +0 -294
  337. package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
  338. package/templates/apps/api/src/services/entitlements.ts +0 -338
  339. package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
  340. package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
  341. package/templates/apps/api/src/services/lead-promotion.ts +0 -160
  342. package/templates/apps/api/src/services/lead-routing.ts +0 -1372
  343. package/templates/apps/api/src/services/leads-inbox.ts +0 -312
  344. package/templates/apps/api/src/services/listing-config.ts +0 -178
  345. package/templates/apps/api/src/services/magnet-completion.ts +0 -242
  346. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -295
  347. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
  348. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -868
  349. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
  350. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -396
  351. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -681
  352. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
  353. package/templates/apps/api/src/services/offerings/catalog.ts +0 -308
  354. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -385
  355. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
  356. package/templates/apps/api/src/services/offerings/connection.ts +0 -1003
  357. package/templates/apps/api/src/services/offerings/index.ts +0 -614
  358. package/templates/apps/api/src/services/offerings/source.ts +0 -140
  359. package/templates/apps/api/src/services/offerings/store.ts +0 -150
  360. package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
  361. package/templates/apps/api/src/services/person.ts +0 -1188
  362. package/templates/apps/api/src/services/plan-offerings.ts +0 -125
  363. package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
  364. package/templates/apps/api/src/services/project-listings.ts +0 -2073
  365. package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
  366. package/templates/apps/api/src/services/request-confirm.ts +0 -698
  367. package/templates/apps/api/src/services/revalidation.ts +0 -235
  368. package/templates/apps/api/src/services/slack-notify.ts +0 -291
  369. package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
  370. package/templates/apps/api/src/services/usage-credits.ts +0 -340
  371. package/templates/apps/api/src/services/verified-email.ts +0 -71
  372. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
  373. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
  374. package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
  375. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
  376. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
  377. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
  378. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
  379. package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
  380. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
  381. package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
  382. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
  383. package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
  384. package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
  385. package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
  386. package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
  387. package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
  388. package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1151
  389. package/templates/apps/mcp/__tests__/index.test.ts +0 -195
  390. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
  391. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
  392. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -65
  393. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -187
  394. package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
  395. package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
  396. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -165
  397. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
  398. package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -228
  399. package/templates/apps/mcp/__tests__/locale.test.ts +0 -135
  400. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
  401. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
  402. package/templates/apps/mcp/__tests__/read_content.test.ts +0 -474
  403. package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -225
  404. package/templates/apps/mcp/__tests__/search_content.test.ts +0 -256
  405. package/templates/apps/mcp/__tests__/server.test.ts +0 -388
  406. package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
  407. package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -307
  408. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -223
  409. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
  410. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
  411. package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
  412. package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
  413. package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
  414. package/templates/apps/mcp/src/abuse/index.ts +0 -342
  415. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
  416. package/templates/apps/mcp/src/boot.ts +0 -167
  417. package/templates/apps/mcp/src/config/modules.ts +0 -43
  418. package/templates/apps/mcp/src/http-transport.ts +0 -526
  419. package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
  420. package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
  421. package/templates/apps/mcp/src/lib/content-adapter.ts +0 -142
  422. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -139
  423. package/templates/apps/mcp/src/lib/errors.ts +0 -61
  424. package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
  425. package/templates/apps/mcp/src/lib/locales.ts +0 -171
  426. package/templates/apps/mcp/src/lib/prisma.ts +0 -39
  427. package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
  428. package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
  429. package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
  430. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
  431. package/templates/apps/mcp/src/request-context.ts +0 -52
  432. package/templates/apps/mcp/src/server.ts +0 -343
  433. package/templates/apps/mcp/src/serverless-app.ts +0 -88
  434. package/templates/apps/mcp/src/tools/audit.ts +0 -127
  435. package/templates/apps/mcp/src/tools/capture_lead.ts +0 -64
  436. package/templates/apps/mcp/src/tools/create_project.ts +0 -134
  437. package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
  438. package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
  439. package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
  440. package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
  441. package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
  442. package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
  443. package/templates/apps/mcp/src/tools/index.ts +0 -137
  444. package/templates/apps/mcp/src/tools/list_pages.ts +0 -74
  445. package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
  446. package/templates/apps/mcp/src/tools/proposals.ts +0 -27
  447. package/templates/apps/mcp/src/tools/purchase.ts +0 -205
  448. package/templates/apps/mcp/src/tools/read_content.ts +0 -75
  449. package/templates/apps/mcp/src/tools/request_callback.ts +0 -59
  450. package/templates/apps/mcp/src/tools/search_content.ts +0 -67
  451. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -57
  452. package/templates/apps/mcp/src/workspace-server.ts +0 -224
  453. package/templates/database/CHANGELOG.md +0 -961
  454. package/templates/database/LICENSE +0 -202
  455. package/templates/database/NOTICE +0 -2
  456. package/templates/database/README.md +0 -243
  457. package/templates/database/__tests__/agents.db.test.ts +0 -320
  458. package/templates/database/__tests__/appointment.db.test.ts +0 -106
  459. package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
  460. package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
  461. package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
  462. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
  463. package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
  464. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
  465. package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
  466. package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
  467. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
  468. package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
  469. package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
  470. package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
  471. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
  472. package/templates/database/__tests__/flows-presets.test.ts +0 -173
  473. package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
  474. package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
  475. package/templates/database/__tests__/member-area.db.test.ts +0 -257
  476. package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
  477. package/templates/database/__tests__/member-contract.db.test.ts +0 -413
  478. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
  479. package/templates/database/__tests__/offerings-migration.test.ts +0 -197
  480. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
  481. package/templates/database/__tests__/offerings.db.test.ts +0 -303
  482. package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
  483. package/templates/database/__tests__/person-contact.db.test.ts +0 -563
  484. package/templates/database/__tests__/person-notes.db.test.ts +0 -249
  485. package/templates/database/__tests__/person.db.test.ts +0 -586
  486. package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
  487. package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
  488. package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
  489. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
  490. package/templates/database/__tests__/seed.test.ts +0 -240
  491. package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
  492. package/templates/database/__tests__/tenancy.test.ts +0 -141
  493. package/templates/database/__tests__/user-cascade.test.ts +0 -140
  494. package/templates/database/_gitignore +0 -8
  495. package/templates/database/auth/.gitkeep +0 -0
  496. package/templates/database/auth/schema.prisma +0 -641
  497. package/templates/database/config/.gitkeep +0 -0
  498. package/templates/database/config/schema.prisma +0 -441
  499. package/templates/database/content/.gitkeep +0 -0
  500. package/templates/database/content/schema.prisma +0 -339
  501. package/templates/database/eslint.config.mjs +0 -69
  502. package/templates/database/flows/listing-diagnostic.ts +0 -182
  503. package/templates/database/flows/presets.ts +0 -315
  504. package/templates/database/inbox/.gitkeep +0 -0
  505. package/templates/database/inbox/README.md +0 -3
  506. package/templates/database/inbox/__tests__/schema.test.ts +0 -44
  507. package/templates/database/inbox/schema.prisma +0 -1447
  508. package/templates/database/jest.config.cjs +0 -36
  509. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
  510. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
  511. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
  512. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
  513. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
  514. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
  515. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
  516. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
  517. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
  518. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
  519. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
  520. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
  521. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
  522. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
  523. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
  524. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
  525. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
  526. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
  527. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
  528. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
  529. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
  530. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
  531. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
  532. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
  533. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
  534. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
  535. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
  536. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
  537. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
  538. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
  539. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
  540. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
  541. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
  542. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
  543. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
  544. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
  545. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
  546. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
  547. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
  548. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
  549. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
  550. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
  551. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
  552. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
  553. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
  554. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
  555. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
  556. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
  557. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
  558. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
  559. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
  560. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
  561. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
  562. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
  563. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
  564. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
  565. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
  566. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
  567. package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
  568. package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
  569. package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
  570. package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
  571. package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
  572. package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
  573. package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
  574. package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
  575. package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
  576. package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
  577. package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
  578. package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
  579. package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
  580. package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
  581. package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
  582. package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
  583. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
  584. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
  585. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
  586. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
  587. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
  588. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
  589. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
  590. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
  591. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
  592. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
  593. package/templates/database/migrations/migration_lock.toml +0 -3
  594. package/templates/database/ops/.gitkeep +0 -0
  595. package/templates/database/ops/schema.prisma +0 -43
  596. package/templates/database/package.json +0 -89
  597. package/templates/database/schema.prisma +0 -71
  598. package/templates/database/scripts/db-generate-locked.sh +0 -80
  599. package/templates/database/scripts/person-backfill.sql +0 -132
  600. package/templates/database/tenancy.ts +0 -183
  601. package/templates/database/tsconfig.build.json +0 -16
  602. package/templates/database/tsconfig.flows.json +0 -15
  603. package/templates/database/tsconfig.json +0 -16
  604. package/templates/database/tsconfig.tenancy.json +0 -14
@@ -1,455 +0,0 @@
1
- /**
2
- * The hub's sign-in-client store — the ONE data-access boundary for a spoke's
3
- * sign-in (#7894, spec docs/specs/7894-the-hub-signs-in-its-spec.md D3, D5, D6).
4
- *
5
- * A spoke signs its visitors in through this hub: the hub is the OAuth-style
6
- * provider and each spoke a confidential client. This file is the only one in
7
- * `apps/api` that names `prisma.oAuthClient` and `prisma.oAuthAuthorization`
8
- * (the web app's `onPasswordReset` is the one other writer, through the Better
9
- * Auth Prisma client it already holds). It also owns the short-lived
10
- * authorization-code rows, which live in `Verification` — the table Better
11
- * Auth already keeps short-lived, single-use secrets in.
12
- *
13
- * A SPOKE'S CLIENT IS ITS `Spoke` ROW'S ID. `OAuthClient.clientId` equals the
14
- * `Spoke.id` it serves, so the binding is by value and no column is added.
15
- * `OAuthAuthorization.clientId` is the FK to the client row's own `id`
16
- * (`oauthc_…`), not to the public `clientId`.
17
- *
18
- * NOTHING SECRET IS STORED IN CLEAR. The client secret, every code and every
19
- * credential are kept as lowercase hex SHA-256 digests: each carries 256 bits
20
- * of entropy, so a fast digest of a lookup key leaks nothing usable.
21
- *
22
- * Three kinds of caller, kept apart:
23
- * - the service (`services/hub-sign-in.ts`) calls the client reads, the code
24
- * functions and the authorization writes;
25
- * - the preHandler branch (`middleware/auth.ts`) calls
26
- * `findAuthorizationByCredentialHash` only;
27
- * - the operator CLI (`bin/spokes.ts`) calls `upsertSignInClient` and
28
- * `disableSignInClient` only. No route imports those two.
29
- *
30
- * Nothing here caches a row: a revocation takes effect on the next request.
31
- */
32
- import { createHash, randomBytes } from "node:crypto";
33
-
34
- import { prisma } from "./prisma.js";
35
- import { findSpokeById } from "./spoke-store.js";
36
-
37
- /** Every hub-issued credential starts with this, so a leaked one is recognisable. */
38
- export const HUB_SESSION_PREFIX = "ailk_hst_";
39
-
40
- /** Every sign-in client secret starts with this. */
41
- export const HUB_CLIENT_SECRET_PREFIX = "ailk_hcs_";
42
-
43
- /** The scope a spoke credential carries: the signed-in person's account area. */
44
- export const HUB_SIGN_IN_SCOPE = "account";
45
-
46
- /** The `Verification.identifier` prefix of an authorization-code row. */
47
- const CODE_IDENTIFIER_PREFIX = "hub-sign-in-code:";
48
-
49
- /** Lowercase hex SHA-256 — the stored form of every secret here. */
50
- export function sha256Hex(value: string): string {
51
- return createHash("sha256").update(value).digest("hex");
52
- }
53
-
54
- /** 32 random bytes in base64url (43 characters). */
55
- function randomToken(): string {
56
- return randomBytes(32).toString("base64url");
57
- }
58
-
59
- /** A new authorization code. */
60
- export function mintCode(): string {
61
- return randomToken();
62
- }
63
-
64
- /** A new credential: `ailk_hst_` + 32 random bytes in base64url. */
65
- export function mintCredential(): string {
66
- return `${HUB_SESSION_PREFIX}${randomToken()}`;
67
- }
68
-
69
- /** A new client secret: `ailk_hcs_` + 32 random bytes in base64url. */
70
- export function mintClientSecret(): string {
71
- return `${HUB_CLIENT_SECRET_PREFIX}${randomToken()}`;
72
- }
73
-
74
- // ── The client ───────────────────────────────────────────────────────────────
75
-
76
- export interface SignInClientRow {
77
- /** The row's own id (`oauthc_…`) — what an authorization's FK points at. */
78
- id: string;
79
- /** The public identifier: the `Spoke.id` this client serves. */
80
- clientId: string;
81
- /** SHA-256 hex of the client secret. */
82
- clientSecret: string;
83
- redirectUris: string[];
84
- enabled: boolean;
85
- }
86
-
87
- const CLIENT_SELECT = {
88
- id: true,
89
- clientId: true,
90
- clientSecret: true,
91
- redirectUris: true,
92
- enabled: true,
93
- } as const;
94
-
95
- /** The client for one spoke, or `null`. */
96
- export async function findClientByClientId(
97
- clientId: string,
98
- ): Promise<SignInClientRow | null> {
99
- return prisma.oAuthClient.findUnique({
100
- where: { clientId },
101
- select: CLIENT_SELECT,
102
- });
103
- }
104
-
105
- /** What the hub's sign-in page may show about a spoke (#8790 D2). */
106
- export interface SignInClientInfo {
107
- clientId: string;
108
- /** The spoke's display name from the registry. */
109
- name: string;
110
- /** The origin of the client's first registered redirect URI. */
111
- origin: string;
112
- }
113
-
114
- /**
115
- * The public shape of one spoke's sign-in client, or `null` when the client
116
- * is missing, disabled, or its spoke is revoked (#8790 D2). Only the
117
- * registry decides what a sign-in page may name — never a query parameter.
118
- */
119
- export async function findSignInClientInfo(
120
- clientId: string,
121
- ): Promise<SignInClientInfo | null> {
122
- const client = await findClientByClientId(clientId);
123
- if (client === null || !client.enabled) return null;
124
- const spoke = await findSpokeById(clientId);
125
- if (spoke === null || spoke.revokedAt !== null) return null;
126
- const first = client.redirectUris[0];
127
- if (first === undefined) return null;
128
- let origin: string;
129
- try {
130
- origin = new URL(first).origin;
131
- } catch {
132
- return null;
133
- }
134
- return { clientId, name: spoke.name, origin };
135
- }
136
-
137
- /**
138
- * Create or update a spoke's sign-in client (the operator CLI). Re-running
139
- * rotates the secret: `clientSecret` is replaced by the new digest, so the
140
- * previous secret stops working at once. Returns nothing secret — the CALLER
141
- * minted `secret` and prints it once.
142
- */
143
- export async function upsertSignInClient(params: {
144
- spokeId: string;
145
- name: string;
146
- redirectUri: string;
147
- secret: string;
148
- }): Promise<void> {
149
- const data = {
150
- name: params.name,
151
- clientSecret: sha256Hex(params.secret),
152
- redirectUris: [params.redirectUri],
153
- scopes: [HUB_SIGN_IN_SCOPE],
154
- trusted: true,
155
- enabled: true,
156
- };
157
- await prisma.oAuthClient.upsert({
158
- where: { clientId: params.spokeId },
159
- create: { clientId: params.spokeId, ...data },
160
- update: data,
161
- });
162
- }
163
-
164
- /** The one path a spoke's sign-in callback lives at (spec 7894 D3, D7). */
165
- export const HUB_CALLBACK_PATH = "/api/hub-session/callback";
166
-
167
- const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1"]);
168
-
169
- /**
170
- * Validate a callback URL an operator registers for a spoke (D3): `https:`
171
- * (or `http:` on a loopback host), the path EXACTLY `/api/hub-session/callback`,
172
- * and no query, fragment or userinfo. Returns the canonical origin + path the
173
- * spoke will send back, or `null`.
174
- */
175
- export function canonicalRedirectUri(raw: string): string | null {
176
- let url: URL;
177
- try {
178
- url = new URL(raw);
179
- } catch {
180
- return null;
181
- }
182
- const secure =
183
- url.protocol === "https:" ||
184
- (url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname));
185
- if (!secure) return null;
186
- if (url.pathname !== HUB_CALLBACK_PATH) return null;
187
- if (url.search !== "" || url.hash !== "") return null;
188
- // `URL` drops an empty `?` / `#`, so the raw text is checked too.
189
- if (raw.includes("?") || raw.includes("#")) return null;
190
- if (url.username !== "" || url.password !== "") return null;
191
- return `${url.origin}${HUB_CALLBACK_PATH}`;
192
- }
193
-
194
- export type RegisterSignInClientResult =
195
- | { ok: true; spokeId: string; secret: string }
196
- | {
197
- ok: false;
198
- reason: "invalid-redirect-uri" | "spoke-not-found" | "spoke-revoked";
199
- };
200
-
201
- /**
202
- * The operator CLI's `sign-in-client` (D3): refuse an invalid callback, an
203
- * unknown spoke or a revoked one; otherwise upsert the client and return the
204
- * freshly minted secret, which the caller prints ONCE. Re-running rotates it.
205
- */
206
- export async function registerSignInClient(params: {
207
- spokeId: string;
208
- redirectUri: string;
209
- }): Promise<RegisterSignInClientResult> {
210
- const redirectUri = canonicalRedirectUri(params.redirectUri);
211
- if (redirectUri === null)
212
- return { ok: false, reason: "invalid-redirect-uri" };
213
-
214
- const spoke = await findSpokeById(params.spokeId);
215
- if (!spoke) return { ok: false, reason: "spoke-not-found" };
216
- if (spoke.revokedAt) return { ok: false, reason: "spoke-revoked" };
217
-
218
- const secret = mintClientSecret();
219
- await upsertSignInClient({
220
- spokeId: spoke.id,
221
- name: spoke.name,
222
- redirectUri,
223
- secret,
224
- });
225
- return { ok: true, spokeId: spoke.id, secret };
226
- }
227
-
228
- /** Switch a spoke's client off. `false` when it has none. */
229
- export async function disableSignInClient(spokeId: string): Promise<boolean> {
230
- const { count } = await prisma.oAuthClient.updateMany({
231
- where: { clientId: spokeId },
232
- data: { enabled: false },
233
- });
234
- return count === 1;
235
- }
236
-
237
- // ── The person ───────────────────────────────────────────────────────────────
238
-
239
- export interface SignInUserRow {
240
- id: string;
241
- name: string | null;
242
- email: string;
243
- emailVerified: boolean;
244
- createdAt: Date;
245
- }
246
-
247
- const USER_SELECT = {
248
- id: true,
249
- name: true,
250
- email: true,
251
- emailVerified: true,
252
- createdAt: true,
253
- } as const;
254
-
255
- /** The five fields a credential speaks for, read live. */
256
- export async function findSignInUser(
257
- userId: string,
258
- ): Promise<SignInUserRow | null> {
259
- return prisma.user.findUnique({
260
- where: { id: userId },
261
- select: USER_SELECT,
262
- });
263
- }
264
-
265
- // ── Authorization codes (`Verification` rows) ────────────────────────────────
266
-
267
- export interface CodePayload {
268
- userId: string;
269
- clientId: string;
270
- redirectUri: string;
271
- codeChallenge: string;
272
- }
273
-
274
- export interface CodeRow {
275
- id: string;
276
- expiresAt: Date;
277
- payload: CodePayload | null;
278
- }
279
-
280
- function codeIdentifier(code: string): string {
281
- return `${CODE_IDENTIFIER_PREFIX}${sha256Hex(code)}`;
282
- }
283
-
284
- /** Store one single-use code, valid until `expiresAt`. */
285
- export async function writeCode(params: {
286
- code: string;
287
- payload: CodePayload;
288
- expiresAt: Date;
289
- }): Promise<void> {
290
- await prisma.verification.create({
291
- data: {
292
- identifier: codeIdentifier(params.code),
293
- value: JSON.stringify(params.payload),
294
- expiresAt: params.expiresAt,
295
- },
296
- });
297
- }
298
-
299
- function parsePayload(value: string): CodePayload | null {
300
- try {
301
- const parsed: unknown = JSON.parse(value);
302
- if (typeof parsed !== "object" || parsed === null) return null;
303
- const { userId, clientId, redirectUri, codeChallenge } = parsed as Record<
304
- string,
305
- unknown
306
- >;
307
- if (
308
- typeof userId === "string" &&
309
- typeof clientId === "string" &&
310
- typeof redirectUri === "string" &&
311
- typeof codeChallenge === "string"
312
- ) {
313
- return { userId, clientId, redirectUri, codeChallenge };
314
- }
315
- return null;
316
- } catch {
317
- return null;
318
- }
319
- }
320
-
321
- async function findCodeRow(code: string): Promise<CodeRow | null> {
322
- const row = await prisma.verification.findFirst({
323
- where: { identifier: codeIdentifier(code) },
324
- select: { id: true, value: true, expiresAt: true },
325
- });
326
- if (!row) return null;
327
- return {
328
- id: row.id,
329
- expiresAt: row.expiresAt,
330
- payload: parsePayload(row.value),
331
- };
332
- }
333
-
334
- /**
335
- * Consume a code exactly once: read its row, then delete it by id and require
336
- * a count of 1. Two concurrent exchanges of one code both read it, but only
337
- * the one whose `deleteMany` removes the row gets it. `null` for an unknown
338
- * code or a lost race — the code is gone either way.
339
- */
340
- export async function consumeCode(code: string): Promise<CodeRow | null> {
341
- const row = await findCodeRow(code);
342
- if (!row) return null;
343
- const { count } = await prisma.verification.deleteMany({
344
- where: { id: row.id },
345
- });
346
- return count === 1 ? row : null;
347
- }
348
-
349
- /**
350
- * Delete one client's unexpired code without exchanging it (the spoke's
351
- * callback burns every code it cannot complete, SEC-7894-4). A code minted for
352
- * another client is left alone. `true` when a row was deleted.
353
- */
354
- export async function burnCode(params: {
355
- code: string;
356
- clientId: string;
357
- now: Date;
358
- }): Promise<boolean> {
359
- const row = await findCodeRow(params.code);
360
- if (!row || row.payload === null) return false;
361
- if (row.payload.clientId !== params.clientId) return false;
362
- if (row.expiresAt.getTime() <= params.now.getTime()) return false;
363
- const { count } = await prisma.verification.deleteMany({
364
- where: { id: row.id },
365
- });
366
- return count === 1;
367
- }
368
-
369
- /** Sweep expired code rows. Best-effort housekeeping on every exchange. */
370
- export async function deleteExpiredCodes(now: Date): Promise<void> {
371
- await prisma.verification.deleteMany({
372
- where: {
373
- identifier: { startsWith: CODE_IDENTIFIER_PREFIX },
374
- expiresAt: { lte: now },
375
- },
376
- });
377
- }
378
-
379
- // ── The grant (`OAuthAuthorization`) ─────────────────────────────────────────
380
-
381
- /**
382
- * Issue the credential for (person, client): one row per pair, so a new
383
- * sign-in rotates the previous credential (spec 7894 Clarifications). The
384
- * digest replaces the old one and the row is un-revoked.
385
- */
386
- export async function upsertAuthorization(params: {
387
- userId: string;
388
- clientRowId: string;
389
- accessTokenHash: string;
390
- expiresAt: Date;
391
- }): Promise<void> {
392
- await prisma.oAuthAuthorization.upsert({
393
- where: {
394
- userId_clientId: { userId: params.userId, clientId: params.clientRowId },
395
- },
396
- create: {
397
- userId: params.userId,
398
- clientId: params.clientRowId,
399
- scopes: [HUB_SIGN_IN_SCOPE],
400
- accessToken: params.accessTokenHash,
401
- expiresAt: params.expiresAt,
402
- },
403
- update: {
404
- scopes: [HUB_SIGN_IN_SCOPE],
405
- accessToken: params.accessTokenHash,
406
- expiresAt: params.expiresAt,
407
- revokedAt: null,
408
- },
409
- });
410
- }
411
-
412
- /** Revoke one client's credential by digest. `true` when a live row matched. */
413
- export async function revokeAuthorization(params: {
414
- clientRowId: string;
415
- accessTokenHash: string;
416
- now: Date;
417
- }): Promise<boolean> {
418
- const { count } = await prisma.oAuthAuthorization.updateMany({
419
- where: {
420
- clientId: params.clientRowId,
421
- accessToken: params.accessTokenHash,
422
- revokedAt: null,
423
- },
424
- data: { revokedAt: params.now },
425
- });
426
- return count === 1;
427
- }
428
-
429
- export interface AuthorizationLookupRow {
430
- userId: string;
431
- expiresAt: Date;
432
- revokedAt: Date | null;
433
- client: { clientId: string; enabled: boolean };
434
- user: { emailVerified: boolean };
435
- }
436
-
437
- /**
438
- * The preHandler's one read: a credential's digest to its grant, with the
439
- * client's public id and enabled flag and the person's verified flag in the
440
- * same query.
441
- */
442
- export async function findAuthorizationByCredentialHash(
443
- accessTokenHash: string,
444
- ): Promise<AuthorizationLookupRow | null> {
445
- return prisma.oAuthAuthorization.findUnique({
446
- where: { accessToken: accessTokenHash },
447
- select: {
448
- userId: true,
449
- expiresAt: true,
450
- revokedAt: true,
451
- client: { select: { clientId: true, enabled: true } },
452
- user: { select: { emailVerified: true } },
453
- },
454
- });
455
- }
@@ -1,122 +0,0 @@
1
- /**
2
- * Lead capture store — always-on JSONL writer (Issue #27 Unit 1).
3
- *
4
- * Appends one JSON line per successful lead submission to apps/api/leads.jsonl
5
- * (or LEAD_CAPTURE_FILE if set). Uses fs.appendFile with flag:'a' which maps to
6
- * POSIX O_APPEND — the kernel guarantees atomicity for writes ≤ PIPE_BUF on
7
- * local filesystems, making this safe for concurrent processes/requests.
8
- *
9
- * Semantic difference from B6 file-fallback:
10
- * B6 file-fallback (.ailk/inbox/) — engaged only when the DB throws (salvage path)
11
- * This module — always-on canonical AX surface; disabled explicitly via env, not by DB presence
12
- *
13
- * Env vars (all read inside function bodies — module is import-side-effect-free):
14
- * LEAD_CAPTURE_FILE — output path (default: apps/api/leads.jsonl relative to cwd)
15
- *
16
- * The default path is LOCAL-ONLY (#6730 D3). In production
17
- * (`NODE_ENV=production`) with `LEAD_CAPTURE_FILE` unset, the write is skipped:
18
- * on serverless hosting a file under the process cwd does not outlive the
19
- * instance, so it is not a record of anything. An operator with a durable
20
- * volume can keep a side copy by setting `LEAD_CAPTURE_FILE` explicitly —
21
- * a copy only: in production it never makes a lead count as delivered
22
- * (`lib/lead-delivery.ts` needs a database or the email vars).
23
- *
24
- * LEAD_CAPTURE_FILE_DISABLED — set to "true" to skip writes (opt-out)
25
- * LEAD_CAPTURE_INCLUDE_IP — set to "true" to include metadata.ip in the record
26
- *
27
- * PII discipline:
28
- * IP is excluded from the written record by default.
29
- * No other PII is filtered — `data` carries whatever the route gave us.
30
- * Callers are responsible for what they put in `data`.
31
- */
32
-
33
- import * as fs from "fs/promises";
34
- import * as path from "path";
35
-
36
- import type { LeadCaptureRecord } from "@working-theory/validation";
37
-
38
- // Re-export so consumers can import from one place.
39
- export type { LeadCaptureRecord };
40
-
41
- export type AppendResult =
42
- | { ok: true; skipped?: true }
43
- | { ok: false; error: string };
44
-
45
- /**
46
- * Append one lead record as a JSONL line.
47
- *
48
- * Always resolves — never throws. Returns ok:false on fs errors so the caller
49
- * can log and continue without crashing the request.
50
- */
51
- export async function appendLeadRecord(
52
- record: LeadCaptureRecord,
53
- ): Promise<AppendResult> {
54
- // Read env inside the function — no module-level side effects.
55
- const disabled = process.env.LEAD_CAPTURE_FILE_DISABLED === "true";
56
- if (disabled) {
57
- return { ok: true, skipped: true };
58
- }
59
- if (process.env.NODE_ENV === "production" && !process.env.LEAD_CAPTURE_FILE) {
60
- return { ok: true, skipped: true };
61
- }
62
-
63
- const includeIp = process.env.LEAD_CAPTURE_INCLUDE_IP === "true";
64
- const outputPath = resolveOutputPath();
65
-
66
- // Strip IP from metadata unless explicitly opted in.
67
- const cleanMeta = includeIp
68
- ? record.metadata
69
- : Object.fromEntries(
70
- Object.entries(record.metadata).filter(([k]) => k !== "ip"),
71
- );
72
-
73
- const line = JSON.stringify({ ...record, metadata: cleanMeta }) + "\n";
74
-
75
- try {
76
- await fs.appendFile(outputPath, line, { flag: "a", encoding: "utf8" });
77
- return { ok: true };
78
- } catch (err) {
79
- const message = err instanceof Error ? err.message : String(err);
80
- return { ok: false, error: message };
81
- }
82
- }
83
-
84
- /**
85
- * Startup-time validation: if LEAD_CAPTURE_FILE points at a path whose parent
86
- * directory does not exist, throw immediately so the server fails fast rather
87
- * than erroring on first write.
88
- *
89
- * Call from server.ts build() before registering routes.
90
- * No-op when LEAD_CAPTURE_FILE is unset or LEAD_CAPTURE_FILE_DISABLED=true.
91
- */
92
- export async function validateLeadCaptureDir(): Promise<void> {
93
- const disabled = process.env.LEAD_CAPTURE_FILE_DISABLED === "true";
94
- const filePath = process.env.LEAD_CAPTURE_FILE;
95
-
96
- if (!filePath || disabled) {
97
- return;
98
- }
99
-
100
- const dir = path.dirname(path.resolve(filePath));
101
-
102
- try {
103
- await fs.access(dir);
104
- } catch {
105
- throw new Error(
106
- `LEAD_CAPTURE_FILE directory does not exist: "${dir}". ` +
107
- `Create the directory or unset LEAD_CAPTURE_FILE.`,
108
- );
109
- }
110
- }
111
-
112
- // ─── Internal ─────────────────────────────────────────────────────────────────
113
-
114
- function resolveOutputPath(): string {
115
- const envPath = process.env.LEAD_CAPTURE_FILE;
116
- if (envPath) {
117
- return path.resolve(envPath);
118
- }
119
- // Default: apps/api/leads.jsonl relative to the process cwd.
120
- // In production (Vercel function or Node standalone), cwd is the project root.
121
- return path.resolve(process.cwd(), "apps/api/leads.jsonl");
122
- }
@@ -1,52 +0,0 @@
1
- /**
2
- * @file lead-delivery.ts
3
- * @description Where a captured lead goes, resolved from the environment (#6730 D1).
4
- *
5
- * inbox — `DATABASE_URL` is set: the database is the destination (the lead
6
- * inbox at `/leads`); the owner email is still sent best-effort.
7
- * email — no database, but `RESEND_API_KEY` plus both notification
8
- * addresses are set: the owner email IS the delivery.
9
- * local — neither, outside production (`pnpm dev`, tests): the local file
10
- * fallback + `leads.jsonl`, so local work needs nothing configured.
11
- * none — neither, in production: nothing is accepted, so no visitor is
12
- * ever told a message was sent when it reached nobody.
13
- *
14
- * A key alone delivers nothing (`sendEmail()` also needs both addresses), so
15
- * it is not counted as configured. `LEAD_CAPTURE_FILE_DISABLED=true` removes
16
- * the local file path, so outside production it resolves to `none` too.
17
- *
18
- * Import-side-effect-free; the environment is read at call time.
19
- */
20
-
21
- export type LeadDelivery = "inbox" | "email" | "local" | "none";
22
-
23
- export type LeadDeliveryKind = "submit" | "subscribe" | "callback";
24
-
25
- export function resolveLeadDelivery(
26
- env: NodeJS.ProcessEnv = process.env,
27
- ): LeadDelivery {
28
- if (env.DATABASE_URL) return "inbox";
29
- if (
30
- env.RESEND_API_KEY &&
31
- env.AILK_LEAD_NOTIFICATION_TO &&
32
- env.AILK_LEAD_NOTIFICATION_FROM
33
- ) {
34
- return "email";
35
- }
36
- if (env.NODE_ENV !== "production" && env.LEAD_CAPTURE_FILE_DISABLED !== "true") {
37
- return "local";
38
- }
39
- return "none";
40
- }
41
-
42
- /**
43
- * Whether a delivery mode accepts a lead of this kind. A newsletter
44
- * subscription is a list entry, not a message — emailing the owner one
45
- * address per signup is not a list — so `subscribe` needs somewhere to keep
46
- * it (the database, or the local file in development).
47
- */
48
- export function acceptsKind(d: LeadDelivery, kind: LeadDeliveryKind): boolean {
49
- if (d === "none") return false;
50
- if (kind === "subscribe") return d === "inbox" || d === "local";
51
- return true;
52
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * Registers the durable home of a renewed licence key (#6677 DD-6).
3
- *
4
- * `@working-theory/license` renews the deployment's key before it lapses and
5
- * keeps the renewed key in a `LicenseKeyStore`. Its default store is a file,
6
- * which a Vercel redeploy wipes — so a redeployed site would fall back to the
7
- * older `AILK_LICENSE_KEY` and, past the renewal grace, to free. With a
8
- * database configured, this registers the store backed by ONE deployment-wide
9
- * `SiteSetting` row, `(DEFAULT_WORKSPACE_ID, "license.renewed_key")`, shared
10
- * by this app, apps/mcp and apps/web.
11
- *
12
- * The row is deployment-wide, not tenant data: the licence is the
13
- * deployment's, so it sits under the seeded default workspace in single- and
14
- * multi-tenant builds alike (the named tenant-scope exclusion in
15
- * architecture.yaml). A DB-less scaffold keeps the file store.
16
- */
17
-
18
- import { DEFAULT_WORKSPACE_ID } from "@working-theory/database/tenancy";
19
- import {
20
- createSiteSettingLicenseKeyStore,
21
- setLicenseKeyStore,
22
- } from "@working-theory/license";
23
- import { logger } from "@working-theory/observability";
24
-
25
- import { prisma } from "./prisma.js";
26
-
27
- /**
28
- * Register the SiteSetting-backed store when `DATABASE_URL` is set. An
29
- * explicitly set `AILK_LICENSE_STORAGE_PATH` is the operator choosing the
30
- * file store, and is honoured. Never throws: a failure logs and leaves the
31
- * file store in place.
32
- */
33
- export async function registerLicenseKeyStore(): Promise<void> {
34
- if (!process.env.DATABASE_URL || process.env.AILK_LICENSE_STORAGE_PATH) return;
35
- try {
36
- setLicenseKeyStore(
37
- createSiteSettingLicenseKeyStore(prisma.siteSetting, DEFAULT_WORKSPACE_ID),
38
- );
39
- } catch (err) {
40
- logger.warn(
41
- { errName: err instanceof Error ? err.name : "UnknownError" },
42
- "[license] could not register the SiteSetting licence-key store — the file store stays in place",
43
- );
44
- }
45
- }