@beechcms/api 0.6.0-preview.1 → 0.6.0-preview.3

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 (373) hide show
  1. package/README.md +4 -4
  2. package/assets/dashboard/BeechLogo.svg +18 -18
  3. package/assets/dashboard/BeechLogoLIght.svg +48 -48
  4. package/assets/dashboard/assets/chart-Cws4Yj6K.js +39 -0
  5. package/assets/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  6. package/assets/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  7. package/assets/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  8. package/assets/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  9. package/assets/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  10. package/assets/dashboard/assets/index-BjPpppHe.css +1 -0
  11. package/assets/dashboard/assets/index-CrW-zhkA.js +642 -0
  12. package/assets/dashboard/assets/lora-cyrillic-ext-wght-normal-YcVxMP-u.woff2 +0 -0
  13. package/assets/dashboard/assets/lora-cyrillic-wght-normal-UWPuZLjM.woff2 +0 -0
  14. package/assets/dashboard/assets/lora-latin-ext-wght-normal-C2Wlntb9.woff2 +0 -0
  15. package/assets/dashboard/assets/lora-latin-wght-normal-BiLcIKcI.woff2 +0 -0
  16. package/assets/dashboard/assets/lora-math-wght-normal-sOy7rEfW.woff2 +0 -0
  17. package/assets/dashboard/assets/lora-symbols-wght-normal-DQ5VrUkH.woff2 +0 -0
  18. package/assets/dashboard/assets/lora-vietnamese-wght-normal-CfJ7gtf3.woff2 +0 -0
  19. package/assets/dashboard/assets/pie-chart-recharts-CAxoDQp2.js +1 -0
  20. package/assets/dashboard/assets/timeseries-chart-recharts-CixDW-LM.js +1 -0
  21. package/assets/dashboard/beechLogoDark.svg +48 -48
  22. package/assets/dashboard/index.html +18 -18
  23. package/assets/dashboard/noResult.svg +42 -42
  24. package/assets/dashboard/sol.svg +3 -3
  25. package/assets/dashboard/undraw_enter_nwx3.svg +36 -36
  26. package/dist/auth/__fixtures__/in-memory-hash-provider.d.ts +5 -0
  27. package/dist/auth/__fixtures__/static-token-service.d.ts +6 -0
  28. package/dist/auth/bcrypt-hash-provider.d.ts +8 -0
  29. package/dist/auth/constants.d.ts +10 -0
  30. package/dist/auth/jose-token-service.d.ts +14 -0
  31. package/dist/auth/login.d.ts +32 -0
  32. package/dist/auth/refresh.d.ts +1 -0
  33. package/dist/factory.d.ts +39 -0
  34. package/dist/features/automations/action-executors/create-entry.executor.d.ts +7 -0
  35. package/dist/features/automations/action-executors/edit-field.executor.d.ts +7 -0
  36. package/dist/features/automations/action-executors/index.d.ts +13 -0
  37. package/dist/features/automations/action-executors/send-mail.executor.d.ts +7 -0
  38. package/dist/features/automations/action-executors/set-variable.executor.d.ts +15 -0
  39. package/dist/features/automations/action-executors/webhook.executor.d.ts +7 -0
  40. package/dist/features/automations/automation-runner.d.ts +13 -0
  41. package/dist/features/automations/automation-runner.utils.d.ts +3 -0
  42. package/dist/features/automations/automations.handler.d.ts +7 -0
  43. package/dist/features/automations/automations.schema.d.ts +191 -0
  44. package/dist/features/automations/context-resolver.d.ts +8 -0
  45. package/dist/features/automations/cron-runner.d.ts +9 -0
  46. package/dist/features/automations/cron-runner.utils.d.ts +1 -0
  47. package/dist/features/automations/filter-translation.d.ts +9 -0
  48. package/dist/features/automations/index.d.ts +7 -0
  49. package/dist/features/automations/template-grammar.d.ts +73 -0
  50. package/dist/features/automations/var-access-resolver.d.ts +6 -0
  51. package/dist/features/automations/when-evaluator.d.ts +3 -0
  52. package/dist/features/automations/when-pushdown.d.ts +2 -0
  53. package/dist/features/backrefs/backrefs.handler.d.ts +3 -0
  54. package/dist/features/backrefs/d1-backref.repository.d.ts +17 -0
  55. package/dist/features/backrefs/index.d.ts +1 -0
  56. package/dist/features/content/constants.d.ts +12 -0
  57. package/dist/features/content/handlers/bulk.handler.d.ts +3 -0
  58. package/dist/features/content/handlers/create.d.ts +3 -0
  59. package/dist/features/content/handlers/delete.d.ts +3 -0
  60. package/dist/features/content/handlers/facets.d.ts +3 -0
  61. package/dist/features/content/handlers/get.d.ts +4 -0
  62. package/dist/features/content/handlers/helpers.d.ts +12 -0
  63. package/dist/features/content/handlers/list.d.ts +3 -0
  64. package/dist/features/content/handlers/update.d.ts +3 -0
  65. package/dist/features/content/index.d.ts +4 -0
  66. package/dist/features/dashboard-layout/dashboard-layout.handler.d.ts +7 -0
  67. package/dist/features/dashboard-layout/index.d.ts +1 -0
  68. package/dist/features/draft/draft.handler.d.ts +4 -0
  69. package/dist/features/draft/draft.middleware.d.ts +9 -0
  70. package/dist/features/draft/index.d.ts +1 -0
  71. package/{src/features/email/email.provider.ts → dist/features/email/email.provider.d.ts} +37 -42
  72. package/dist/features/email/email.service.d.ts +13 -0
  73. package/dist/features/email/email.types.d.ts +94 -0
  74. package/{src/features/email/index.ts → dist/features/email/index.d.ts} +20 -33
  75. package/dist/features/email/providers/resend.d.ts +36 -0
  76. package/dist/features/email/providers/smtp.d.ts +11 -0
  77. package/dist/features/email/templates/automation-mail.d.ts +8 -0
  78. package/dist/features/email/templates/password-changed.d.ts +15 -0
  79. package/dist/features/email/templates/password-reset.d.ts +18 -0
  80. package/dist/features/email/templates/shell.d.ts +58 -0
  81. package/dist/features/notifications/index.d.ts +1 -0
  82. package/dist/features/notifications/notifications.handler.d.ts +15 -0
  83. package/dist/features/password-reset/index.d.ts +6 -0
  84. package/dist/features/password-reset/request.d.ts +10 -0
  85. package/dist/features/password-reset/reset.d.ts +9 -0
  86. package/dist/features/rotate-field/index.d.ts +1 -0
  87. package/dist/features/rotate-field/rotate-field.handler.d.ts +7 -0
  88. package/dist/features/rotate-field/rotate-field.schema.d.ts +11 -0
  89. package/dist/features/schema/schema.handler.d.ts +7 -0
  90. package/dist/features/seeds/index.d.ts +1 -0
  91. package/dist/features/seeds/seeds.handler.d.ts +6 -0
  92. package/dist/features/settings/settings.handler.d.ts +7 -0
  93. package/dist/features/setup/index.d.ts +7 -0
  94. package/dist/features/stats/index.d.ts +1 -0
  95. package/dist/features/stats/stats.handler.d.ts +7 -0
  96. package/dist/features/webhooks/index.d.ts +3 -0
  97. package/dist/index.d.ts +6 -0
  98. package/dist/index.js +9666 -0
  99. package/dist/media-utils.d.ts +25 -0
  100. package/dist/middleware/auth-providers.middleware.d.ts +8 -0
  101. package/dist/middleware/observability.middleware.d.ts +20 -0
  102. package/dist/middleware/rate-limit.middleware.d.ts +9 -0
  103. package/dist/middleware/repository.middleware.d.ts +34 -0
  104. package/dist/middleware/seed-registry.middleware.d.ts +10 -0
  105. package/dist/middleware/storage.middleware.d.ts +7 -0
  106. package/dist/middleware.d.ts +11 -0
  107. package/dist/public/access-policy.d.ts +12 -0
  108. package/dist/public/api-key-middleware.d.ts +6 -0
  109. package/dist/public/cache-utils.d.ts +10 -0
  110. package/dist/public/entry-projection.d.ts +2 -0
  111. package/dist/public/idempotency.d.ts +9 -0
  112. package/dist/public/index.d.ts +11 -0
  113. package/dist/public/problem-details.d.ts +31 -0
  114. package/dist/public/public-add.d.ts +3 -0
  115. package/dist/public/public-edit.d.ts +5 -0
  116. package/dist/public/public-errors.d.ts +13 -0
  117. package/dist/public/public-read.d.ts +3 -0
  118. package/dist/public/public-routes.d.ts +3 -0
  119. package/dist/public/query-builder.d.ts +28 -0
  120. package/dist/public/rate-limit-middleware.d.ts +3 -0
  121. package/dist/public/read-list.d.ts +26 -0
  122. package/dist/public/read-single.d.ts +22 -0
  123. package/dist/public/response-builder.d.ts +22 -0
  124. package/dist/public/sanitize.d.ts +23 -0
  125. package/dist/public/slug-utils.d.ts +11 -0
  126. package/dist/rate-limit/cloudflare-rate-limiter.d.ts +6 -0
  127. package/dist/rate-limit/in-memory-rate-limiter.d.ts +7 -0
  128. package/dist/rate-limit/no-op-rate-limiter.d.ts +4 -0
  129. package/dist/search-utils.d.ts +54 -0
  130. package/dist/search.d.ts +6 -0
  131. package/dist/shared/apply-policies.d.ts +10 -0
  132. package/dist/shared/automations.repository.d1.d.ts +12 -0
  133. package/dist/shared/background-notification-service.d.ts +18 -0
  134. package/dist/shared/base.repository.d1.d.ts +18 -0
  135. package/dist/shared/content-utils.d.ts +21 -0
  136. package/dist/shared/content.repository.d1.d.ts +68 -0
  137. package/dist/shared/d1-activity-log.repository.d.ts +13 -0
  138. package/dist/shared/d1-activity-logger.d.ts +20 -0
  139. package/dist/shared/d1-analytics.repository.d.ts +20 -0
  140. package/dist/shared/d1-content-scan.repository.d.ts +7 -0
  141. package/dist/shared/d1-notification.repository.d.ts +17 -0
  142. package/dist/shared/d1-password-reset-token.repository.d.ts +10 -0
  143. package/dist/shared/d1-search.repository.d.ts +14 -0
  144. package/dist/shared/d1-session.repository.d.ts +12 -0
  145. package/dist/shared/d1-setup-checklist.repository.d.ts +12 -0
  146. package/dist/shared/d1-user.repository.d.ts +18 -0
  147. package/dist/shared/d1-widget.repository.d.ts +31 -0
  148. package/dist/shared/dashboard-layout.repository.d1.d.ts +9 -0
  149. package/dist/shared/demo-data-sql.d.ts +1 -0
  150. package/dist/shared/demo-data.repository.d1.d.ts +6 -0
  151. package/dist/shared/execution-context-scheduler.d.ts +6 -0
  152. package/dist/shared/fixed-clock.d.ts +13 -0
  153. package/dist/shared/fts-sync.d.ts +1 -0
  154. package/dist/shared/idempotency.repository.d1.d.ts +16 -0
  155. package/dist/shared/in-memory-activity-logger.d.ts +11 -0
  156. package/dist/shared/in-memory-notification-service.d.ts +11 -0
  157. package/dist/shared/in-memory-seed.repository.d.ts +18 -0
  158. package/dist/shared/media.repository.d1.d.ts +35 -0
  159. package/dist/shared/qstash-notification-service.d.ts +18 -0
  160. package/dist/shared/query-utils.d.ts +36 -0
  161. package/dist/shared/request-utils.d.ts +13 -0
  162. package/dist/shared/schema-mutator.d1.d.ts +12 -0
  163. package/dist/shared/seed-layout.repository.d1.d.ts +9 -0
  164. package/dist/shared/seed-registry-cache.d.ts +12 -0
  165. package/dist/shared/seed.repository.d1.d.ts +13 -0
  166. package/dist/shared/sequential-id-generator.d.ts +13 -0
  167. package/dist/shared/site-settings.repository.d1.d.ts +7 -0
  168. package/dist/shared/storage/factory.d.ts +8 -0
  169. package/dist/shared/storage/s3-bucket.d.ts +43 -0
  170. package/dist/shared/storage-utils.d.ts +7 -0
  171. package/dist/shared/system-stats.repository.d1.d.ts +25 -0
  172. package/dist/types.d.ts +85 -0
  173. package/dist/upload.d.ts +16 -0
  174. package/dist/widget.d.ts +7 -0
  175. package/migrations/0000_v040_base.sql +265 -265
  176. package/migrations/0029_automations.sql +14 -14
  177. package/migrations/0030_test_seeds.sql +125 -125
  178. package/package.json +27 -18
  179. package/assets/dashboard/assets/index-BSjk0Sx9.js +0 -634
  180. package/assets/dashboard/assets/index-kRCYVN2B.css +0 -1
  181. package/src/auth/__fixtures__/in-memory-hash-provider.ts +0 -17
  182. package/src/auth/__fixtures__/static-token-service.ts +0 -22
  183. package/src/auth/bcrypt-hash-provider.ts +0 -24
  184. package/src/auth/constants.ts +0 -14
  185. package/src/auth/generate-refresh-token.test.ts +0 -23
  186. package/src/auth/hash-provider.test.ts +0 -55
  187. package/src/auth/jose-token-service.ts +0 -62
  188. package/src/auth/jwt-claims-passthrough.test.ts +0 -87
  189. package/src/auth/login.test.ts +0 -100
  190. package/src/auth/login.ts +0 -78
  191. package/src/auth/refresh.ts +0 -11
  192. package/src/auth/token-service.test.ts +0 -90
  193. package/src/factory.ts +0 -368
  194. package/src/features/automations/__tests__/action-executors.test.ts +0 -255
  195. package/src/features/automations/__tests__/automation-runner.test.ts +0 -196
  196. package/src/features/automations/__tests__/automation-runner.utils.test.ts +0 -60
  197. package/src/features/automations/__tests__/automations.handler.test.ts +0 -264
  198. package/src/features/automations/__tests__/automations.repository.test.ts +0 -163
  199. package/src/features/automations/__tests__/automations.schema.test.ts +0 -224
  200. package/src/features/automations/__tests__/context-resolver.test.ts +0 -126
  201. package/src/features/automations/__tests__/cron-runner.test.ts +0 -267
  202. package/src/features/automations/__tests__/cron-runner.utils.test.ts +0 -144
  203. package/src/features/automations/__tests__/set-variable.executor.test.ts +0 -383
  204. package/src/features/automations/__tests__/template-grammar.test.ts +0 -308
  205. package/src/features/automations/__tests__/webhook.executor.test.ts +0 -142
  206. package/src/features/automations/__tests__/when-evaluator.test.ts +0 -274
  207. package/src/features/automations/__tests__/when-pushdown.test.ts +0 -281
  208. package/src/features/automations/action-executors/create-entry.executor.ts +0 -27
  209. package/src/features/automations/action-executors/edit-field.executor.ts +0 -26
  210. package/src/features/automations/action-executors/index.ts +0 -37
  211. package/src/features/automations/action-executors/send-mail.executor.ts +0 -53
  212. package/src/features/automations/action-executors/set-variable.executor.ts +0 -159
  213. package/src/features/automations/action-executors/webhook.executor.ts +0 -67
  214. package/src/features/automations/automation-runner.ts +0 -85
  215. package/src/features/automations/automation-runner.utils.ts +0 -47
  216. package/src/features/automations/automations.handler.ts +0 -197
  217. package/src/features/automations/automations.schema.ts +0 -177
  218. package/src/features/automations/context-resolver.ts +0 -152
  219. package/src/features/automations/cron-runner.ts +0 -140
  220. package/src/features/automations/cron-runner.utils.ts +0 -44
  221. package/src/features/automations/filter-translation.ts +0 -46
  222. package/src/features/automations/index.ts +0 -16
  223. package/src/features/automations/template-grammar.ts +0 -245
  224. package/src/features/automations/var-access-resolver.ts +0 -140
  225. package/src/features/automations/when-evaluator.ts +0 -87
  226. package/src/features/automations/when-pushdown.ts +0 -57
  227. package/src/features/backrefs/__tests__/backrefs.handler.test.ts +0 -359
  228. package/src/features/backrefs/backrefs.handler.ts +0 -168
  229. package/src/features/backrefs/d1-backref.repository.ts +0 -84
  230. package/src/features/backrefs/index.ts +0 -5
  231. package/src/features/content/constants.ts +0 -16
  232. package/src/features/content/handlers/bulk.handler.ts +0 -185
  233. package/src/features/content/handlers/create.ts +0 -129
  234. package/src/features/content/handlers/delete.ts +0 -62
  235. package/src/features/content/handlers/facets.ts +0 -49
  236. package/src/features/content/handlers/get.ts +0 -120
  237. package/src/features/content/handlers/helpers.test.ts +0 -180
  238. package/src/features/content/handlers/helpers.ts +0 -93
  239. package/src/features/content/handlers/list.ts +0 -174
  240. package/src/features/content/handlers/update.ts +0 -174
  241. package/src/features/content/index.ts +0 -26
  242. package/src/features/draft/draft.handler.ts +0 -195
  243. package/src/features/draft/draft.middleware.ts +0 -66
  244. package/src/features/draft/index.ts +0 -5
  245. package/src/features/email/email.service.ts +0 -98
  246. package/src/features/email/email.types.ts +0 -119
  247. package/src/features/email/providers/resend.ts +0 -67
  248. package/src/features/email/providers/smtp.ts +0 -55
  249. package/src/features/email/templates/automation-mail.ts +0 -19
  250. package/src/features/email/templates/password-changed.ts +0 -63
  251. package/src/features/email/templates/password-reset.ts +0 -68
  252. package/src/features/email/templates/shell.ts +0 -96
  253. package/src/features/notifications/index.ts +0 -5
  254. package/src/features/notifications/notifications.handler.ts +0 -105
  255. package/src/features/password-reset/index.ts +0 -19
  256. package/src/features/password-reset/request.ts +0 -92
  257. package/src/features/password-reset/reset.ts +0 -102
  258. package/src/features/rotate-field/index.ts +0 -5
  259. package/src/features/rotate-field/rotate-field.handler.ts +0 -132
  260. package/src/features/rotate-field/rotate-field.schema.ts +0 -17
  261. package/src/features/schema/schema.handler.ts +0 -131
  262. package/src/features/seeds/index.ts +0 -5
  263. package/src/features/seeds/seeds.handler.test.ts +0 -632
  264. package/src/features/seeds/seeds.handler.ts +0 -693
  265. package/src/features/settings/__tests__/settings.handler.test.ts +0 -555
  266. package/src/features/settings/settings.handler.ts +0 -392
  267. package/src/features/setup/index.ts +0 -204
  268. package/src/features/stats/index.ts +0 -5
  269. package/src/features/stats/stats.handler.ts +0 -420
  270. package/src/features/webhooks/index.ts +0 -63
  271. package/src/index.ts +0 -65
  272. package/src/media-utils.ts +0 -82
  273. package/src/middleware/auth-providers.middleware.ts +0 -45
  274. package/src/middleware/observability.middleware.ts +0 -70
  275. package/src/middleware/rate-limit.middleware.ts +0 -45
  276. package/src/middleware/repository.middleware.ts +0 -114
  277. package/src/middleware/seed-registry.middleware.test.ts +0 -97
  278. package/src/middleware/seed-registry.middleware.ts +0 -21
  279. package/src/middleware/storage.middleware.ts +0 -25
  280. package/src/middleware.ts +0 -45
  281. package/src/public/access-policy.ts +0 -27
  282. package/src/public/api-key-middleware.ts +0 -57
  283. package/src/public/cache-utils.ts +0 -38
  284. package/src/public/entry-projection.ts +0 -46
  285. package/src/public/idempotency.ts +0 -23
  286. package/src/public/index.ts +0 -16
  287. package/src/public/problem-details.ts +0 -124
  288. package/src/public/public-add.ts +0 -114
  289. package/src/public/public-edit.ts +0 -163
  290. package/src/public/public-errors.ts +0 -19
  291. package/src/public/public-read.ts +0 -63
  292. package/src/public/public-routes.ts +0 -88
  293. package/src/public/query-builder.test.ts +0 -224
  294. package/src/public/query-builder.ts +0 -156
  295. package/src/public/rate-limit-middleware.ts +0 -34
  296. package/src/public/read-list.ts +0 -54
  297. package/src/public/read-single.ts +0 -48
  298. package/src/public/response-builder.ts +0 -30
  299. package/src/public/sanitize.ts +0 -69
  300. package/src/public/slug-utils.ts +0 -18
  301. package/src/rate-limit/cloudflare-rate-limiter.test.ts +0 -30
  302. package/src/rate-limit/cloudflare-rate-limiter.ts +0 -15
  303. package/src/rate-limit/in-memory-rate-limiter.test.ts +0 -37
  304. package/src/rate-limit/in-memory-rate-limiter.ts +0 -17
  305. package/src/rate-limit/no-op-rate-limiter.test.ts +0 -22
  306. package/src/rate-limit/no-op-rate-limiter.ts +0 -11
  307. package/src/search-utils.test.ts +0 -211
  308. package/src/search-utils.ts +0 -213
  309. package/src/search.ts +0 -65
  310. package/src/shared/apply-policies.test.ts +0 -81
  311. package/src/shared/apply-policies.ts +0 -67
  312. package/src/shared/automations.repository.d1.ts +0 -150
  313. package/src/shared/background-notification-service.test.ts +0 -62
  314. package/src/shared/background-notification-service.ts +0 -52
  315. package/src/shared/base.repository.d1.ts +0 -32
  316. package/src/shared/content-utils.test.ts +0 -165
  317. package/src/shared/content-utils.ts +0 -86
  318. package/src/shared/content.repository.d1.test.ts +0 -458
  319. package/src/shared/content.repository.d1.ts +0 -851
  320. package/src/shared/d1-activity-log.repository.test.ts +0 -140
  321. package/src/shared/d1-activity-log.repository.ts +0 -105
  322. package/src/shared/d1-activity-logger.test.ts +0 -86
  323. package/src/shared/d1-activity-logger.ts +0 -67
  324. package/src/shared/d1-analytics.repository.test.ts +0 -78
  325. package/src/shared/d1-analytics.repository.ts +0 -85
  326. package/src/shared/d1-content-scan.repository.test.ts +0 -80
  327. package/src/shared/d1-content-scan.repository.ts +0 -37
  328. package/src/shared/d1-notification.repository.test.ts +0 -128
  329. package/src/shared/d1-notification.repository.ts +0 -118
  330. package/src/shared/d1-password-reset-token.repository.test.ts +0 -81
  331. package/src/shared/d1-password-reset-token.repository.ts +0 -56
  332. package/src/shared/d1-search.repository.test.ts +0 -87
  333. package/src/shared/d1-search.repository.ts +0 -88
  334. package/src/shared/d1-session.repository.test.ts +0 -125
  335. package/src/shared/d1-session.repository.ts +0 -102
  336. package/src/shared/d1-setup-checklist.repository.ts +0 -36
  337. package/src/shared/d1-user.repository.test.ts +0 -151
  338. package/src/shared/d1-user.repository.ts +0 -119
  339. package/src/shared/d1-widget.repository.test.ts +0 -221
  340. package/src/shared/d1-widget.repository.ts +0 -341
  341. package/src/shared/demo-data-sql.ts +0 -54
  342. package/src/shared/demo-data.repository.d1.ts +0 -20
  343. package/src/shared/execution-context-scheduler.ts +0 -13
  344. package/src/shared/fixed-clock.ts +0 -25
  345. package/src/shared/fts-sync.ts +0 -8
  346. package/src/shared/idempotency.repository.d1.test.ts +0 -83
  347. package/src/shared/idempotency.repository.d1.ts +0 -60
  348. package/src/shared/in-memory-activity-logger.ts +0 -19
  349. package/src/shared/in-memory-notification-service.ts +0 -19
  350. package/src/shared/in-memory-seed.repository.ts +0 -51
  351. package/src/shared/media.repository.d1.test.ts +0 -107
  352. package/src/shared/media.repository.d1.ts +0 -68
  353. package/src/shared/qstash-notification-service.test.ts +0 -67
  354. package/src/shared/qstash-notification-service.ts +0 -55
  355. package/src/shared/query-utils.ts +0 -141
  356. package/src/shared/request-utils.ts +0 -26
  357. package/src/shared/schema-mutator.d1.ts +0 -64
  358. package/src/shared/seed-layout.repository.d1.test.ts +0 -114
  359. package/src/shared/seed-layout.repository.d1.ts +0 -62
  360. package/src/shared/seed-registry-cache.test.ts +0 -68
  361. package/src/shared/seed-registry-cache.ts +0 -49
  362. package/src/shared/seed.repository.d1.test.ts +0 -143
  363. package/src/shared/seed.repository.d1.ts +0 -98
  364. package/src/shared/sequential-id-generator.ts +0 -33
  365. package/src/shared/site-settings.repository.d1.ts +0 -53
  366. package/src/shared/storage/factory.ts +0 -41
  367. package/src/shared/storage/s3-bucket.ts +0 -195
  368. package/src/shared/storage-utils.ts +0 -40
  369. package/src/shared/system-stats.repository.d1.test.ts +0 -58
  370. package/src/shared/system-stats.repository.d1.ts +0 -48
  371. package/src/types.ts +0 -87
  372. package/src/upload.ts +0 -198
  373. package/src/widget.ts +0 -212
