create-ailk 0.24.0 → 0.26.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 (638) hide show
  1. package/README.md +53 -22
  2. package/component-catalog.json +3 -3
  3. package/component-catalog.md +3 -3
  4. package/dist/add-module.js +4 -2
  5. package/dist/add-route.d.ts +12 -1
  6. package/dist/add-route.js +31 -3
  7. package/dist/cli.js +12 -7
  8. package/dist/derive-architecture.d.ts +3 -4
  9. package/dist/derive-architecture.js +65 -29
  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 +2 -1
  14. package/dist/lib/fetch-template-snapshot.js +8 -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 +36 -15
  19. package/dist/lib/module-tier.d.ts +2 -8
  20. package/dist/lib/module-tier.js +13 -12
  21. package/dist/module-architecture.d.ts +20 -3
  22. package/dist/module-architecture.js +129 -552
  23. package/dist/paid-sections.d.ts +25 -1
  24. package/dist/paid-sections.js +88 -3
  25. package/dist/starter-grid.d.ts +6 -6
  26. package/dist/starter-grid.js +12 -5
  27. package/dist/surfaces.js +39 -2
  28. package/dist/template-record.d.ts +21 -3
  29. package/dist/template-record.js +38 -7
  30. package/dist/topology.d.ts +16 -3
  31. package/dist/topology.js +54 -23
  32. package/dist/update.d.ts +10 -1
  33. package/dist/update.js +715 -21
  34. package/package.json +3 -3
  35. package/release-scope.json +2 -2
  36. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +8 -2
  37. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +2 -2
  38. package/site-templates/marketing-site/ailk-template.json +7 -1
  39. package/site-templates/marketing-site/provenance.json +7 -1
  40. package/site-templates/saas-product/ailk-template.json +2 -1
  41. package/site-templates/saas-product/provenance.json +1 -0
  42. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  43. package/templates/.claude/hooks/template-guard.sh +137 -0
  44. package/templates/.claude/rules/extending.md +106 -0
  45. package/templates/.claude/rules/loop-contract.md +2 -2
  46. package/templates/.claude/settings.json +11 -0
  47. package/templates/.env.example +20 -5
  48. package/templates/.github/workflows/ci.yml +7 -4
  49. package/templates/CLAUDE.md +11 -1
  50. package/templates/CONVENTIONS.md +8 -10
  51. package/templates/README.md +14 -13
  52. package/templates/apps/api/.env.example +23 -2
  53. package/templates/apps/api/CLAUDE.md +119 -83
  54. package/templates/apps/api/jest.config.cjs +15 -5
  55. package/templates/apps/api/package.json +16 -20
  56. package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
  57. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
  58. package/templates/apps/api/src/index.ts +1 -1
  59. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +16 -0
  60. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
  61. package/templates/apps/api/src/modules/commerce.ts +10 -0
  62. package/templates/apps/api/src/modules/content-write.ts +10 -0
  63. package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
  64. package/templates/apps/api/src/modules/scheduling.ts +10 -0
  65. package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
  66. package/templates/apps/api/src/modules/workspace.ts +10 -0
  67. package/templates/apps/api/src/server.ts +117 -1882
  68. package/templates/apps/api/vercel.json +2 -2
  69. package/templates/apps/mcp/CLAUDE.md +90 -26
  70. package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
  71. package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
  72. package/templates/apps/mcp/jest.config.cjs +6 -1
  73. package/templates/apps/mcp/package.json +5 -13
  74. package/templates/apps/mcp/src/app.ts +8 -7
  75. package/templates/apps/mcp/src/index.ts +6 -34
  76. package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
  77. package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
  78. package/templates/apps/mcp/src/site.ts +12 -0
  79. package/templates/apps/web/.env.example +1 -1
  80. package/templates/apps/web/CLAUDE.md +31 -3
  81. package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
  82. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +43 -4
  83. package/templates/apps/web/app/[locale]/(auth)/legal-footnote.tsx +35 -0
  84. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +117 -8
  85. package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +14 -37
  86. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +6 -6
  87. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +20 -35
  88. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/page.test.tsx +108 -0
  89. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +111 -5
  90. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +78 -16
  91. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +132 -12
  92. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +53 -1
  93. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +38 -0
  94. package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +4 -2
  95. package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +47 -24
  96. package/templates/apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx +23 -4
  97. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
  98. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
  99. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
  100. package/templates/apps/web/app/[locale]/layout.tsx +33 -13
  101. package/templates/apps/web/app/[locale]/meet/confirmed/BookingHandOff.tsx +128 -0
  102. package/templates/apps/web/app/[locale]/meet/confirmed/__tests__/BookingHandOff.test.tsx +126 -0
  103. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
  104. package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
  105. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
  106. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
  107. package/templates/apps/web/app/api/revalidate/route.ts +3 -3
  108. package/templates/apps/web/auth.ts +10 -6
  109. package/templates/apps/web/i18n/request.ts +49 -1
  110. package/templates/apps/web/jest.config.cjs +1 -0
  111. package/templates/apps/web/lib/__tests__/account-config.test.ts +7 -0
  112. package/templates/apps/web/lib/__tests__/auth-email.test.ts +276 -0
  113. package/templates/apps/web/lib/auth-email.ts +103 -21
  114. package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +72 -23
  115. package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +94 -70
  116. package/templates/apps/web/lib/prisma-for-auth.ts +5 -2
  117. package/templates/apps/web/lib/relay.ts +2 -2
  118. package/templates/apps/web/lib/release-scope.ts +47 -0
  119. package/templates/apps/web/lib/server-api.ts +1 -1
  120. package/templates/apps/web/lib/sign-up-agreements.ts +291 -28
  121. package/templates/apps/web/lib/site-contributions.ts +18 -0
  122. package/templates/apps/web/messages/en.json +186 -20
  123. package/templates/apps/web/messages/site/en.json +1 -0
  124. package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
  125. package/templates/customizations.yaml +37 -0
  126. package/templates/database/prisma.config.ts +10 -14
  127. package/templates/database/seed-test.ts +2 -2
  128. package/templates/database/seed.ts +5 -5
  129. package/templates/package.json +12 -6
  130. package/templates/pnpm-workspace.yaml +0 -1
  131. package/templates/project.yaml +16 -8
  132. package/templates/tools/jest/reporters.cjs +65 -0
  133. package/templates/tools/lint-architecture.ts +553 -7
  134. package/templates/tsconfig.json +1 -2
  135. package/versions.json +49 -36
  136. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
  137. package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
  138. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
  139. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
  140. package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
  141. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
  142. package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
  143. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
  144. package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
  145. package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
  146. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
  147. package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
  148. package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
  149. package/templates/apps/api/src/bin/spokes.ts +0 -198
  150. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
  151. package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
  152. package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
  153. package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
  154. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
  155. package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
  156. package/templates/apps/api/src/config/index.ts +0 -596
  157. package/templates/apps/api/src/config/modules.ts +0 -83
  158. package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
  159. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
  160. package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
  161. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
  162. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
  163. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
  164. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
  165. package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
  166. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
  167. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
  168. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
  169. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
  170. package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
  171. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
  172. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
  173. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
  174. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
  175. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
  176. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
  177. package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
  178. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
  179. package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
  180. package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
  181. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
  182. package/templates/apps/api/src/lib/agent-store.ts +0 -613
  183. package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
  184. package/templates/apps/api/src/lib/consent-store.ts +0 -363
  185. package/templates/apps/api/src/lib/content-adapter.ts +0 -112
  186. package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
  187. package/templates/apps/api/src/lib/error-serializer.ts +0 -164
  188. package/templates/apps/api/src/lib/errors.ts +0 -95
  189. package/templates/apps/api/src/lib/file-fallback.ts +0 -87
  190. package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
  191. package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
  192. package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
  193. package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
  194. package/templates/apps/api/src/lib/license-key-store.ts +0 -45
  195. package/templates/apps/api/src/lib/locales.ts +0 -201
  196. package/templates/apps/api/src/lib/outbound-http.ts +0 -127
  197. package/templates/apps/api/src/lib/prisma.ts +0 -21
  198. package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
  199. package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
  200. package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
  201. package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
  202. package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
  203. package/templates/apps/api/src/lib/site.ts +0 -257
  204. package/templates/apps/api/src/lib/slice-load.ts +0 -90
  205. package/templates/apps/api/src/lib/spoke-store.ts +0 -180
  206. package/templates/apps/api/src/lib/stripe.ts +0 -321
  207. package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
  208. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
  209. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
  210. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
  211. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
  212. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
  213. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
  214. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
  215. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
  216. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
  217. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
  218. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
  219. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
  220. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
  221. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
  222. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
  223. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
  224. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
  225. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
  226. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
  227. package/templates/apps/api/src/middleware/auth.ts +0 -864
  228. package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
  229. package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
  230. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
  231. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
  232. package/templates/apps/api/src/openapi/index.ts +0 -18
  233. package/templates/apps/api/src/openapi/spec.ts +0 -2148
  234. package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
  235. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
  236. package/templates/apps/api/src/routes/aeo/index.ts +0 -107
  237. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
  238. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
  239. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
  240. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
  241. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
  242. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
  243. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
  244. package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
  245. package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
  246. package/templates/apps/api/src/routes/auth/user.ts +0 -305
  247. package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
  248. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
  249. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
  250. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
  251. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
  252. package/templates/apps/api/src/routes/checkout/index.ts +0 -34
  253. package/templates/apps/api/src/routes/checkout/session.ts +0 -171
  254. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
  255. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
  256. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
  257. package/templates/apps/api/src/routes/consent/account.ts +0 -268
  258. package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
  259. package/templates/apps/api/src/routes/consent/index.ts +0 -26
  260. package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
  261. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
  262. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
  263. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
  264. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
  265. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
  266. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
  267. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
  268. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
  269. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
  270. package/templates/apps/api/src/routes/content/get-page.ts +0 -183
  271. package/templates/apps/api/src/routes/content/index.ts +0 -49
  272. package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
  273. package/templates/apps/api/src/routes/content/list-types.ts +0 -19
  274. package/templates/apps/api/src/routes/content/offerings.ts +0 -184
  275. package/templates/apps/api/src/routes/content/pricing.ts +0 -176
  276. package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
  277. package/templates/apps/api/src/routes/content/search.ts +0 -100
  278. package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
  279. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
  280. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
  281. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
  282. package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
  283. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
  284. package/templates/apps/api/src/routes/leads/index.ts +0 -639
  285. package/templates/apps/api/src/routes/leads/list.ts +0 -104
  286. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
  287. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
  288. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
  289. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
  290. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
  291. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
  292. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
  293. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
  294. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
  295. package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
  296. package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
  297. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
  298. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
  299. package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
  300. package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
  301. package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
  302. package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
  303. package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
  304. package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
  305. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
  306. package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
  307. package/templates/apps/api/src/routes/requests/index.ts +0 -54
  308. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
  309. package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
  310. package/templates/apps/api/src/routes/webhooks/README.md +0 -398
  311. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
  312. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
  313. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
  314. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
  315. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
  316. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
  317. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
  318. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
  319. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
  320. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
  321. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
  322. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
  323. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
  324. package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
  325. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
  326. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
  327. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
  328. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
  329. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
  330. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
  331. package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
  332. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
  333. package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
  334. package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
  335. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
  336. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
  337. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
  338. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
  339. package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
  340. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
  341. package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
  342. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
  343. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
  344. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
  345. package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
  346. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
  347. package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
  348. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
  349. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
  350. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
  351. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
  352. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
  353. package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
  354. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
  355. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
  356. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
  357. package/templates/apps/api/src/services/abandon-email.ts +0 -336
  358. package/templates/apps/api/src/services/aeo-score.ts +0 -325
  359. package/templates/apps/api/src/services/answer-distributions.ts +0 -138
  360. package/templates/apps/api/src/services/audit-log.ts +0 -961
  361. package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
  362. package/templates/apps/api/src/services/consent.ts +0 -834
  363. package/templates/apps/api/src/services/default-tenant.ts +0 -416
  364. package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
  365. package/templates/apps/api/src/services/dunning-policy.ts +0 -294
  366. package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
  367. package/templates/apps/api/src/services/entitlements.ts +0 -338
  368. package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
  369. package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
  370. package/templates/apps/api/src/services/lead-promotion.ts +0 -160
  371. package/templates/apps/api/src/services/lead-routing.ts +0 -1372
  372. package/templates/apps/api/src/services/leads-inbox.ts +0 -312
  373. package/templates/apps/api/src/services/listing-config.ts +0 -178
  374. package/templates/apps/api/src/services/magnet-completion.ts +0 -242
  375. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
  376. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
  377. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
  378. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
  379. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
  380. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
  381. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
  382. package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
  383. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
  384. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
  385. package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
  386. package/templates/apps/api/src/services/offerings/index.ts +0 -614
  387. package/templates/apps/api/src/services/offerings/source.ts +0 -140
  388. package/templates/apps/api/src/services/offerings/store.ts +0 -150
  389. package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
  390. package/templates/apps/api/src/services/person.ts +0 -1211
  391. package/templates/apps/api/src/services/plan-offerings.ts +0 -125
  392. package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
  393. package/templates/apps/api/src/services/project-listings.ts +0 -2085
  394. package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
  395. package/templates/apps/api/src/services/request-confirm.ts +0 -698
  396. package/templates/apps/api/src/services/revalidation.ts +0 -235
  397. package/templates/apps/api/src/services/slack-notify.ts +0 -291
  398. package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
  399. package/templates/apps/api/src/services/usage-credits.ts +0 -340
  400. package/templates/apps/api/src/services/verified-email.ts +0 -71
  401. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
  402. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
  403. package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
  404. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
  405. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
  406. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
  407. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
  408. package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
  409. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
  410. package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
  411. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
  412. package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
  413. package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
  414. package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
  415. package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
  416. package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
  417. package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
  418. package/templates/apps/mcp/__tests__/index.test.ts +0 -195
  419. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
  420. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
  421. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
  422. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
  423. package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
  424. package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
  425. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
  426. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
  427. package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
  428. package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
  429. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
  430. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
  431. package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
  432. package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
  433. package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
  434. package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
  435. package/templates/apps/mcp/__tests__/server.test.ts +0 -388
  436. package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
  437. package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
  438. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
  439. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
  440. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
  441. package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
  442. package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
  443. package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
  444. package/templates/apps/mcp/src/abuse/index.ts +0 -349
  445. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
  446. package/templates/apps/mcp/src/boot.ts +0 -167
  447. package/templates/apps/mcp/src/config/modules.ts +0 -43
  448. package/templates/apps/mcp/src/http-transport.ts +0 -564
  449. package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
  450. package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
  451. package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
  452. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
  453. package/templates/apps/mcp/src/lib/errors.ts +0 -61
  454. package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
  455. package/templates/apps/mcp/src/lib/locales.ts +0 -171
  456. package/templates/apps/mcp/src/lib/prisma.ts +0 -39
  457. package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
  458. package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
  459. package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
  460. package/templates/apps/mcp/src/lib/site-config.ts +0 -53
  461. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
  462. package/templates/apps/mcp/src/request-context.ts +0 -52
  463. package/templates/apps/mcp/src/server.ts +0 -343
  464. package/templates/apps/mcp/src/serverless-app.ts +0 -88
  465. package/templates/apps/mcp/src/tools/audit.ts +0 -127
  466. package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
  467. package/templates/apps/mcp/src/tools/create_project.ts +0 -134
  468. package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
  469. package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
  470. package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
  471. package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
  472. package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
  473. package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
  474. package/templates/apps/mcp/src/tools/index.ts +0 -138
  475. package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
  476. package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
  477. package/templates/apps/mcp/src/tools/proposals.ts +0 -27
  478. package/templates/apps/mcp/src/tools/purchase.ts +0 -205
  479. package/templates/apps/mcp/src/tools/read_content.ts +0 -81
  480. package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
  481. package/templates/apps/mcp/src/tools/search_content.ts +0 -63
  482. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
  483. package/templates/apps/mcp/src/workspace-server.ts +0 -224
  484. package/templates/database/CHANGELOG.md +0 -981
  485. package/templates/database/LICENSE +0 -202
  486. package/templates/database/NOTICE +0 -2
  487. package/templates/database/README.md +0 -243
  488. package/templates/database/__tests__/agents.db.test.ts +0 -320
  489. package/templates/database/__tests__/appointment.db.test.ts +0 -106
  490. package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
  491. package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
  492. package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
  493. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
  494. package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
  495. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
  496. package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
  497. package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
  498. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
  499. package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
  500. package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
  501. package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
  502. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
  503. package/templates/database/__tests__/flows-presets.test.ts +0 -173
  504. package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
  505. package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
  506. package/templates/database/__tests__/member-area.db.test.ts +0 -257
  507. package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
  508. package/templates/database/__tests__/member-contract.db.test.ts +0 -413
  509. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
  510. package/templates/database/__tests__/offerings-migration.test.ts +0 -197
  511. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
  512. package/templates/database/__tests__/offerings.db.test.ts +0 -303
  513. package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
  514. package/templates/database/__tests__/person-contact.db.test.ts +0 -563
  515. package/templates/database/__tests__/person-notes.db.test.ts +0 -249
  516. package/templates/database/__tests__/person.db.test.ts +0 -586
  517. package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
  518. package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
  519. package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
  520. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
  521. package/templates/database/__tests__/seed.test.ts +0 -272
  522. package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
  523. package/templates/database/__tests__/tenancy.test.ts +0 -141
  524. package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
  525. package/templates/database/__tests__/user-cascade.test.ts +0 -140
  526. package/templates/database/_gitignore +0 -8
  527. package/templates/database/auth/.gitkeep +0 -0
  528. package/templates/database/auth/schema.prisma +0 -641
  529. package/templates/database/config/.gitkeep +0 -0
  530. package/templates/database/config/schema.prisma +0 -441
  531. package/templates/database/content/.gitkeep +0 -0
  532. package/templates/database/content/schema.prisma +0 -339
  533. package/templates/database/eslint.config.mjs +0 -69
  534. package/templates/database/flows/listing-diagnostic.ts +0 -182
  535. package/templates/database/flows/presets.ts +0 -315
  536. package/templates/database/inbox/.gitkeep +0 -0
  537. package/templates/database/inbox/README.md +0 -3
  538. package/templates/database/inbox/__tests__/schema.test.ts +0 -44
  539. package/templates/database/inbox/schema.prisma +0 -1447
  540. package/templates/database/jest.config.cjs +0 -36
  541. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
  542. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
  543. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
  544. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
  545. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
  546. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
  547. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
  548. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
  549. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
  550. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
  551. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
  552. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
  553. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
  554. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
  555. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
  556. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
  557. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
  558. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
  559. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
  560. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
  561. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
  562. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
  563. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
  564. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
  565. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
  566. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
  567. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
  568. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
  569. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
  570. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
  571. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
  572. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
  573. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
  574. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
  575. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
  576. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
  577. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
  578. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
  579. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
  580. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
  581. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
  582. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
  583. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
  584. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
  585. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
  586. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
  587. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
  588. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
  589. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
  590. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
  591. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
  592. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
  593. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
  594. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
  595. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
  596. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
  597. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
  598. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
  599. package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
  600. package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
  601. package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
  602. package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
  603. package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
  604. package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
  605. package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
  606. package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
  607. package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
  608. package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
  609. package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
  610. package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
  611. package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
  612. package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
  613. package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
  614. package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
  615. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
  616. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
  617. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
  618. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
  619. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
  620. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
  621. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
  622. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
  623. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
  624. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
  625. package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
  626. package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
  627. package/templates/database/migrations/migration_lock.toml +0 -3
  628. package/templates/database/ops/.gitkeep +0 -0
  629. package/templates/database/ops/schema.prisma +0 -43
  630. package/templates/database/package.json +0 -89
  631. package/templates/database/schema.prisma +0 -71
  632. package/templates/database/scripts/db-generate-locked.sh +0 -80
  633. package/templates/database/scripts/person-backfill.sql +0 -132
  634. package/templates/database/tenancy.ts +0 -183
  635. package/templates/database/tsconfig.build.json +0 -16
  636. package/templates/database/tsconfig.flows.json +0 -15
  637. package/templates/database/tsconfig.json +0 -16
  638. package/templates/database/tsconfig.tenancy.json +0 -14
