create-ailk 0.24.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 (599) hide show
  1. package/README.md +42 -20
  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 +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/module-architecture.d.ts +20 -3
  20. package/dist/module-architecture.js +117 -550
  21. package/dist/paid-sections.d.ts +25 -1
  22. package/dist/paid-sections.js +88 -3
  23. package/dist/surfaces.js +10 -2
  24. package/dist/template-record.d.ts +14 -4
  25. package/dist/template-record.js +23 -5
  26. package/dist/topology.d.ts +16 -3
  27. package/dist/topology.js +31 -19
  28. package/dist/update.d.ts +10 -1
  29. package/dist/update.js +540 -16
  30. package/package.json +3 -3
  31. package/release-scope.json +1 -1
  32. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  33. package/templates/.claude/hooks/template-guard.sh +137 -0
  34. package/templates/.claude/rules/extending.md +106 -0
  35. package/templates/.claude/rules/loop-contract.md +2 -2
  36. package/templates/.claude/settings.json +11 -0
  37. package/templates/.env.example +5 -5
  38. package/templates/.github/workflows/ci.yml +7 -4
  39. package/templates/CLAUDE.md +11 -1
  40. package/templates/CONVENTIONS.md +8 -10
  41. package/templates/README.md +14 -13
  42. package/templates/apps/api/.env.example +2 -2
  43. package/templates/apps/api/CLAUDE.md +102 -76
  44. package/templates/apps/api/jest.config.cjs +15 -5
  45. package/templates/apps/api/package.json +16 -20
  46. package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
  47. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
  48. package/templates/apps/api/src/index.ts +1 -1
  49. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
  50. package/templates/apps/api/src/modules/commerce.ts +10 -0
  51. package/templates/apps/api/src/modules/content-write.ts +10 -0
  52. package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
  53. package/templates/apps/api/src/modules/scheduling.ts +10 -0
  54. package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
  55. package/templates/apps/api/src/modules/workspace.ts +10 -0
  56. package/templates/apps/api/src/server.ts +117 -1882
  57. package/templates/apps/api/vercel.json +2 -2
  58. package/templates/apps/mcp/CLAUDE.md +67 -20
  59. package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
  60. package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
  61. package/templates/apps/mcp/jest.config.cjs +6 -1
  62. package/templates/apps/mcp/package.json +5 -13
  63. package/templates/apps/mcp/src/app.ts +8 -7
  64. package/templates/apps/mcp/src/index.ts +6 -34
  65. package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
  66. package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
  67. package/templates/apps/mcp/src/site.ts +12 -0
  68. package/templates/apps/web/.env.example +1 -1
  69. package/templates/apps/web/CLAUDE.md +10 -3
  70. package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
  71. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
  72. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
  73. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
  74. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
  75. package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
  76. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
  77. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
  78. package/templates/apps/web/app/api/revalidate/route.ts +3 -3
  79. package/templates/apps/web/auth.ts +2 -2
  80. package/templates/apps/web/jest.config.cjs +1 -0
  81. package/templates/apps/web/lib/auth-email.ts +1 -1
  82. package/templates/apps/web/lib/relay.ts +2 -2
  83. package/templates/apps/web/lib/release-scope.ts +47 -0
  84. package/templates/apps/web/lib/server-api.ts +1 -1
  85. package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
  86. package/templates/customizations.yaml +37 -0
  87. package/templates/database/prisma.config.ts +10 -14
  88. package/templates/database/seed-test.ts +2 -2
  89. package/templates/database/seed.ts +5 -5
  90. package/templates/package.json +12 -6
  91. package/templates/pnpm-workspace.yaml +0 -1
  92. package/templates/project.yaml +16 -8
  93. package/templates/tools/jest/reporters.cjs +65 -0
  94. package/templates/tools/lint-architecture.ts +553 -7
  95. package/templates/tsconfig.json +1 -2
  96. package/versions.json +48 -35
  97. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
  98. package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
  99. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
  100. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
  101. package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
  102. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
  103. package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
  104. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
  105. package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
  106. package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
  107. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
  108. package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
  109. package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
  110. package/templates/apps/api/src/bin/spokes.ts +0 -198
  111. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
  112. package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
  113. package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
  114. package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
  115. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
  116. package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
  117. package/templates/apps/api/src/config/index.ts +0 -596
  118. package/templates/apps/api/src/config/modules.ts +0 -83
  119. package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
  120. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
  121. package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
  122. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
  123. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
  124. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
  125. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
  126. package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
  127. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
  128. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
  129. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
  130. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
  131. package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
  132. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
  133. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
  134. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
  135. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
  136. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
  137. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
  138. package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
  139. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
  140. package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
  141. package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
  142. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
  143. package/templates/apps/api/src/lib/agent-store.ts +0 -613
  144. package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
  145. package/templates/apps/api/src/lib/consent-store.ts +0 -363
  146. package/templates/apps/api/src/lib/content-adapter.ts +0 -112
  147. package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
  148. package/templates/apps/api/src/lib/error-serializer.ts +0 -164
  149. package/templates/apps/api/src/lib/errors.ts +0 -95
  150. package/templates/apps/api/src/lib/file-fallback.ts +0 -87
  151. package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
  152. package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
  153. package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
  154. package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
  155. package/templates/apps/api/src/lib/license-key-store.ts +0 -45
  156. package/templates/apps/api/src/lib/locales.ts +0 -201
  157. package/templates/apps/api/src/lib/outbound-http.ts +0 -127
  158. package/templates/apps/api/src/lib/prisma.ts +0 -21
  159. package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
  160. package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
  161. package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
  162. package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
  163. package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
  164. package/templates/apps/api/src/lib/site.ts +0 -257
  165. package/templates/apps/api/src/lib/slice-load.ts +0 -90
  166. package/templates/apps/api/src/lib/spoke-store.ts +0 -180
  167. package/templates/apps/api/src/lib/stripe.ts +0 -321
  168. package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
  169. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
  170. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
  171. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
  172. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
  173. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
  174. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
  175. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
  176. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
  177. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
  178. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
  179. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
  180. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
  181. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
  182. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
  183. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
  184. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
  185. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
  186. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
  187. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
  188. package/templates/apps/api/src/middleware/auth.ts +0 -864
  189. package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
  190. package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
  191. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
  192. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
  193. package/templates/apps/api/src/openapi/index.ts +0 -18
  194. package/templates/apps/api/src/openapi/spec.ts +0 -2148
  195. package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
  196. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
  197. package/templates/apps/api/src/routes/aeo/index.ts +0 -107
  198. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
  199. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
  200. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
  201. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
  202. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
  203. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
  204. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
  205. package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
  206. package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
  207. package/templates/apps/api/src/routes/auth/user.ts +0 -305
  208. package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
  209. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
  210. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
  211. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
  212. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
  213. package/templates/apps/api/src/routes/checkout/index.ts +0 -34
  214. package/templates/apps/api/src/routes/checkout/session.ts +0 -171
  215. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
  216. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
  217. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
  218. package/templates/apps/api/src/routes/consent/account.ts +0 -268
  219. package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
  220. package/templates/apps/api/src/routes/consent/index.ts +0 -26
  221. package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
  222. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
  223. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
  224. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
  225. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
  226. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
  227. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
  228. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
  229. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
  230. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
  231. package/templates/apps/api/src/routes/content/get-page.ts +0 -183
  232. package/templates/apps/api/src/routes/content/index.ts +0 -49
  233. package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
  234. package/templates/apps/api/src/routes/content/list-types.ts +0 -19
  235. package/templates/apps/api/src/routes/content/offerings.ts +0 -184
  236. package/templates/apps/api/src/routes/content/pricing.ts +0 -176
  237. package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
  238. package/templates/apps/api/src/routes/content/search.ts +0 -100
  239. package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
  240. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
  241. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
  242. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
  243. package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
  244. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
  245. package/templates/apps/api/src/routes/leads/index.ts +0 -639
  246. package/templates/apps/api/src/routes/leads/list.ts +0 -104
  247. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
  248. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
  249. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
  250. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
  251. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
  252. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
  253. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
  254. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
  255. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
  256. package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
  257. package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
  258. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
  259. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
  260. package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
  261. package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
  262. package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
  263. package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
  264. package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
  265. package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
  266. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
  267. package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
  268. package/templates/apps/api/src/routes/requests/index.ts +0 -54
  269. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
  270. package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
  271. package/templates/apps/api/src/routes/webhooks/README.md +0 -398
  272. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
  273. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
  274. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
  275. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
  276. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
  277. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
  278. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
  279. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
  280. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
  281. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
  282. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
  283. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
  284. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
  285. package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
  286. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
  287. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
  288. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
  289. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
  290. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
  291. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
  292. package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
  293. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
  294. package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
  295. package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
  296. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
  297. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
  298. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
  299. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
  300. package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
  301. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
  302. package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
  303. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
  304. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
  305. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
  306. package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
  307. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
  308. package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
  309. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
  310. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
  311. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
  312. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
  313. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
  314. package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
  315. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
  316. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
  317. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
  318. package/templates/apps/api/src/services/abandon-email.ts +0 -336
  319. package/templates/apps/api/src/services/aeo-score.ts +0 -325
  320. package/templates/apps/api/src/services/answer-distributions.ts +0 -138
  321. package/templates/apps/api/src/services/audit-log.ts +0 -961
  322. package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
  323. package/templates/apps/api/src/services/consent.ts +0 -834
  324. package/templates/apps/api/src/services/default-tenant.ts +0 -416
  325. package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
  326. package/templates/apps/api/src/services/dunning-policy.ts +0 -294
  327. package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
  328. package/templates/apps/api/src/services/entitlements.ts +0 -338
  329. package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
  330. package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
  331. package/templates/apps/api/src/services/lead-promotion.ts +0 -160
  332. package/templates/apps/api/src/services/lead-routing.ts +0 -1372
  333. package/templates/apps/api/src/services/leads-inbox.ts +0 -312
  334. package/templates/apps/api/src/services/listing-config.ts +0 -178
  335. package/templates/apps/api/src/services/magnet-completion.ts +0 -242
  336. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
  337. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
  338. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
  339. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
  340. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
  341. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
  342. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
  343. package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
  344. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
  345. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
  346. package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
  347. package/templates/apps/api/src/services/offerings/index.ts +0 -614
  348. package/templates/apps/api/src/services/offerings/source.ts +0 -140
  349. package/templates/apps/api/src/services/offerings/store.ts +0 -150
  350. package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
  351. package/templates/apps/api/src/services/person.ts +0 -1211
  352. package/templates/apps/api/src/services/plan-offerings.ts +0 -125
  353. package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
  354. package/templates/apps/api/src/services/project-listings.ts +0 -2085
  355. package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
  356. package/templates/apps/api/src/services/request-confirm.ts +0 -698
  357. package/templates/apps/api/src/services/revalidation.ts +0 -235
  358. package/templates/apps/api/src/services/slack-notify.ts +0 -291
  359. package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
  360. package/templates/apps/api/src/services/usage-credits.ts +0 -340
  361. package/templates/apps/api/src/services/verified-email.ts +0 -71
  362. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
  363. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
  364. package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
  365. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
  366. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
  367. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
  368. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
  369. package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
  370. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
  371. package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
  372. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
  373. package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
  374. package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
  375. package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
  376. package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
  377. package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
  378. package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
  379. package/templates/apps/mcp/__tests__/index.test.ts +0 -195
  380. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
  381. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
  382. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
  383. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
  384. package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
  385. package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
  386. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
  387. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
  388. package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
  389. package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
  390. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
  391. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
  392. package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
  393. package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
  394. package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
  395. package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
  396. package/templates/apps/mcp/__tests__/server.test.ts +0 -388
  397. package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
  398. package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
  399. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
  400. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
  401. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
  402. package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
  403. package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
  404. package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
  405. package/templates/apps/mcp/src/abuse/index.ts +0 -349
  406. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
  407. package/templates/apps/mcp/src/boot.ts +0 -167
  408. package/templates/apps/mcp/src/config/modules.ts +0 -43
  409. package/templates/apps/mcp/src/http-transport.ts +0 -564
  410. package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
  411. package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
  412. package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
  413. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
  414. package/templates/apps/mcp/src/lib/errors.ts +0 -61
  415. package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
  416. package/templates/apps/mcp/src/lib/locales.ts +0 -171
  417. package/templates/apps/mcp/src/lib/prisma.ts +0 -39
  418. package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
  419. package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
  420. package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
  421. package/templates/apps/mcp/src/lib/site-config.ts +0 -53
  422. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
  423. package/templates/apps/mcp/src/request-context.ts +0 -52
  424. package/templates/apps/mcp/src/server.ts +0 -343
  425. package/templates/apps/mcp/src/serverless-app.ts +0 -88
  426. package/templates/apps/mcp/src/tools/audit.ts +0 -127
  427. package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
  428. package/templates/apps/mcp/src/tools/create_project.ts +0 -134
  429. package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
  430. package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
  431. package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
  432. package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
  433. package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
  434. package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
  435. package/templates/apps/mcp/src/tools/index.ts +0 -138
  436. package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
  437. package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
  438. package/templates/apps/mcp/src/tools/proposals.ts +0 -27
  439. package/templates/apps/mcp/src/tools/purchase.ts +0 -205
  440. package/templates/apps/mcp/src/tools/read_content.ts +0 -81
  441. package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
  442. package/templates/apps/mcp/src/tools/search_content.ts +0 -63
  443. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
  444. package/templates/apps/mcp/src/workspace-server.ts +0 -224
  445. package/templates/database/CHANGELOG.md +0 -981
  446. package/templates/database/LICENSE +0 -202
  447. package/templates/database/NOTICE +0 -2
  448. package/templates/database/README.md +0 -243
  449. package/templates/database/__tests__/agents.db.test.ts +0 -320
  450. package/templates/database/__tests__/appointment.db.test.ts +0 -106
  451. package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
  452. package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
  453. package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
  454. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
  455. package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
  456. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
  457. package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
  458. package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
  459. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
  460. package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
  461. package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
  462. package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
  463. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
  464. package/templates/database/__tests__/flows-presets.test.ts +0 -173
  465. package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
  466. package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
  467. package/templates/database/__tests__/member-area.db.test.ts +0 -257
  468. package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
  469. package/templates/database/__tests__/member-contract.db.test.ts +0 -413
  470. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
  471. package/templates/database/__tests__/offerings-migration.test.ts +0 -197
  472. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
  473. package/templates/database/__tests__/offerings.db.test.ts +0 -303
  474. package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
  475. package/templates/database/__tests__/person-contact.db.test.ts +0 -563
  476. package/templates/database/__tests__/person-notes.db.test.ts +0 -249
  477. package/templates/database/__tests__/person.db.test.ts +0 -586
  478. package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
  479. package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
  480. package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
  481. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
  482. package/templates/database/__tests__/seed.test.ts +0 -272
  483. package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
  484. package/templates/database/__tests__/tenancy.test.ts +0 -141
  485. package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
  486. package/templates/database/__tests__/user-cascade.test.ts +0 -140
  487. package/templates/database/_gitignore +0 -8
  488. package/templates/database/auth/.gitkeep +0 -0
  489. package/templates/database/auth/schema.prisma +0 -641
  490. package/templates/database/config/.gitkeep +0 -0
  491. package/templates/database/config/schema.prisma +0 -441
  492. package/templates/database/content/.gitkeep +0 -0
  493. package/templates/database/content/schema.prisma +0 -339
  494. package/templates/database/eslint.config.mjs +0 -69
  495. package/templates/database/flows/listing-diagnostic.ts +0 -182
  496. package/templates/database/flows/presets.ts +0 -315
  497. package/templates/database/inbox/.gitkeep +0 -0
  498. package/templates/database/inbox/README.md +0 -3
  499. package/templates/database/inbox/__tests__/schema.test.ts +0 -44
  500. package/templates/database/inbox/schema.prisma +0 -1447
  501. package/templates/database/jest.config.cjs +0 -36
  502. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
  503. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
  504. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
  505. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
  506. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
  507. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
  508. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
  509. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
  510. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
  511. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
  512. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
  513. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
  514. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
  515. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
  516. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
  517. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
  518. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
  519. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
  520. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
  521. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
  522. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
  523. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
  524. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
  525. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
  526. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
  527. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
  528. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
  529. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
  530. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
  531. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
  532. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
  533. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
  534. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
  535. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
  536. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
  537. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
  538. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
  539. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
  540. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
  541. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
  542. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
  543. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
  544. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
  545. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
  546. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
  547. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
  548. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
  549. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
  550. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
  551. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
  552. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
  553. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
  554. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
  555. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
  556. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
  557. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
  558. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
  559. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
  560. package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
  561. package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
  562. package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
  563. package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
  564. package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
  565. package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
  566. package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
  567. package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
  568. package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
  569. package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
  570. package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
  571. package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
  572. package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
  573. package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
  574. package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
  575. package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
  576. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
  577. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
  578. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
  579. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
  580. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
  581. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
  582. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
  583. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
  584. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
  585. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
  586. package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
  587. package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
  588. package/templates/database/migrations/migration_lock.toml +0 -3
  589. package/templates/database/ops/.gitkeep +0 -0
  590. package/templates/database/ops/schema.prisma +0 -43
  591. package/templates/database/package.json +0 -89
  592. package/templates/database/schema.prisma +0 -71
  593. package/templates/database/scripts/db-generate-locked.sh +0 -80
  594. package/templates/database/scripts/person-backfill.sql +0 -132
  595. package/templates/database/tenancy.ts +0 -183
  596. package/templates/database/tsconfig.build.json +0 -16
  597. package/templates/database/tsconfig.flows.json +0 -15
  598. package/templates/database/tsconfig.json +0 -16
  599. package/templates/database/tsconfig.tenancy.json +0 -14