@@ -1,195 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- /// <reference types="@cloudflare/workers-types" />
6
- import { Context, Hono } from 'hono'
7
- import {
8
- validateAndSanitizeSeedPayload,
9
- resolvePolicies,
10
- RelationTargetNotFoundError,
11
- } from '@beechcms/core'
12
- import { publicProblem } from '../../public/problem-details'
13
- import { cleanStr } from '../../shared/query-utils'
14
- import { applyVisibility } from '../../shared/apply-policies'
15
- import { AppEnv } from '../../types'
16
- import { CONTENT_ERRORS } from '../content/constants'
17
- import { draftGuard } from './draft.middleware'
18
-
19
- const draftApp = new Hono<AppEnv>()
20
-
21
- // GET /drafts — Unified list of pending drafts across all draft-enabled seeds.
22
- draftApp.get('/drafts', async (context) => {
23
- const seeds = context.get('seedRegistry').draftEnabled()
24
- const repository = context.get('repository')
25
- const drafts = await repository.findPendingDrafts(seeds)
26
- return context.json(drafts)
27
- })
28
-
29
- function normalizeBody(raw: unknown): Record<string, unknown> {
30
- return typeof raw === 'object' && raw !== null ? (raw as Record<string, unknown>) : {}
31
- }
32
-
33
- function logDraftActivity(
34
- context: Context<AppEnv>,
35
- id: string,
36
- slug: string,
37
- title: string,
38
- note: 'draft saved' | 'draft published'
39
- ) {
40
- const actor = context.get('jwtPayload')
41
- context.get('activityLogger').log({
42
- action: 'update',
43
- entityType: 'content',
44
- entityId: id,
45
- entitySlug: slug,
46
- details: { title, note },
47
- actor: {
48
- id: actor.sub,
49
- email: actor.email ?? 'unknown',
50
- name: [actor.name, actor.surname].filter(Boolean).join(' ') || null,
51
- },
52
- })
53
- }
54
-
55
- // PUT /:slug/:id/draft — Creates or overwrites the pending draft
56
- draftApp.put('/:slug/:id/draft', draftGuard, async (context) => {
57
- const slug = context.req.param('slug')
58
- const id = context.req.param('id')
59
- const seed = context.get('getSeed')(slug)!
60
-
61
- let body: Record<string, unknown>
62
- try {
63
- body = normalizeBody(await context.req.json<unknown>())
64
- } catch {
65
- return publicProblem(context, {
66
- type: 'content-invalid-json',
67
- title: 'Bad Request',
68
- status: 400,
69
- detail: CONTENT_ERRORS.INVALID_JSON_BODY
70
- })
71
- }
72
-
73
- const sensitiveAliases = Object.keys(body).filter((alias) => {
74
- const branch = seed.branches.find((b) => b.alias === alias)
75
- return branch != null && resolvePolicies(branch).privacy !== 'plain'
76
- })
77
-
78
- if (sensitiveAliases.length > 0) {
79
- return publicProblem(context, {
80
- type: 'content-sensitive-field-edit',
81
- title: 'Unprocessable Entity',
82
- status: 422,
83
- detail: `${CONTENT_ERRORS.SENSITIVE_FIELD_EDIT}: ${sensitiveAliases.join(', ')}`
84
- })
85
- }
86
-
87
- const validation = validateAndSanitizeSeedPayload(seed, body, {
88
- operation: 'update',
89
- allowNull: true,
90
- requireAtLeastOneValidField: true,
91
- enforceRequiredFields: false,
92
- idGenerator: context.get('idGenerator'),
93
- })
94
-
95
- if (validation.dangerousFields.length > 0) {
96
- return publicProblem(context, {
97
- type: 'content-dangerous-content',
98
- title: 'Unprocessable Entity',
99
- status: 422,
100
- detail: `Dangerous markup in field '${validation.dangerousFields[0]}'`
101
- })
102
- }
103
-
104
- if (validation.details.length > 0) {
105
- return publicProblem(context, {
106
- type: 'content-validation-failed',
107
- title: 'Bad Request',
108
- status: 400,
109
- detail: 'Validation failed',
110
- errors: validation.details
111
- })
112
- }
113
-
114
- const repository = context.get('repository')
115
- await repository.saveDraft(seed, id, validation.data)
116
-
117
- const displayTitle = cleanStr(validation.data[seed.displayNameAlias]) ?? id
118
- logDraftActivity(context, id, slug, displayTitle, 'draft saved')
119
-
120
- return context.json({ success: true })
121
- })
122
-
123
- // GET /:slug/:id/draft — Retrieves the pending draft
124
- draftApp.get('/:slug/:id/draft', draftGuard, async (context) => {
125
- const slug = context.req.param('slug')
126
- const id = context.req.param('id')
127
- const seed = context.get('getSeed')(slug)!
128
-
129
- const repository = context.get('repository')
130
- const draft = await repository.getDraft(seed, id)
131
-
132
- if (!draft) {
133
- return publicProblem(context, {
134
- type: 'draft-not-found',
135
- title: 'Not Found',
136
- status: 404,
137
- detail: 'No pending draft for this entry'
138
- })
139
- }
140
-
141
- return context.json({ data: applyVisibility(draft, seed) })
142
- })
143
-
144
- // POST /:slug/:id/draft/publish — Atomically promotes draft to live
145
- draftApp.post('/:slug/:id/draft/publish', draftGuard, async (context) => {
146
- const slug = context.req.param('slug')
147
- const id = context.req.param('id')
148
- const seed = context.get('getSeed')(slug)!
149
-
150
- const repository = context.get('repository')
151
- const draft = await repository.getDraft(seed, id)
152
-
153
- if (!draft) {
154
- return publicProblem(context, {
155
- type: 'draft-not-found',
156
- title: 'Not Found',
157
- status: 404,
158
- detail: 'No pending draft to publish'
159
- })
160
- }
161
-
162
- try {
163
- await repository.publishDraft(seed, id)
164
- } catch (err) {
165
- if (err instanceof RelationTargetNotFoundError) {
166
- return publicProblem(context, {
167
- type: 'relation-target-not-found',
168
- title: 'Relation Target Not Found',
169
- status: 422,
170
- detail: `Field '${err.alias}' references '${err.targetSeed}' id='${err.value}' which does not exist`,
171
- })
172
- }
173
- throw err
174
- }
175
-
176
- const displayValue = draft[seed.displayNameAlias]
177
- const displayStr = typeof displayValue === 'string' ? displayValue : id
178
- logDraftActivity(context, id, slug, displayStr, 'draft published')
179
-
180
- return context.json({ success: true })
181
- })
182
-
183
- // DELETE /:slug/:id/draft — Discards the pending draft
184
- draftApp.delete('/:slug/:id/draft', draftGuard, async (context) => {
185
- const slug = context.req.param('slug')
186
- const id = context.req.param('id')
187
- const seed = context.get('getSeed')(slug)!
188
-
189
- const repository = context.get('repository')
190
- await repository.deleteDraft(seed, id)
191
-
192
- return context.json({ success: true })
193
- })
194
-
195
- export { draftApp }
@@ -1,66 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- import { createMiddleware } from 'hono/factory'
6
- import { EntryNotFoundError } from '@beechcms/core'
7
- import { publicProblem } from '../../public/problem-details'
8
- import { CONTENT_ERRORS } from '../content/constants'
9
- import type { AppEnv } from '../../types'
10
-
11
- /**
12
- * Middleware that guards draft-related endpoints.
13
- * Responsibilities:
14
- * 1. Validates that the targeted Seed schema exists.
15
- * 2. Ensures the Seed configuration explicitly allows drafts.
16
- * 3. Confirms that the main live content entry exists in the repository.
17
- */
18
- export const draftGuard = createMiddleware<AppEnv>(async (context, next) => {
19
- const slug = context.req.param('slug')
20
- const id = context.req.param('id')
21
-
22
- if (!slug || !id) {
23
- return publicProblem(context, {
24
- type: 'content-invalid-request',
25
- title: 'Bad Request',
26
- status: 400,
27
- detail: 'Missing required route parameters',
28
- })
29
- }
30
-
31
- const seed = context.get('getSeed')(slug)
32
- if (!seed) {
33
- return publicProblem(context, {
34
- type: 'content-seed-not-found',
35
- title: 'Not Found',
36
- status: 404,
37
- detail: CONTENT_ERRORS.SEED_NOT_FOUND,
38
- })
39
- }
40
-
41
- if (!seed.allowDrafts) {
42
- return publicProblem(context, {
43
- type: 'draft-not-allowed',
44
- title: 'Method Not Allowed',
45
- status: 405,
46
- detail: 'This content type does not support pending drafts. Set allowDrafts: true on the Seed to enable.',
47
- })
48
- }
49
-
50
- const repository = context.get('repository')
51
- try {
52
- await repository.findById(seed, id)
53
- } catch (error) {
54
- if (error instanceof EntryNotFoundError) {
55
- return publicProblem(context, {
56
- type: 'content-not-found',
57
- title: 'Not Found',
58
- status: 404,
59
- detail: CONTENT_ERRORS.NOT_FOUND,
60
- })
61
- }
62
- throw error
63
- }
64
-
65
- await next()
66
- })
@@ -1,5 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- export { draftApp } from './draft.handler'
@@ -1,98 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- import { ResendEmailProvider } from './providers/resend'
6
- import { SmtpEmailProvider } from './providers/smtp'
7
- import { buildPasswordResetEmail } from './templates/password-reset'
8
- import { buildPasswordChangedEmail } from './templates/password-changed'
9
- import { buildAutomationEmail } from './templates/automation-mail'
10
- import type { EmailProvider } from './email.provider'
11
- import type {
12
- PasswordResetEmailParams,
13
- PasswordChangedEmailParams,
14
- AutomationMailParams,
15
- } from './email.types'
16
-
17
- const DEFAULT_FROM = 'Beech CMS <onboarding@resend.dev>'
18
-
19
- export interface EmailProviderEnv {
20
- /** "smtp" | "resend"; default "resend" if absent */
21
- provider?: string
22
- /** Resend API key, used when provider is "resend" */
23
- apiKey?: string
24
- /** Mailpit base URL (e.g. http://localhost:8025), used when provider is "smtp" */
25
- smtpBaseUrl?: string
26
- isDev?: boolean
27
- }
28
-
29
- // TODO: il sistema di selezione provider è attualmente hardcoded su "smtp" | "resend".
30
- // Sarebbe meglio aprirlo a provider di terze parti (Postmark, SendGrid, Brevo, SES, ...)
31
- // senza che l'utente debba toccare il codice. Opzioni da valutare:
32
- // 1. Strategia plugin: EMAIL_PROVIDER accetta un path a modulo ES (`./my-provider.ts`)
33
- // che esporta default class implementing EmailProvider — zero lock-in.
34
- // 2. Provider SMTP generico: rimuovere il coupling con Mailpit dalla denominazione
35
- // e accettare qualsiasi server SMTP via SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS
36
- // (il SmtpEmailProvider attuale usa già l'HTTP API di Mailpit, non SMTP raw —
37
- // andrebbe riscritto con nodemailer o un client SMTP standard per coprire qualsiasi server).
38
- // 3. Webhook email: EMAIL_PROVIDER=webhook + EMAIL_WEBHOOK_URL per integrazioni custom.
39
- // Riferimento: email.provider.ts definisce l'interfaccia — è già sufficientemente astratta.
40
- function createProvider(env: EmailProviderEnv): EmailProvider {
41
- if (env.provider === 'smtp') {
42
- if (!env.smtpBaseUrl) throw new Error('SMTP provider selected but SMTP_HOST is missing')
43
- return new SmtpEmailProvider({ baseUrl: env.smtpBaseUrl })
44
- }
45
- return new ResendEmailProvider(env.apiKey ?? '', env.isDev ?? false)
46
- }
47
-
48
- export async function sendPasswordResetEmail(
49
- params: PasswordResetEmailParams,
50
- ): Promise<void> {
51
- const provider = createProvider({
52
- provider: params.provider,
53
- apiKey: params.apiKey,
54
- smtpBaseUrl: params.smtpBaseUrl,
55
- isDev: params.isDev ?? false,
56
- })
57
- const { subject, html } = buildPasswordResetEmail(params.resetUrl, params.locale)
58
- await provider.send({
59
- from: params.from ?? DEFAULT_FROM,
60
- to: [params.to],
61
- subject,
62
- html,
63
- })
64
- }
65
-
66
- export async function sendPasswordChangedEmail(
67
- params: PasswordChangedEmailParams,
68
- ): Promise<void> {
69
- const provider = createProvider({
70
- provider: params.provider,
71
- apiKey: params.apiKey,
72
- smtpBaseUrl: params.smtpBaseUrl,
73
- isDev: params.isDev ?? false,
74
- })
75
- const { subject, html } = buildPasswordChangedEmail(params.locale)
76
- await provider.send({
77
- from: params.from ?? DEFAULT_FROM,
78
- to: [params.to],
79
- subject,
80
- html,
81
- })
82
- }
83
-
84
- export async function sendAutomationMail(params: AutomationMailParams): Promise<void> {
85
- const provider = createProvider({
86
- provider: params.provider,
87
- apiKey: params.apiKey ?? params.resendApiKey,
88
- smtpBaseUrl: params.smtpBaseUrl,
89
- isDev: false,
90
- })
91
- const message = buildAutomationEmail(params)
92
- await provider.send({
93
- from: params.from ?? DEFAULT_FROM,
94
- to: [message.to],
95
- subject: message.subject,
96
- html: message.html,
97
- })
98
- }
@@ -1,119 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- /**
6
- * Shared types for the Beech CMS email module.
7
- *
8
- * All types used across provider, service, and templates are defined here
9
- * so that each layer remains decoupled from the others.
10
- */
11
-
12
- // ── Locale ────────────────────────────────────────────────────────────────────
13
-
14
- /**
15
- * Supported languages for the email template system.
16
- *
17
- * To add a new language:
18
- * 1. Add the ISO code here (e.g., `'fr'`).
19
- * 2. Add the corresponding translation in the `COPY` object of every
20
- * file in `templates/`. TypeScript will flag missing keys.
21
- */
22
- export const SUPPORTED_EMAIL_LOCALES = ['en', 'it'] as const
23
- export type EmailLocale = (typeof SUPPORTED_EMAIL_LOCALES)[number]
24
-
25
- /**
26
- * Resolves an unverified locale string (e.g., from a request body)
27
- * to a supported `EmailLocale` value. Any unknown value
28
- * safely falls back to `'en'`.
29
- *
30
- * @param raw - Raw value from the client (can be anything).
31
- * @returns A valid `EmailLocale`, always.
32
- */
33
- export function resolveEmailLocale(raw: unknown): EmailLocale {
34
- if (
35
- typeof raw === 'string' &&
36
- (SUPPORTED_EMAIL_LOCALES as readonly string[]).includes(raw)
37
- ) {
38
- return raw as EmailLocale
39
- }
40
- return 'en'
41
- }
42
-
43
- // ── Outbound message ──────────────────────────────────────────────────────────
44
-
45
- /**
46
- * The resolved email message that the provider receives and sends.
47
- * It is constructed by the service by combining the call parameters
48
- * with the template builder output.
49
- */
50
- export interface OutboundEmail {
51
- /** Sender address in RFC 5321 format (e.g., "Beech CMS <noreply@beechcms.dev>"). */
52
- from: string
53
- /** List of recipient addresses. Must contain at least one element. */
54
- to: string[]
55
- subject: string
56
- /** Complete HTML body. Must be a valid HTML document (see `templates/shell.ts`). */
57
- html: string
58
- }
59
-
60
- // ── Service function parameters ───────────────────────────────────────────────
61
-
62
- /**
63
- * Shared parameters for every email sending function in `email.service.ts`.
64
- * Specific functions extend this type with the additional fields
65
- * required for their respective templates.
66
- */
67
- export interface BaseEmailParams {
68
- /** Main recipient address. */
69
- to: string
70
- /** Email body language. Use `resolveEmailLocale()` before passing it here. */
71
- locale: EmailLocale
72
- /**
73
- * Resend API key (or the active provider's key). Must be non-empty —
74
- * the caller is responsible for validating it before invoking the service.
75
- */
76
- apiKey: string
77
- /**
78
- * Sender address in RFC 5321 format.
79
- * Default: "Beech CMS <onboarding@resend.dev>" (Resend test sender).
80
- * In production, set a verified address via the
81
- * `EMAIL_FROM` environment variable.
82
- */
83
- from?: string
84
- /**
85
- * When `true`, provider errors are logged to the console.
86
- * Set to `false` in production to avoid exposing internal details.
87
- */
88
- isDev?: boolean
89
- }
90
-
91
- /** Parameters for the password reset email — adds the reset URL. */
92
- export interface PasswordResetEmailParams extends BaseEmailParams {
93
- /**
94
- * Complete URL that the user clicks to set the new password.
95
- * Contains the token in plain text as a query param `?token=<uuid>`.
96
- * Constructed by the caller as `${APP_URL}/reset-password?token=${token}`.
97
- */
98
- resetUrl: string
99
- provider?: 'smtp' | 'resend'
100
- smtpBaseUrl?: string
101
- }
102
-
103
- /** Parameters for the "password changed" notification. No additional fields. */
104
- export interface PasswordChangedEmailParams extends BaseEmailParams {
105
- provider?: 'smtp' | 'resend'
106
- smtpBaseUrl?: string
107
- }
108
-
109
- export interface AutomationMailParams {
110
- to: string
111
- subject: string
112
- /** Plain text or HTML — passed verbatim to provider. */
113
- body: string
114
- apiKey?: string
115
- resendApiKey?: string
116
- from?: string
117
- provider?: 'smtp' | 'resend'
118
- smtpBaseUrl?: string
119
- }
@@ -1,67 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- /// <reference types="@cloudflare/workers-types" />
6
- import type { EmailProvider } from '../email.provider'
7
- import type { OutboundEmail } from '../email.types'
8
-
9
- /** Resend REST endpoint for sending emails. */
10
- const RESEND_API_URL = 'https://api.resend.com/emails'
11
-
12
- /**
13
- * Resend implementation of EmailProvider.
14
- *
15
- * This is the ONLY file in the email module that knows about Resend.
16
- * Every other file is completely unaware of which provider is active.
17
- *
18
- * ─── HOW TO REPLACE THIS PROVIDER ──────────────────────────────────────────
19
- * 1. Create a new file in `providers/` (e.g., `providers/sendgrid.ts`).
20
- * 2. Export a class that implements `EmailProvider` (a single method: `send`).
21
- * 3. In `email.service.ts`, replace `new ResendEmailProvider(...)` with
22
- * your new class in the `createProvider()` function.
23
- * 4. Update the environment variables in `types.ts` and `wrangler.jsonc`.
24
- * 5. No other file in the project needs to be modified.
25
- *
26
- * Resend API Documentation: https://resend.com/docs/api-reference/emails/send-email
27
- * ─────────────────────────────────────────────────────────────────────────────
28
- */
29
- export class ResendEmailProvider implements EmailProvider {
30
- private readonly apiKey: string
31
-
32
- /** When `true`, errors are logged to the console (development only). */
33
- private readonly isDev: boolean
34
-
35
- constructor(apiKey: string, isDev = false) {
36
- this.apiKey = apiKey
37
- this.isDev = isDev
38
- }
39
-
40
- /**
41
- * Sends the email via the Resend REST API (`POST /emails`).
42
- *
43
- * Throws an exception if Resend responds with a non-2xx status, so that
44
- * the caller (`email.service.ts`) can decide whether to propagate the error
45
- * or handle it silently (fire-and-forget).
46
- *
47
- * The response body is read for logging only in the development environment,
48
- * to avoid unnecessarily consuming the body stream in production.
49
- */
50
- async send(email: OutboundEmail): Promise<void> {
51
- const response = await fetch(RESEND_API_URL, {
52
- method: 'POST',
53
- headers: {
54
- Authorization: `Bearer ${this.apiKey}`,
55
- 'Content-Type': 'application/json',
56
- },
57
- body: JSON.stringify(email),
58
- })
59
-
60
- if (!response.ok) {
61
- const detail = this.isDev
62
- ? await response.text()
63
- : `HTTP ${response.status}`
64
- throw new Error(`[ResendEmailProvider] send failed — ${detail}`)
65
- }
66
- }
67
- }
@@ -1,55 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- /// <reference types="@cloudflare/workers-types" />
6
- import type { EmailProvider } from '../email.provider'
7
- import type { OutboundEmail } from '../email.types'
8
-
9
- export interface SmtpProviderConfig {
10
- /** Base URL of the Mailpit HTTP API, e.g. http://localhost:8025 */
11
- baseUrl: string
12
- }
13
-
14
- interface MailpitAddress { Name?: string; Email: string }
15
- interface MailpitSendPayload {
16
- From: MailpitAddress
17
- To: MailpitAddress[]
18
- Subject: string
19
- HTML?: string
20
- Text?: string
21
- }
22
-
23
- function parseAddress(raw: string): MailpitAddress {
24
- const match = raw.match(/^\s*(.+?)\s*<([^>]+)>\s*$/)
25
- if (match) return { Name: match[1], Email: match[2] }
26
- return { Email: raw.trim() }
27
- }
28
-
29
- export class SmtpEmailProvider implements EmailProvider {
30
- private readonly endpoint: string
31
-
32
- constructor(config: SmtpProviderConfig) {
33
- this.endpoint = `${config.baseUrl.replace(/\/$/, '')}/api/v1/send`
34
- }
35
-
36
- async send(email: OutboundEmail): Promise<void> {
37
- const payload: MailpitSendPayload = {
38
- From: parseAddress(email.from),
39
- To: email.to.map(parseAddress),
40
- Subject: email.subject,
41
- HTML: email.html,
42
- }
43
-
44
- const response = await fetch(this.endpoint, {
45
- method: 'POST',
46
- headers: { 'Content-Type': 'application/json' },
47
- body: JSON.stringify(payload),
48
- })
49
-
50
- if (!response.ok) {
51
- const body = await response.text().catch(() => `HTTP ${response.status}`)
52
- throw new Error(`[SmtpEmailProvider] send failed — ${body}`)
53
- }
54
- }
55
- }
@@ -1,19 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- import type { AutomationMailParams } from '../email.types'
6
-
7
- /** Identity builder: automation payloads are already user-authored. */
8
- export function buildAutomationEmail(params: AutomationMailParams) {
9
- return {
10
- to: params.to,
11
- subject: params.subject,
12
- html: params.body,
13
- text: stripHtml(params.body),
14
- }
15
- }
16
-
17
- function stripHtml(input: string): string {
18
- return input.replace(/<[^>]+>/g, '').trim()
19
- }
@@ -1,63 +0,0 @@
1
- // SPDX-License-Identifier: BUSL-1.1
2
- // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
- // See LICENSE in the repository root for license terms.
4
-
5
- import type { EmailLocale } from '../email.types'
6
- import { buildEmailShell } from './shell'
7
-
8
- /**
9
- * Localized texts for the "password changed" security notification.
10
- *
11
- * ─── ADDING A NEW LANGUAGE ──────────────────────────────────────────────────
12
- * See instructions in `templates/password-reset.ts`.
13
- * ─────────────────────────────────────────────────────────────────────────────
14
- */
15
- const COPY: Record<EmailLocale, {
16
- subject: string
17
- title: string
18
- body: string
19
- warning: string
20
- footer: string
21
- }> = {
22
- en: {
23
- subject: 'Your Beech CMS password has been changed',
24
- title: 'Your password has been changed',
25
- body: 'Your Beech CMS account password was successfully changed. If you made this change, no action is needed.',
26
- warning:
27
- 'If you did not make this change, your account may be compromised. Contact your administrator immediately.',
28
- footer: 'This is an automated security notification. Do not reply to this email.',
29
- },
30
- it: {
31
- subject: 'La tua password Beech CMS è stata modificata',
32
- title: 'La tua password è stata modificata',
33
- body: 'La password del tuo account Beech CMS è stata modificata con successo. Se hai effettuato tu questa modifica, non devi fare nulla.',
34
- warning:
35
- 'Se non hai effettuato tu questa modifica, il tuo account potrebbe essere compromesso. Contatta immediatamente il tuo amministratore.',
36
- footer: 'Questa è una notifica di sicurezza automatica. Non rispondere a questa email.',
37
- },
38
- }
39
-
40
- /**
41
- * Builds the "password changed" notification email.
42
- *
43
- * This email does not have a CTA button — it is a pure security notification.
44
- * The `warning` block (red text) warns the user to take action if they
45
- * were not the one who changed the password.
46
- *
47
- * @param locale - Language for the email subject and body.
48
- * @returns Object with `subject` (string) and `html` (complete HTML document).
49
- */
50
- export function buildPasswordChangedEmail(
51
- locale: EmailLocale,
52
- ): { subject: string; html: string } {
53
- const c = COPY[locale]
54
- return {
55
- subject: c.subject,
56
- html: buildEmailShell(locale, {
57
- title: c.title,
58
- body: c.body,
59
- warning: c.warning,
60
- footer: c.footer,
61
- }),
62
- }
63
- }