@@ -1,96 +0,0 @@
1
- // oss: false
2
- /**
3
- * The magnet-deliverable Asset store's data-access boundary (#6310 D16).
4
- *
5
- * `deliverable-fulfillment.ts` resolves `deliverables.assets[].assetKey`
6
- * against the workspace-scoped `Asset` model before falling back to the
7
- * legacy `DeliverableAsset` store (D1/D2), and the download route
8
- * (`routes/deliverables/index.ts`) serves an `asset_`-class grant's bytes
9
- * from the same model (D6). Neither caller may run a raw `prisma.asset`
10
- * query directly — that access is banned by the tenant-scope
11
- * `forbidden_pattern` in architecture.yaml — and neither is `lib/asset-store.ts`
12
- * a fit: it is `workspace`/`multi-tenant`-owned (`MODULE_SLICES`), so a
13
- * `signal-collectors` file (the route) cannot import it, and
14
- * `deliverable-fulfillment.ts` ships in every scaffold regardless of module
15
- * selection. This file is its own named boundary instead — modelled
16
- * line-for-line on `lib/asset-store.ts` — exporting exactly two scoped
17
- * reads and nothing else:
18
- *
19
- * - `findDeliverableAssetIdByKey(workspaceId, key)` — the mint-time
20
- * resolution (D2): does an `Asset` exist at this workspace's `key`?
21
- * - `readDeliverableAsset(assetId, workspaceId)` — the serve-time read
22
- * (D6): the bytes, scoped by the `workspaceId` the grant carries
23
- * (D15), so a rewritten or mis-set grant can never serve another
24
- * workspace's bytes.
25
- *
26
- * Neither ever resolves a client file (SEC-7877-A, #7877): an asset tagged
27
- * `private`, one a member-area message attaches, or one a delivered piece
28
- * version names (#8171 D3), is the same `null` a miss is — so a magnet pointed at a client file's key mints nothing and a
29
- * grant minted before the file became one serves nothing.
30
- *
31
- * No write, no `findMany`, no list, no unscoped read — both functions take
32
- * a `workspaceId` the caller resolved server-side, never a client-supplied
33
- * value, so neither can enumerate or cross a tenant boundary (NFR3).
34
- */
35
- import { PRIVATE_ASSET_TAG } from "@working-theory/validation";
36
-
37
- import { prisma } from "./prisma.js";
38
-
39
- /** A client file (SEC-7877-A) — `private`-tagged, attached to a message, or a version's file (#8171 D3). */
40
- async function isClientFile(
41
- assetId: string,
42
- workspaceId: string,
43
- tags: string[],
44
- ): Promise<boolean> {
45
- if (tags.includes(PRIVATE_ASSET_TAG)) return true;
46
- if ((await prisma.interaction.count({ where: { assetId, workspaceId } })) > 0) return true;
47
- return (await prisma.pieceVersion.count({ where: { assetId, workspaceId } })) > 0;
48
- }
49
-
50
- /** What the mint-time resolution needs, and nothing more. */
51
- export async function findDeliverableAssetIdByKey(
52
- workspaceId: string,
53
- key: string,
54
- ): Promise<string | null> {
55
- const row = await prisma.asset.findFirst({
56
- where: { workspaceId, key },
57
- select: { id: true, tags: true },
58
- });
59
- if (!row || (await isClientFile(row.id, workspaceId, row.tags))) return null;
60
- return row.id;
61
- }
62
-
63
- /** What the serve path needs, and deliberately nothing more (no key, no workspace). */
64
- export type DeliverableAssetBytes = {
65
- filename: string;
66
- contentType: string;
67
- bytes: Buffer;
68
- };
69
-
70
- /**
71
- * Resolve one asset's bytes by id, scoped by `workspaceId` (D15). A foreign-
72
- * workspace id — or any other miss — returns `null`; the caller turns that
73
- * into the same uniform 404 an unknown grant gets (D6/FR5).
74
- */
75
- export async function readDeliverableAsset(
76
- assetId: string,
77
- workspaceId: string | null,
78
- ): Promise<DeliverableAssetBytes | null> {
79
- if (workspaceId === null) return null;
80
-
81
- const row = await prisma.asset.findFirst({
82
- where: { id: assetId, workspaceId },
83
- select: { filename: true, contentType: true, bytes: true, tags: true },
84
- });
85
- if (!row || (await isClientFile(assetId, workspaceId, row.tags))) return null;
86
-
87
- return {
88
- filename: row.filename,
89
- contentType: row.contentType,
90
- // Prisma maps a `Bytes` column to `Uint8Array`, and Fastify treats only
91
- // a `Buffer` as a raw payload — this wraps rather than copies
92
- // (`Buffer.from(buffer, byteOffset, length)` is a view), mirroring
93
- // `asset-store.ts`'s own identical wrap.
94
- bytes: Buffer.from(row.bytes.buffer, row.bytes.byteOffset, row.bytes.byteLength),
95
- };
96
- }
@@ -1,164 +0,0 @@
1
- /**
2
- * Fastify error-serializer — prevents internal error detail from leaking to clients.
3
- *
4
- * Fastify's default error handler echoes `err.message` (and in dev,
5
- * `err.stack`) in the response body. For internal errors (DB failures, SDK
6
- * exceptions, unhandled throws) that's sensitive: connection strings, host
7
- * names, schema hints, internal paths. This handler:
8
- *
9
- * - Maps any 5xx-class internal Error to `{ error: "internal_error" }`
10
- * with no detail
11
- * - Logs the full Error (message, stack, request context) to pino at
12
- * error level
13
- * - Lets Fastify's built-in 4xx validation errors flow through
14
- * (their `validation` payload is safe to surface — it describes the
15
- * client's input, not server internals)
16
- * - Leaves replies that handlers already committed (explicit status + body)
17
- * untouched
18
- */
19
- import { idRegex } from "@working-theory/ids";
20
- import type { FastifyError, FastifyInstance } from "fastify";
21
-
22
- const GENERIC_INTERNAL_BODY = { error: "internal_error" } as const;
23
-
24
- /**
25
- * The request target with its QUERY STRING removed (#5970 security review,
26
- * finding 1).
27
- *
28
- * A route may carry its credential in the query — `GET
29
- * /v1/requests/:id/confirm?token=…` does, because a link in an email has
30
- * nowhere else to put one — and this handler logs `path` on EVERY error on
31
- * EVERY route. Logging the raw target would write that credential into the
32
- * API's own log the moment anything went wrong, which is precisely when logs
33
- * get read, copied into tickets, and shipped to third parties.
34
- */
35
- function pathWithoutQuery(url: string): string {
36
- const queryAt = url.indexOf("?");
37
- return queryAt === -1 ? url : url.slice(0, queryAt);
38
- }
39
-
40
- /**
41
- * #6084 D14 — `GET /v1/checkout/sessions/:id` puts its credential in the
42
- * PATH, so a `cs_…`-shaped segment is truncated to its first 8 characters
43
- * plus `…` (a path SEGMENT rule, never a substring replace, so it cannot
44
- * corrupt an unrelated URL). #6216 D11 adds the same arm for `lead_…`
45
- * segments and #8438 SEC-8438-10 for `person_…` segments, which would
46
- * otherwise put a full id beside `remoteAddress`.
47
- */
48
- const SESSION_ID_LOG_SEGMENT = /^cs_[A-Za-z0-9_]+$/;
49
- const LEAD_ID_LOG_SEGMENT = idRegex("lead");
50
- const PERSON_ID_LOG_SEGMENT = idRegex("person");
51
-
52
- /**
53
- * #8932 D10 (contract W9) — a webhook connection token is the per-connection
54
- * receiver's routing credential (`/v1/webhooks/<provider>/:connectionToken`).
55
- * Every segment after the provider is replaced by one literal
56
- * `:connectionToken`, keeping no prefix — unlike the id arms above — and
57
- * empty segments are dropped first, so a trailing slash, a double slash or a
58
- * mis-pasted extra segment cannot carry the token past the rule.
59
- */
60
- const CONNECTION_TOKEN_PLACEHOLDER = ":connectionToken";
61
-
62
- /** A segment as the router matches it: percent-decoded, or raw when it does not decode. */
63
- function decodedSegment(segment: string): string {
64
- try {
65
- return decodeURIComponent(segment);
66
- } catch {
67
- return segment;
68
- }
69
- }
70
-
71
- function redactConnectionToken(path: string): string | null {
72
- // Compared DECODED: the router decodes before it matches, so
73
- // `/v1/%77ebhooks/stripe/<token>` reaches the token route and must be
74
- // redacted like its plain spelling.
75
- const segments = path
76
- .split("/")
77
- .filter((segment) => segment.length > 0)
78
- .map(decodedSegment);
79
- if (segments.length < 4 || segments[0] !== "v1" || segments[1] !== "webhooks") {
80
- return null;
81
- }
82
- return `/${segments.slice(0, 3).join("/")}/${CONNECTION_TOKEN_PLACEHOLDER}`;
83
- }
84
-
85
- /**
86
- * The ONE path redactor for a log line (#8932 D10): the query string dropped,
87
- * a webhook connection token replaced whole, and every `cs_…`, `lead_…` and
88
- * `person_…` segment truncated. The Fastify request serializer (`server.ts`)
89
- * and this handler's three `path:` fields both call it, so a 429, 413, 415 or
90
- * 5xx on a token route logs the same redacted path its request line does.
91
- * A route parameter that is an identifier rather than a secret — `:id` — is
92
- * kept: it is what makes the line useful.
93
- */
94
- export function redactLogPath(url: string): string {
95
- const path = pathWithoutQuery(url);
96
- const tokenless = redactConnectionToken(path);
97
- if (tokenless !== null) return tokenless;
98
- return path
99
- .split("/")
100
- .map((segment) =>
101
- SESSION_ID_LOG_SEGMENT.test(segment) ||
102
- LEAD_ID_LOG_SEGMENT.test(segment) ||
103
- PERSON_ID_LOG_SEGMENT.test(segment)
104
- ? `${segment.slice(0, 8)}…`
105
- : segment,
106
- )
107
- .join("/");
108
- }
109
-
110
- export function registerErrorSerializer(server: FastifyInstance): void {
111
- server.setErrorHandler(async (err: FastifyError, request, reply) => {
112
- // Validation errors (Fastify's schema validator) — keep structured detail.
113
- // These describe the client request, not server internals.
114
- if (err.validation) {
115
- const status = err.statusCode ?? 400;
116
- request.log.warn(
117
- {
118
- method: request.method,
119
- path: redactLogPath(request.url),
120
- validation: err.validation,
121
- },
122
- "request validation failed",
123
- );
124
- return reply.code(status).send({
125
- error: "validation-error",
126
- details: err.validation,
127
- });
128
- }
129
-
130
- // Explicit 4xx errors thrown by handlers (e.g. fastify.httpErrors.notFound)
131
- // also flow through — they're a deliberate boundary signal, not an
132
- // internal leak.
133
- const status = err.statusCode ?? 500;
134
- if (status >= 400 && status < 500) {
135
- request.log.info(
136
- {
137
- method: request.method,
138
- path: redactLogPath(request.url),
139
- statusCode: status,
140
- errName: err.name,
141
- },
142
- "request returned 4xx",
143
- );
144
- // Don't echo err.message — handlers that want a structured body should
145
- // call reply.code().send() directly. This branch is the safe fallback.
146
- return reply.code(status).send({ error: err.code ?? "client_error" });
147
- }
148
-
149
- // 5xx — log everything, return nothing identifying.
150
- request.log.error(
151
- {
152
- method: request.method,
153
- path: redactLogPath(request.url),
154
- errName: err.name,
155
- errMessage: err.message,
156
- errStack: err.stack,
157
- errCode: err.code,
158
- },
159
- "internal server error",
160
- );
161
-
162
- return reply.code(500).send(GENERIC_INTERNAL_BODY);
163
- });
164
- }
@@ -1,95 +0,0 @@
1
- /**
2
- * Canonical error shape for apps/api content-write routes (D14a Stage 0).
3
- *
4
- * Every error response from create/update/delete content routes returns this
5
- * shape as the JSON body, paired with the appropriate HTTP status. The MCP
6
- * twin (`apps/mcp/src/lib/errors.ts`) returns the same shape sans `status` —
7
- * MCP carries the error in the tool result body itself.
8
- *
9
- * Codes are a closed set; consumers can switch on them to drive UI / retry
10
- * logic without parsing free-form `message` text. New codes get added here
11
- * before any route uses them.
12
- *
13
- * Usage:
14
- * const err = validationError("Invalid type or slug", { field: "type" });
15
- * return reply.status(err.status).send(err.body);
16
- */
17
- import { mapAdapterError } from "@working-theory/content-adapters";
18
-
19
- export type ErrorCode =
20
- | "validation_failed"
21
- | "not_found"
22
- | "conflict"
23
- | "payment_required"
24
- | "unauthorized";
25
-
26
- export interface ErrorBody {
27
- error: ErrorCode;
28
- message: string;
29
- details?: Record<string, unknown>;
30
- }
31
-
32
- export interface ErrorResponse {
33
- status: number;
34
- body: ErrorBody;
35
- }
36
-
37
- function makeBody(
38
- code: ErrorCode,
39
- message: string,
40
- details?: Record<string, unknown>,
41
- ): ErrorBody {
42
- if (details === undefined) {
43
- return { error: code, message };
44
- }
45
- return { error: code, message, details };
46
- }
47
-
48
- export function validationError(
49
- message: string,
50
- details?: Record<string, unknown>,
51
- ): ErrorResponse {
52
- return { status: 400, body: makeBody("validation_failed", message, details) };
53
- }
54
-
55
- export function unauthorizedError(message: string): ErrorResponse {
56
- return { status: 401, body: makeBody("unauthorized", message) };
57
- }
58
-
59
- export function paymentRequiredError(message: string): ErrorResponse {
60
- return { status: 402, body: makeBody("payment_required", message) };
61
- }
62
-
63
- export function notFoundError(message: string): ErrorResponse {
64
- return { status: 404, body: makeBody("not_found", message) };
65
- }
66
-
67
- export function conflictError(
68
- message: string,
69
- details?: Record<string, unknown>,
70
- ): ErrorResponse {
71
- return { status: 409, body: makeBody("conflict", message, details) };
72
- }
73
-
74
- /**
75
- * Route-layer adapter for `mapAdapterError` from `@working-theory/content-adapters`.
76
- * The package emits a canonical `{error, message, details?}` body but
77
- * cannot know the HTTP status (it has no app dependency). This helper
78
- * pairs the body with the right status. Returns `null` if the error
79
- * wasn't an `AdapterWriteError` (caller should treat as 500).
80
- */
81
- export function adapterErrorResponse(
82
- err: unknown,
83
- ctx: { type: string; slug: string },
84
- ): ErrorResponse | null {
85
- const body = mapAdapterError(err, ctx);
86
- if (body === null) return null;
87
- switch (body.error) {
88
- case "conflict":
89
- return { status: 409, body };
90
- case "not_found":
91
- return { status: 404, body };
92
- case "validation_failed":
93
- return { status: 400, body };
94
- }
95
- }
@@ -1,87 +0,0 @@
1
- /**
2
- * File-fallback writer for the AILK inbox.
3
- *
4
- * Writes a Lead to ${AILK_INBOX_FALLBACK_DIR ?? '.ailk/inbox'}/<ISO-ts>-<lead.id>.json
5
- * when the database is unavailable. Engaged by B6's lead-routing service on DB failure.
6
- *
7
- * Path-traversal-safe by construction:
8
- * 1. lead.id is validated against /^[a-z0-9_-]{8,64}$/i before any fs operation.
9
- * 2. The resolved write path is checked to be strictly inside targetDir.
10
- *
11
- * No quota / count cap. Operators running with this fallback engaged for extended periods
12
- * should monitor disk usage and replay leads back to DB once it returns.
13
- *
14
- * Module is import-side-effect-free. No env reads at module-load time.
15
- */
16
-
17
- import * as fs from "fs/promises";
18
- import * as path from "path";
19
-
20
- import type { Lead } from "@working-theory/validation";
21
-
22
- export type FallbackLead = Lead;
23
-
24
- export type FallbackResult =
25
- | { ok: true; path: string }
26
- | {
27
- ok: false;
28
- error: {
29
- kind: "invalid_id" | "path_escape" | "fs_error";
30
- message: string;
31
- };
32
- };
33
-
34
- const LEAD_ID_RE = /^[a-z0-9_-]{8,64}$/i;
35
-
36
- export async function writeLeadFallback(
37
- lead: FallbackLead,
38
- ): Promise<FallbackResult> {
39
- if (!LEAD_ID_RE.test(lead.id)) {
40
- return {
41
- ok: false,
42
- error: { kind: "invalid_id", message: `Invalid lead id: ${lead.id}` },
43
- };
44
- }
45
-
46
- // Resolve target directory — read env inside the function (no module-level side effects)
47
- const envDir = process.env.AILK_INBOX_FALLBACK_DIR ?? ".ailk/inbox";
48
- const targetDir = path.resolve(process.cwd(), envDir);
49
-
50
- const rawTs = isValidIso(lead.createdAt)
51
- ? lead.createdAt
52
- : new Date().toISOString();
53
- // Replace colons with hyphens for Windows filesystem compatibility
54
- const ts = rawTs.replace(/:/g, "-");
55
-
56
- const filename = `${ts}-${lead.id}.json`;
57
- const resolved = path.resolve(targetDir, filename);
58
-
59
- // Path-escape check: relative path must not start with '..' or be absolute
60
- const rel = path.relative(targetDir, resolved);
61
- if (rel.startsWith("..") || path.isAbsolute(rel)) {
62
- return {
63
- ok: false,
64
- error: {
65
- kind: "path_escape",
66
- message: `Path escape detected: ${resolved}`,
67
- },
68
- };
69
- }
70
-
71
- try {
72
- await fs.mkdir(targetDir, { recursive: true });
73
- await fs.writeFile(resolved, JSON.stringify(lead, null, 2));
74
- return { ok: true, path: resolved };
75
- } catch (err) {
76
- const message = err instanceof Error ? err.message : String(err);
77
- return { ok: false, error: { kind: "fs_error", message } };
78
- }
79
- }
80
-
81
- // Require YYYY-MM-DD prefix before accepting as ISO — rejects slash-dates, traversal strings, etc.
82
- const ISO_RE = /^\d{4}-\d{2}-\d{2}(T[\d:.Z+-]*)?$/;
83
-
84
- function isValidIso(value: string): boolean {
85
- if (!value || !ISO_RE.test(value)) return false;
86
- return !isNaN(new Date(value).getTime());
87
- }
@@ -1,136 +0,0 @@
1
- /**
2
- * A magnet's completion setting — its data boundary (#8757, spec
3
- * docs/specs/8757-a-per-magnet-completion-setting-spec.md D3).
4
- *
5
- * `flow_definitions.completion` / `checkout_offering` are new columns, and
6
- * `lib/tenant-db.ts` — the magnet routes' only other data path — stays closed
7
- * under the parallel contract with #8746 (D7), so the two columns get this
8
- * named boundary of their own. Every statement is scoped by a server-resolved
9
- * `workspaceId` (a tenant's, or the public lead route's resolved workspace):
10
- *
11
- * - `completionsFor` — one `findMany` by workspace AND id list;
12
- * - `setCompletion` — one `updateMany` by id AND workspace, writing
13
- * exactly the two columns;
14
- * - `liveCompletionBySlug` — one `findFirst` of a LIVE magnet by workspace
15
- * AND slug (its pair, title and config — the
16
- * config for a declared `completionEmail`);
17
- * - `inviteSendCounts` — two `lead.count`s for the invite email's caps
18
- * (D6), by workspace AND `flow:<slug>` source.
19
- *
20
- * No list without an id set, no other model, no read by any other key.
21
- * Base tree (SEC-8757-D): no `oss: false` marker and no `MODULE_SLICES`
22
- * entry, because the never-gate lead route imports it. `architecture.yaml`
23
- * lists this file under the tenant-scope rule's `paths_scoped` with exactly
24
- * these four call sites' counts, so a further access fails the lint.
25
- */
26
- import {
27
- FLOW_COMPLETION_DEFAULT,
28
- flowCompletionSettingSchema,
29
- type FlowCompletionSetting,
30
- } from "@working-theory/validation";
31
-
32
- import { prisma } from "./prisma.js";
33
-
34
- const DEFAULT_SETTING: FlowCompletionSetting = {
35
- completion: FLOW_COMPLETION_DEFAULT,
36
- checkoutOffering: null,
37
- };
38
-
39
- /**
40
- * A stored pair as the vocabulary reads it. The database's CHECKs make every
41
- * stored pair valid; a row that carries neither column (a test fixture, or a
42
- * read before the migration) reads as the default, as `customersEnabled` does.
43
- */
44
- function toSetting(row: { completion?: unknown; checkoutOffering?: unknown }) {
45
- const parsed = flowCompletionSettingSchema.safeParse({
46
- completion: row.completion,
47
- checkoutOffering: row.checkoutOffering ?? null,
48
- });
49
- return parsed.success ? parsed.data : DEFAULT_SETTING;
50
- }
51
-
52
- /** The setting of each of `ids` in `workspaceId`. An id absent from the map reads as `lead`. */
53
- export async function completionsFor(
54
- workspaceId: string,
55
- ids: readonly string[],
56
- ): Promise<Map<string, FlowCompletionSetting>> {
57
- const out = new Map<string, FlowCompletionSetting>();
58
- if (ids.length === 0) return out;
59
- const rows = await prisma.flowDefinition.findMany({
60
- where: { workspaceId, id: { in: [...ids] } },
61
- select: { id: true, completion: true, checkoutOffering: true },
62
- });
63
- for (const row of rows) out.set(row.id, toSetting(row));
64
- return out;
65
- }
66
-
67
- /** `completionsFor`'s answer for one id. */
68
- export function completionOf(
69
- settings: Map<string, FlowCompletionSetting>,
70
- id: string,
71
- ): FlowCompletionSetting {
72
- return settings.get(id) ?? DEFAULT_SETTING;
73
- }
74
-
75
- /** Write the pair onto magnet `id` of `workspaceId`; nothing else on the row. */
76
- export async function setCompletion(
77
- workspaceId: string,
78
- id: string,
79
- setting: FlowCompletionSetting,
80
- ): Promise<"set" | "not_found"> {
81
- const result = await prisma.flowDefinition.updateMany({
82
- where: { id, workspaceId },
83
- data: { completion: setting.completion, checkoutOffering: setting.checkoutOffering },
84
- });
85
- return result.count > 0 ? "set" : "not_found";
86
- }
87
-
88
- export type LiveCompletion = FlowCompletionSetting & {
89
- title: string;
90
- /** The stored config, unparsed — the invite email reads its `completionEmail`. */
91
- config: unknown;
92
- };
93
-
94
- /** The LIVE magnet at `slug` in `workspaceId`: its setting, title and config, or `null`. */
95
- export async function liveCompletionBySlug(
96
- workspaceId: string,
97
- slug: string,
98
- ): Promise<LiveCompletion | null> {
99
- const row = await prisma.flowDefinition.findFirst({
100
- where: { workspaceId, slug, status: "live" },
101
- select: { title: true, config: true, completion: true, checkoutOffering: true },
102
- });
103
- return row === null ? null : { ...toSetting(row), title: row.title, config: row.config };
104
- }
105
-
106
- const DAY_MS = 24 * 60 * 60 * 1000;
107
- const HOUR_MS = 60 * 60 * 1000;
108
-
109
- /**
110
- * D6's two caps, counted in the database so they hold across instances and
111
- * against a spoofed `x-forwarded-for`: this magnet's leads for `email`
112
- * (case-insensitively) over the last day, and all of its leads over the last
113
- * hour. Both include the lead the caller just wrote.
114
- */
115
- export async function inviteSendCounts(
116
- workspaceId: string,
117
- slug: string,
118
- email: string,
119
- now: Date,
120
- ): Promise<{ recipientDay: number; siteHour: number }> {
121
- const source = `flow:${slug}`;
122
- const [recipientDay, siteHour] = await Promise.all([
123
- prisma.lead.count({
124
- where: {
125
- workspaceId,
126
- source,
127
- email: { equals: email, mode: "insensitive" },
128
- createdAt: { gte: new Date(now.getTime() - DAY_MS) },
129
- },
130
- }),
131
- prisma.lead.count({
132
- where: { workspaceId, source, createdAt: { gte: new Date(now.getTime() - HOUR_MS) } },
133
- }),
134
- ]);
135
- return { recipientDay, siteHour };
136
- }