@@ -1,257 +0,0 @@
1
- /**
2
- * @file lead-capture-store.test.ts
3
- * Unit tests for the lead-capture-store write path (Issue #27 Unit 1).
4
- *
5
- * All fs operations are mocked; no real disk I/O in these tests.
6
- * Acceptance criteria covered (spec §5.1):
7
- * AC1 — file write on every successful submission (always-on by default)
8
- * AC3 — IPs default OFF; opt-in via LEAD_CAPTURE_INCLUDE_IP=true
9
- * AC4 — LEAD_CAPTURE_FILE_DISABLED=true short-circuits write
10
- * AC5 — LEAD_CAPTURE_FILE env drives output path
11
- * AC7 — 50 concurrent writes land without corruption (POSIX O_APPEND atomicity)
12
- * AC8 — startup-time directory check (tested in server.test.ts)
13
- * AC9 — LeadCaptureRecord shape validated by Zod schema
14
- * AC14 — appendLeadRecord resolves ok:false on fs error (never throws)
15
- */
16
-
17
- // ─── fs mock ─────────────────────────────────────────────────────────────────
18
- const mockAppendFile = jest.fn();
19
- const mockAccess = jest.fn();
20
- const mockMkdir = jest.fn();
21
-
22
- jest.mock("fs/promises", () => ({
23
- appendFile: (...args: unknown[]) => mockAppendFile(...args),
24
- access: (...args: unknown[]) => mockAccess(...args),
25
- mkdir: (...args: unknown[]) => mockMkdir(...args),
26
- }));
27
-
28
- import {
29
- appendLeadRecord,
30
- validateLeadCaptureDir,
31
- } from "../lead-capture-store.js";
32
- import type { LeadCaptureRecord } from "../lead-capture-store.js";
33
-
34
- // ─── Helpers ─────────────────────────────────────────────────────────────────
35
-
36
- const record: LeadCaptureRecord = {
37
- id: "fallback-1700000000000-test1",
38
- createdAt: "2024-01-01T00:00:00.000Z",
39
- source: "contact",
40
- data: { email: "test@example.com", message: "hello" },
41
- metadata: {},
42
- };
43
-
44
- // ─── Tests ───────────────────────────────────────────────────────────────────
45
-
46
- describe("appendLeadRecord", () => {
47
- beforeEach(() => {
48
- jest.clearAllMocks();
49
- mockAppendFile.mockResolvedValue(undefined);
50
- mockMkdir.mockResolvedValue(undefined);
51
- // Clear lead-capture env vars
52
- delete process.env.LEAD_CAPTURE_FILE;
53
- delete process.env.LEAD_CAPTURE_FILE_DISABLED;
54
- delete process.env.LEAD_CAPTURE_INCLUDE_IP;
55
- });
56
-
57
- afterEach(() => {
58
- delete process.env.LEAD_CAPTURE_FILE;
59
- delete process.env.LEAD_CAPTURE_FILE_DISABLED;
60
- delete process.env.LEAD_CAPTURE_INCLUDE_IP;
61
- });
62
-
63
- // AC1 — always-on by default (no env set)
64
- it("writes a JSONL line by default (always-on)", async () => {
65
- const result = await appendLeadRecord(record);
66
-
67
- expect(result.ok).toBe(true);
68
- expect(mockAppendFile).toHaveBeenCalledTimes(1);
69
- // Verify the written content is valid JSON with a newline
70
- const [, content, opts] = mockAppendFile.mock.calls[0];
71
- expect(opts).toMatchObject({ flag: "a" });
72
- const parsed = JSON.parse(content.trimEnd());
73
- expect(parsed.id).toBe(record.id);
74
- expect(parsed.source).toBe(record.source);
75
- });
76
-
77
- // AC5 — LEAD_CAPTURE_FILE drives output path
78
- it("uses LEAD_CAPTURE_FILE env for output path", async () => {
79
- process.env.LEAD_CAPTURE_FILE = "/tmp/test-leads.jsonl";
80
- const result = await appendLeadRecord(record);
81
-
82
- expect(result.ok).toBe(true);
83
- expect(mockAppendFile).toHaveBeenCalledWith(
84
- "/tmp/test-leads.jsonl",
85
- expect.any(String),
86
- expect.objectContaining({ flag: "a" }),
87
- );
88
- });
89
-
90
- // AC5 — defaults to apps/api/leads.jsonl relative to cwd when unset
91
- it("defaults to apps/api/leads.jsonl when LEAD_CAPTURE_FILE not set", async () => {
92
- const result = await appendLeadRecord(record);
93
-
94
- expect(result.ok).toBe(true);
95
- const [filePath] = mockAppendFile.mock.calls[0];
96
- expect(filePath).toMatch(/leads\.jsonl$/);
97
- });
98
-
99
- // #6730 D3 — the default file is local-only: in production it does not
100
- // outlive a serverless instance, so it is skipped unless explicitly pointed
101
- // at a durable path.
102
- describe("in production (#6730 D3)", () => {
103
- const savedNodeEnv = process.env.NODE_ENV;
104
- afterEach(() => {
105
- process.env.NODE_ENV = savedNodeEnv;
106
- });
107
-
108
- it("skips the write when LEAD_CAPTURE_FILE is unset", async () => {
109
- process.env.NODE_ENV = "production";
110
-
111
- const result = await appendLeadRecord(record);
112
-
113
- expect(result).toEqual({ ok: true, skipped: true });
114
- expect(mockAppendFile).not.toHaveBeenCalled();
115
- });
116
-
117
- it("writes when LEAD_CAPTURE_FILE is set explicitly", async () => {
118
- process.env.NODE_ENV = "production";
119
- process.env.LEAD_CAPTURE_FILE = "/data/leads.jsonl";
120
-
121
- const result = await appendLeadRecord(record);
122
-
123
- expect(result).toEqual({ ok: true });
124
- expect(mockAppendFile).toHaveBeenCalledTimes(1);
125
- expect(mockAppendFile.mock.calls[0][0]).toBe("/data/leads.jsonl");
126
- });
127
- });
128
-
129
- // AC4 — LEAD_CAPTURE_FILE_DISABLED=true skips the write
130
- it("short-circuits write when LEAD_CAPTURE_FILE_DISABLED=true", async () => {
131
- process.env.LEAD_CAPTURE_FILE_DISABLED = "true";
132
- const result = await appendLeadRecord(record);
133
-
134
- expect(result.ok).toBe(true);
135
- expect((result as { ok: true; skipped: true }).skipped).toBe(true);
136
- expect(mockAppendFile).not.toHaveBeenCalled();
137
- });
138
-
139
- // AC3 — IPs default OFF
140
- it("does not include IP by default", async () => {
141
- const recordWithIp: LeadCaptureRecord = {
142
- ...record,
143
- metadata: { ip: "1.2.3.4" },
144
- };
145
- const result = await appendLeadRecord(recordWithIp);
146
-
147
- expect(result.ok).toBe(true);
148
- const [, content] = mockAppendFile.mock.calls[0];
149
- const parsed = JSON.parse(content.trimEnd());
150
- expect(parsed.metadata?.ip).toBeUndefined();
151
- });
152
-
153
- // AC3 — LEAD_CAPTURE_INCLUDE_IP=true includes the IP
154
- it("includes IP when LEAD_CAPTURE_INCLUDE_IP=true", async () => {
155
- process.env.LEAD_CAPTURE_INCLUDE_IP = "true";
156
- const recordWithIp: LeadCaptureRecord = {
157
- ...record,
158
- metadata: { ip: "1.2.3.4" },
159
- };
160
- const result = await appendLeadRecord(recordWithIp);
161
-
162
- expect(result.ok).toBe(true);
163
- const [, content] = mockAppendFile.mock.calls[0];
164
- const parsed = JSON.parse(content.trimEnd());
165
- expect(parsed.metadata?.ip).toBe("1.2.3.4");
166
- });
167
-
168
- // AC14 — never throws; returns ok:false on fs error
169
- it("returns ok:false on fs error, never throws", async () => {
170
- mockAppendFile.mockRejectedValue(new Error("ENOSPC: no space"));
171
-
172
- const result = await appendLeadRecord(record);
173
-
174
- expect(result.ok).toBe(false);
175
- expect((result as { ok: false; error: string }).error).toMatch(/ENOSPC/);
176
- await expect(appendLeadRecord(record)).resolves.toBeDefined();
177
- });
178
-
179
- // Written content must be JSONL (one JSON object per line + newline)
180
- it("writes valid JSONL format (one JSON object + trailing newline)", async () => {
181
- await appendLeadRecord(record);
182
- const [, content] = mockAppendFile.mock.calls[0];
183
- expect(content).toMatch(/\n$/);
184
- // Must parse as JSON
185
- expect(() => JSON.parse(content.trimEnd())).not.toThrow();
186
- });
187
-
188
- // AC7 — 50-concurrent write integrity (atomicity via O_APPEND flag)
189
- // We verify the flag is set and all 50 calls complete successfully.
190
- // Real O_APPEND atomicity is kernel-guaranteed for local filesystems.
191
- it("50 concurrent writes all resolve ok:true with flag:a", async () => {
192
- const promises = Array.from({ length: 50 }, (_, i) =>
193
- appendLeadRecord({ ...record, id: `fallback-1700000000000-${i}` }),
194
- );
195
- const results = await Promise.all(promises);
196
- expect(results).toHaveLength(50);
197
- results.forEach((r) => expect(r.ok).toBe(true));
198
- // All calls use flag:'a'
199
- mockAppendFile.mock.calls.forEach(([, , opts]) => {
200
- expect(opts).toMatchObject({ flag: "a" });
201
- });
202
- expect(mockAppendFile).toHaveBeenCalledTimes(50);
203
- });
204
-
205
- // Record shape must match LeadCaptureRecord (id, createdAt, source, data, metadata)
206
- it("written JSONL contains all required top-level fields", async () => {
207
- await appendLeadRecord(record);
208
- const [, content] = mockAppendFile.mock.calls[0];
209
- const parsed = JSON.parse(content.trimEnd());
210
- expect(parsed).toHaveProperty("id");
211
- expect(parsed).toHaveProperty("createdAt");
212
- expect(parsed).toHaveProperty("source");
213
- expect(parsed).toHaveProperty("data");
214
- expect(parsed).toHaveProperty("metadata");
215
- });
216
- });
217
-
218
- describe("validateLeadCaptureDir", () => {
219
- beforeEach(() => {
220
- jest.clearAllMocks();
221
- delete process.env.LEAD_CAPTURE_FILE;
222
- delete process.env.LEAD_CAPTURE_FILE_DISABLED;
223
- });
224
-
225
- afterEach(() => {
226
- delete process.env.LEAD_CAPTURE_FILE;
227
- delete process.env.LEAD_CAPTURE_FILE_DISABLED;
228
- });
229
-
230
- // AC8 — no LEAD_CAPTURE_FILE set → no-op (validation passes)
231
- it("resolves without error when LEAD_CAPTURE_FILE not set", async () => {
232
- await expect(validateLeadCaptureDir()).resolves.toBeUndefined();
233
- });
234
-
235
- // AC8 — LEAD_CAPTURE_FILE_DISABLED → no-op
236
- it("resolves without error when LEAD_CAPTURE_FILE_DISABLED=true", async () => {
237
- process.env.LEAD_CAPTURE_FILE_DISABLED = "true";
238
- process.env.LEAD_CAPTURE_FILE = "/nonexistent/dir/leads.jsonl";
239
- await expect(validateLeadCaptureDir()).resolves.toBeUndefined();
240
- });
241
-
242
- // AC8 — directory exists → resolves
243
- it("resolves when LEAD_CAPTURE_FILE directory exists", async () => {
244
- process.env.LEAD_CAPTURE_FILE = "/tmp/exists/leads.jsonl";
245
- mockAccess.mockResolvedValue(undefined);
246
- await expect(validateLeadCaptureDir()).resolves.toBeUndefined();
247
- });
248
-
249
- // AC8 — directory missing → throws
250
- it("throws when LEAD_CAPTURE_FILE directory does not exist", async () => {
251
- process.env.LEAD_CAPTURE_FILE = "/nonexistent/dir/leads.jsonl";
252
- mockAccess.mockRejectedValue(
253
- Object.assign(new Error("ENOENT"), { code: "ENOENT" }),
254
- );
255
- await expect(validateLeadCaptureDir()).rejects.toThrow(/LEAD_CAPTURE_FILE/);
256
- });
257
- });
@@ -1,96 +0,0 @@
1
- /**
2
- * @file lead-delivery.test.ts
3
- * @description The #6730 D1 delivery table, row by row.
4
- */
5
-
6
- import { acceptsKind, resolveLeadDelivery } from "../lead-delivery";
7
-
8
- const EMAIL = {
9
- RESEND_API_KEY: "re_test",
10
- AILK_LEAD_NOTIFICATION_TO: "owner@example.com",
11
- AILK_LEAD_NOTIFICATION_FROM: "noreply@example.com",
12
- };
13
-
14
- describe("resolveLeadDelivery", () => {
15
- it("DATABASE_URL alone → inbox", () => {
16
- expect(resolveLeadDelivery({ DATABASE_URL: "postgres://x", NODE_ENV: "production" })).toBe(
17
- "inbox",
18
- );
19
- });
20
-
21
- it("DATABASE_URL wins over the email vars", () => {
22
- expect(resolveLeadDelivery({ DATABASE_URL: "postgres://x", ...EMAIL })).toBe("inbox");
23
- });
24
-
25
- it("the three email vars, no database → email", () => {
26
- expect(resolveLeadDelivery({ ...EMAIL, NODE_ENV: "production" })).toBe("email");
27
- expect(resolveLeadDelivery({ ...EMAIL, NODE_ENV: "development" })).toBe("email");
28
- });
29
-
30
- it("a bare RESEND_API_KEY is not email delivery — local in dev, none in production", () => {
31
- expect(resolveLeadDelivery({ RESEND_API_KEY: "re_test", NODE_ENV: "development" })).toBe(
32
- "local",
33
- );
34
- expect(resolveLeadDelivery({ RESEND_API_KEY: "re_test", NODE_ENV: "production" })).toBe(
35
- "none",
36
- );
37
- });
38
-
39
- it("the key and one address only → not email", () => {
40
- expect(
41
- resolveLeadDelivery({
42
- RESEND_API_KEY: "re_test",
43
- AILK_LEAD_NOTIFICATION_TO: "owner@example.com",
44
- NODE_ENV: "production",
45
- }),
46
- ).toBe("none");
47
- });
48
-
49
- it("nothing configured in production → none", () => {
50
- expect(resolveLeadDelivery({ NODE_ENV: "production" })).toBe("none");
51
- });
52
-
53
- it("nothing configured outside production → local", () => {
54
- expect(resolveLeadDelivery({ NODE_ENV: "test" })).toBe("local");
55
- expect(resolveLeadDelivery({})).toBe("local");
56
- });
57
-
58
- it("LEAD_CAPTURE_FILE_DISABLED=true removes the local path → none", () => {
59
- expect(
60
- resolveLeadDelivery({ NODE_ENV: "development", LEAD_CAPTURE_FILE_DISABLED: "true" }),
61
- ).toBe("none");
62
- });
63
-
64
- it("reads process.env by default", () => {
65
- const saved = process.env.DATABASE_URL;
66
- process.env.DATABASE_URL = "postgres://x";
67
- try {
68
- expect(resolveLeadDelivery()).toBe("inbox");
69
- } finally {
70
- if (saved === undefined) delete process.env.DATABASE_URL;
71
- else process.env.DATABASE_URL = saved;
72
- }
73
- });
74
- });
75
-
76
- describe("acceptsKind", () => {
77
- it("none accepts nothing", () => {
78
- expect(acceptsKind("none", "submit")).toBe(false);
79
- expect(acceptsKind("none", "subscribe")).toBe(false);
80
- expect(acceptsKind("none", "callback")).toBe(false);
81
- });
82
-
83
- it("email accepts submit and callback, never subscribe", () => {
84
- expect(acceptsKind("email", "submit")).toBe(true);
85
- expect(acceptsKind("email", "callback")).toBe(true);
86
- expect(acceptsKind("email", "subscribe")).toBe(false);
87
- });
88
-
89
- it("inbox and local accept every kind", () => {
90
- for (const d of ["inbox", "local"] as const) {
91
- expect(acceptsKind(d, "submit")).toBe(true);
92
- expect(acceptsKind(d, "subscribe")).toBe(true);
93
- expect(acceptsKind(d, "callback")).toBe(true);
94
- }
95
- });
96
- });
@@ -1,125 +0,0 @@
1
- /**
2
- * outbound-http — fetch wrapper with timeout + SSRF allow-list.
3
- *
4
- * Every outbound HTTP call originating from apps/api/src/lib goes through this
5
- * wrapper. Two guarantees:
6
- *
7
- * 1. Default 10s timeout via AbortSignal.timeout
8
- * 2. SSRF allow-list — RFC 1918 / loopback / link-local addresses are rejected
9
- * unless explicitly allowed (test-mode escape hatch only)
10
- *
11
- * The wrapper is forward-looking — apps/api/src/lib currently has no outbound
12
- * fetch callsites — so the wrapper exists and tests pin its contract before
13
- * the first consumer arrives.
14
- */
15
- import { ssrfBlocked, outboundFetch } from "../outbound-http.js";
16
-
17
- describe("outbound-http — SSRF allow-list", () => {
18
- it.each([
19
- ["http://127.0.0.1/path", "loopback"],
20
- ["http://127.255.0.1/path", "loopback"],
21
- ["http://localhost/path", "loopback hostname"],
22
- ["http://10.0.0.1/", "RFC 1918 10/8"],
23
- ["http://10.255.255.255/", "RFC 1918 10/8 edge"],
24
- ["http://172.16.0.1/", "RFC 1918 172.16/12"],
25
- ["http://172.31.255.255/", "RFC 1918 172.16/12 edge"],
26
- ["http://192.168.0.1/", "RFC 1918 192.168/16"],
27
- ["http://192.168.255.255/", "RFC 1918 192.168/16 edge"],
28
- ["http://169.254.169.254/latest/meta-data/", "AWS metadata link-local"],
29
- ["http://169.254.0.1/", "link-local"],
30
- ["http://[::1]/", "IPv6 loopback"],
31
- ["http://0.0.0.0/", "all-interfaces wildcard"],
32
- ])("rejects %s (%s)", (url) => {
33
- expect(ssrfBlocked(url)).toBe(true);
34
- });
35
-
36
- it.each([
37
- ["https://api.stripe.com/v1/x", "public Stripe"],
38
- ["https://api.example.com/path", "generic public host"],
39
- ["http://8.8.8.8/", "public IP"],
40
- ["https://172.15.0.1/", "172.15 is OUT of RFC 1918 172.16/12"],
41
- ["https://172.32.0.1/", "172.32 is OUT of RFC 1918 172.16/12"],
42
- ])("allows %s (%s)", (url) => {
43
- expect(ssrfBlocked(url)).toBe(false);
44
- });
45
-
46
- it("rejects non-HTTP schemes", () => {
47
- expect(ssrfBlocked("file:///etc/passwd")).toBe(true);
48
- expect(ssrfBlocked("ftp://example.com/")).toBe(true);
49
- expect(ssrfBlocked("javascript:alert(1)")).toBe(true);
50
- expect(ssrfBlocked("gopher://example.com/")).toBe(true);
51
- });
52
-
53
- it("rejects unparseable URLs", () => {
54
- expect(ssrfBlocked("not a url")).toBe(true);
55
- expect(ssrfBlocked("")).toBe(true);
56
- });
57
- });
58
-
59
- describe("outbound-http — outboundFetch", () => {
60
- let originalFetch: typeof globalThis.fetch;
61
-
62
- beforeEach(() => {
63
- originalFetch = globalThis.fetch;
64
- });
65
-
66
- afterEach(() => {
67
- globalThis.fetch = originalFetch;
68
- });
69
-
70
- it("rejects SSRF-blocked URLs before issuing a network call", async () => {
71
- const fetchSpy: jest.Mock<ReturnType<typeof globalThis.fetch>, Parameters<typeof globalThis.fetch>> =
72
- jest.fn();
73
- globalThis.fetch = fetchSpy;
74
-
75
- await expect(outboundFetch("http://127.0.0.1/admin")).rejects.toThrow(
76
- /SSRF|disallowed|forbidden/i,
77
- );
78
- expect(fetchSpy).not.toHaveBeenCalled();
79
- });
80
-
81
- it("issues fetch on an allowed URL with a default timeout signal", async () => {
82
- const fetchSpy: typeof globalThis.fetch = jest.fn(async (_url, init) => {
83
- // confirm AbortSignal is wired
84
- expect((init as RequestInit | undefined)?.signal).toBeDefined();
85
- return new Response("ok", { status: 200 });
86
- });
87
- globalThis.fetch = fetchSpy;
88
-
89
- const res = await outboundFetch("https://api.example.com/x");
90
- expect(res.status).toBe(200);
91
- expect(fetchSpy).toHaveBeenCalledTimes(1);
92
- });
93
-
94
- it("aborts when timeout elapses before fetch resolves", async () => {
95
- // Mock fetch to honor the abort signal — simulates a real slow server.
96
- const slowFetch: typeof globalThis.fetch = async (_url, init) => {
97
- return new Promise((_resolve, reject) => {
98
- (init as RequestInit | undefined)?.signal?.addEventListener(
99
- "abort",
100
- () => {
101
- reject(new DOMException("aborted", "AbortError"));
102
- },
103
- );
104
- });
105
- };
106
- globalThis.fetch = slowFetch;
107
-
108
- await expect(
109
- outboundFetch("https://api.example.com/slow", { timeoutMs: 50 }),
110
- ).rejects.toThrow(/abort|timeout/i);
111
- });
112
-
113
- it("respects the per-call allowPrivate escape hatch (test/dev only)", async () => {
114
- const fetchSpy: typeof globalThis.fetch = jest.fn(
115
- async () => new Response("ok", { status: 200 }),
116
- );
117
- globalThis.fetch = fetchSpy;
118
-
119
- const res = await outboundFetch("http://127.0.0.1/local-svc", {
120
- allowPrivate: true,
121
- });
122
- expect(res.status).toBe(200);
123
- expect(fetchSpy).toHaveBeenCalledTimes(1);
124
- });
125
- });
@@ -1,165 +0,0 @@
1
- /**
2
- * Unit tests for the prisma.ts singleton — verify construction, log routing,
3
- * and globalThis caching behaviour without touching the real adapter or DB.
4
- */
5
-
6
- const mockPrismaInstance = {
7
- $connect: jest.fn(),
8
- $disconnect: jest.fn(),
9
- user: {},
10
- apiToken: {},
11
- userData: {},
12
- };
13
-
14
- const MockPrismaClient = jest.fn().mockImplementation((options) => {
15
- expect(options).toBeDefined();
16
- expect(options.adapter).toBeDefined();
17
- return mockPrismaInstance;
18
- });
19
-
20
- // Mock @prisma/adapter-pg so the import in prisma.ts doesn't construct a
21
- // real pg.Pool against DATABASE_URL.
22
- const MockPrismaPg = jest.fn().mockImplementation((config) => {
23
- expect(config).toBeDefined();
24
- expect(config.connectionString).toBeDefined();
25
- return { __mockAdapter: true };
26
- });
27
-
28
- jest.mock('@prisma/adapter-pg', () => ({
29
- PrismaPg: MockPrismaPg,
30
- }));
31
-
32
- jest.mock('@working-theory/database', () => ({
33
- PrismaClient: MockPrismaClient,
34
- }));
35
-
36
- describe('Prisma Client', () => {
37
- const originalEnv = process.env;
38
-
39
- beforeEach(() => {
40
- jest.resetModules();
41
- process.env = { ...originalEnv };
42
- // Clear global prisma
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
44
- (globalThis as any).prisma = undefined;
45
- jest.clearAllMocks();
46
- });
47
-
48
- afterEach(() => {
49
- process.env = originalEnv;
50
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
51
- (globalThis as any).prisma = undefined;
52
- });
53
-
54
- describe('PrismaClient initialization', () => {
55
- it('should create new PrismaClient instance when globalThis.prisma is undefined', () => {
56
- // ARRANGE
57
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
58
- (globalThis as any).prisma = undefined;
59
- process.env.NODE_ENV = 'test';
60
-
61
- // ACT
62
- const { prisma } = require('../prisma');
63
-
64
- // ASSERT
65
- expect(prisma).toBeDefined();
66
- const { PrismaClient } = require('@working-theory/database');
67
- expect(PrismaClient).toHaveBeenCalled();
68
- });
69
-
70
- it('should use existing globalThis.prisma instance if available', () => {
71
- // ARRANGE
72
- const mockPrisma = { $connect: jest.fn(), user: {} };
73
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
74
- (globalThis as any).prisma = mockPrisma;
75
-
76
- // ACT
77
- const { prisma } = require('../prisma');
78
-
79
- // ASSERT
80
- expect(prisma).toBe(mockPrisma);
81
- const { PrismaClient } = require('@working-theory/database');
82
- expect(PrismaClient).not.toHaveBeenCalled();
83
- });
84
-
85
- it('should configure logging for development environment', () => {
86
- // ARRANGE
87
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
88
- (globalThis as any).prisma = undefined;
89
- process.env.NODE_ENV = 'development';
90
-
91
- // ACT
92
- require('../prisma');
93
-
94
- // ASSERT
95
- const { PrismaClient } = require('@working-theory/database');
96
- expect(PrismaClient).toHaveBeenCalledWith({
97
- adapter: expect.objectContaining({ __mockAdapter: true }),
98
- log: ['query', 'error', 'warn'],
99
- });
100
- });
101
-
102
- it('should configure minimal logging for production environment', () => {
103
- // ARRANGE
104
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
105
- (globalThis as any).prisma = undefined;
106
- process.env.NODE_ENV = 'production';
107
-
108
- // ACT
109
- require('../prisma');
110
-
111
- // ASSERT
112
- const { PrismaClient } = require('@working-theory/database');
113
- expect(PrismaClient).toHaveBeenCalledWith({
114
- adapter: expect.objectContaining({ __mockAdapter: true }),
115
- log: ['error'],
116
- });
117
- });
118
-
119
- it('should configure minimal logging for test environment', () => {
120
- // ARRANGE
121
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
122
- (globalThis as any).prisma = undefined;
123
- process.env.NODE_ENV = 'test';
124
-
125
- // ACT
126
- require('../prisma');
127
-
128
- // ASSERT
129
- const { PrismaClient } = require('@working-theory/database');
130
- expect(PrismaClient).toHaveBeenCalledWith({
131
- adapter: expect.objectContaining({ __mockAdapter: true }),
132
- log: ['error'],
133
- });
134
- });
135
-
136
- it('should store prisma instance in globalThis for non-production environments', () => {
137
- // ARRANGE
138
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
139
- (globalThis as any).prisma = undefined;
140
- process.env.NODE_ENV = 'development';
141
-
142
- // ACT
143
- const { prisma } = require('../prisma');
144
-
145
- // ASSERT
146
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
147
- expect((globalThis as any).prisma).toBe(prisma);
148
- });
149
-
150
- it('should not store prisma instance in globalThis for production', () => {
151
- // ARRANGE
152
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- #506/#507: pre-existing test-hygiene violation
153
- (globalThis as any).prisma = undefined;
154
- process.env.NODE_ENV = 'production';
155
-
156
- // ACT
157
- const { prisma } = require('../prisma');
158
-
159
- // ASSERT
160
- // In production, it should not be stored in globalThis
161
- // But the instance should still be created
162
- expect(prisma).toBeDefined();
163
- });
164
- });
165
- });