@beechcms/api 0.6.0-preview.2 → 0.6.0-preview.4

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 (388) 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-BwlCt-IA.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-BcVN-DNy.js +642 -0
  11. package/assets/dashboard/assets/index-Cf1yRCqG.css +1 -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-BMWpjFzf.js +1 -0
  20. package/assets/dashboard/assets/timeseries-chart-recharts-8_GwAFR0.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 +45 -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} +19 -24
  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} +3 -16
  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 +7 -0
  98. package/dist/index.js +9732 -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/queue.middleware.d.ts +11 -0
  103. package/dist/middleware/rate-limit.middleware.d.ts +9 -0
  104. package/dist/middleware/repository.middleware.d.ts +34 -0
  105. package/dist/middleware/seed-registry.middleware.d.ts +10 -0
  106. package/dist/middleware/storage.middleware.d.ts +7 -0
  107. package/dist/middleware.d.ts +11 -0
  108. package/dist/public/access-policy.d.ts +12 -0
  109. package/dist/public/api-key-middleware.d.ts +6 -0
  110. package/dist/public/cache-utils.d.ts +10 -0
  111. package/dist/public/entry-projection.d.ts +2 -0
  112. package/dist/public/idempotency.d.ts +9 -0
  113. package/dist/public/index.d.ts +11 -0
  114. package/dist/public/problem-details.d.ts +31 -0
  115. package/dist/public/public-add.d.ts +3 -0
  116. package/dist/public/public-edit.d.ts +5 -0
  117. package/dist/public/public-errors.d.ts +13 -0
  118. package/dist/public/public-read.d.ts +3 -0
  119. package/dist/public/public-routes.d.ts +3 -0
  120. package/dist/public/query-builder.d.ts +28 -0
  121. package/dist/public/rate-limit-middleware.d.ts +3 -0
  122. package/dist/public/read-list.d.ts +26 -0
  123. package/dist/public/read-single.d.ts +22 -0
  124. package/dist/public/response-builder.d.ts +22 -0
  125. package/dist/public/sanitize.d.ts +23 -0
  126. package/{src/public/slug-utils.ts → dist/public/slug-utils.d.ts} +3 -10
  127. package/dist/rate-limit/cloudflare-rate-limiter.d.ts +6 -0
  128. package/dist/rate-limit/in-memory-rate-limiter.d.ts +7 -0
  129. package/dist/rate-limit/no-op-rate-limiter.d.ts +4 -0
  130. package/dist/search-utils.d.ts +54 -0
  131. package/dist/search.d.ts +6 -0
  132. package/dist/shared/apply-policies.d.ts +10 -0
  133. package/dist/shared/automations.repository.d1.d.ts +12 -0
  134. package/dist/shared/background-notification-service.d.ts +18 -0
  135. package/dist/shared/base.repository.d1.d.ts +18 -0
  136. package/dist/shared/cloudflare-queue-service.d.ts +11 -0
  137. package/dist/shared/content-utils.d.ts +21 -0
  138. package/dist/shared/content.repository.d1.d.ts +68 -0
  139. package/dist/shared/d1-activity-log.repository.d.ts +13 -0
  140. package/dist/shared/d1-activity-logger.d.ts +20 -0
  141. package/dist/shared/d1-analytics.repository.d.ts +20 -0
  142. package/dist/shared/d1-content-scan.repository.d.ts +7 -0
  143. package/dist/shared/d1-notification.repository.d.ts +17 -0
  144. package/dist/shared/d1-password-reset-token.repository.d.ts +10 -0
  145. package/dist/shared/d1-search.repository.d.ts +14 -0
  146. package/dist/shared/d1-session.repository.d.ts +12 -0
  147. package/dist/shared/d1-setup-checklist.repository.d.ts +12 -0
  148. package/dist/shared/d1-user.repository.d.ts +18 -0
  149. package/dist/shared/d1-widget.repository.d.ts +31 -0
  150. package/dist/shared/dashboard-layout.repository.d1.d.ts +9 -0
  151. package/dist/shared/demo-data-sql.d.ts +1 -0
  152. package/dist/shared/demo-data.repository.d1.d.ts +6 -0
  153. package/dist/shared/execution-context-scheduler.d.ts +6 -0
  154. package/dist/shared/fixed-clock.d.ts +13 -0
  155. package/dist/shared/fts-sync.d.ts +1 -0
  156. package/dist/shared/idempotency.repository.d1.d.ts +16 -0
  157. package/dist/shared/in-memory-activity-logger.d.ts +11 -0
  158. package/dist/shared/in-memory-notification-service.d.ts +11 -0
  159. package/dist/shared/in-memory-queue-service.d.ts +16 -0
  160. package/dist/shared/in-memory-seed.repository.d.ts +18 -0
  161. package/dist/shared/media.repository.d1.d.ts +35 -0
  162. package/dist/shared/qstash-notification-service.d.ts +18 -0
  163. package/dist/shared/query-utils.d.ts +36 -0
  164. package/dist/shared/queue-consumer.d.ts +9 -0
  165. package/dist/shared/request-utils.d.ts +13 -0
  166. package/dist/shared/schema-mutator.d1.d.ts +12 -0
  167. package/dist/shared/seed-layout.repository.d1.d.ts +9 -0
  168. package/dist/shared/seed-registry-cache.d.ts +12 -0
  169. package/dist/shared/seed.repository.d1.d.ts +13 -0
  170. package/dist/shared/sequential-id-generator.d.ts +13 -0
  171. package/dist/shared/site-settings.repository.d1.d.ts +7 -0
  172. package/dist/shared/storage/factory.d.ts +8 -0
  173. package/dist/shared/storage/s3-bucket.d.ts +43 -0
  174. package/dist/shared/storage-utils.d.ts +7 -0
  175. package/dist/shared/system-stats.repository.d1.d.ts +25 -0
  176. package/dist/types.d.ts +87 -0
  177. package/dist/upload.d.ts +16 -0
  178. package/dist/widget.d.ts +7 -0
  179. package/migrations/0000_v040_base.sql +265 -265
  180. package/migrations/0029_automations.sql +14 -14
  181. package/migrations/0030_test_seeds.sql +125 -125
  182. package/package.json +28 -18
  183. package/assets/dashboard/assets/chart-BrJFdsGZ.js +0 -39
  184. package/assets/dashboard/assets/index-CIaoMxuB.css +0 -1
  185. package/assets/dashboard/assets/index-wTKgygsg.js +0 -636
  186. package/assets/dashboard/assets/pie-chart-recharts-BEaE1FOE.js +0 -1
  187. package/assets/dashboard/assets/timeseries-chart-recharts-DmWM6imF.js +0 -1
  188. package/src/auth/__fixtures__/in-memory-hash-provider.ts +0 -17
  189. package/src/auth/__fixtures__/static-token-service.ts +0 -22
  190. package/src/auth/bcrypt-hash-provider.ts +0 -24
  191. package/src/auth/constants.ts +0 -14
  192. package/src/auth/generate-refresh-token.test.ts +0 -23
  193. package/src/auth/hash-provider.test.ts +0 -55
  194. package/src/auth/jose-token-service.ts +0 -62
  195. package/src/auth/jwt-claims-passthrough.test.ts +0 -87
  196. package/src/auth/login.test.ts +0 -100
  197. package/src/auth/login.ts +0 -78
  198. package/src/auth/refresh.ts +0 -11
  199. package/src/auth/token-service.test.ts +0 -90
  200. package/src/factory.ts +0 -370
  201. package/src/features/automations/__tests__/action-executors.test.ts +0 -255
  202. package/src/features/automations/__tests__/automation-runner.test.ts +0 -196
  203. package/src/features/automations/__tests__/automation-runner.utils.test.ts +0 -60
  204. package/src/features/automations/__tests__/automations.handler.test.ts +0 -264
  205. package/src/features/automations/__tests__/automations.repository.test.ts +0 -163
  206. package/src/features/automations/__tests__/automations.schema.test.ts +0 -224
  207. package/src/features/automations/__tests__/context-resolver.test.ts +0 -126
  208. package/src/features/automations/__tests__/cron-runner.test.ts +0 -267
  209. package/src/features/automations/__tests__/cron-runner.utils.test.ts +0 -144
  210. package/src/features/automations/__tests__/set-variable.executor.test.ts +0 -383
  211. package/src/features/automations/__tests__/template-grammar.test.ts +0 -308
  212. package/src/features/automations/__tests__/webhook.executor.test.ts +0 -142
  213. package/src/features/automations/__tests__/when-evaluator.test.ts +0 -274
  214. package/src/features/automations/__tests__/when-pushdown.test.ts +0 -281
  215. package/src/features/automations/action-executors/create-entry.executor.ts +0 -27
  216. package/src/features/automations/action-executors/edit-field.executor.ts +0 -26
  217. package/src/features/automations/action-executors/index.ts +0 -37
  218. package/src/features/automations/action-executors/send-mail.executor.ts +0 -53
  219. package/src/features/automations/action-executors/set-variable.executor.ts +0 -159
  220. package/src/features/automations/action-executors/webhook.executor.ts +0 -67
  221. package/src/features/automations/automation-runner.ts +0 -85
  222. package/src/features/automations/automation-runner.utils.ts +0 -47
  223. package/src/features/automations/automations.handler.ts +0 -197
  224. package/src/features/automations/automations.schema.ts +0 -177
  225. package/src/features/automations/context-resolver.ts +0 -152
  226. package/src/features/automations/cron-runner.ts +0 -140
  227. package/src/features/automations/cron-runner.utils.ts +0 -44
  228. package/src/features/automations/filter-translation.ts +0 -46
  229. package/src/features/automations/index.ts +0 -16
  230. package/src/features/automations/template-grammar.ts +0 -245
  231. package/src/features/automations/var-access-resolver.ts +0 -140
  232. package/src/features/automations/when-evaluator.ts +0 -87
  233. package/src/features/automations/when-pushdown.ts +0 -57
  234. package/src/features/backrefs/__tests__/backrefs.handler.test.ts +0 -359
  235. package/src/features/backrefs/backrefs.handler.ts +0 -168
  236. package/src/features/backrefs/d1-backref.repository.ts +0 -84
  237. package/src/features/backrefs/index.ts +0 -5
  238. package/src/features/content/constants.ts +0 -16
  239. package/src/features/content/handlers/bulk.handler.ts +0 -185
  240. package/src/features/content/handlers/create.ts +0 -129
  241. package/src/features/content/handlers/delete.ts +0 -62
  242. package/src/features/content/handlers/facets.ts +0 -49
  243. package/src/features/content/handlers/get.ts +0 -120
  244. package/src/features/content/handlers/helpers.test.ts +0 -180
  245. package/src/features/content/handlers/helpers.ts +0 -93
  246. package/src/features/content/handlers/list.ts +0 -174
  247. package/src/features/content/handlers/update.ts +0 -174
  248. package/src/features/content/index.ts +0 -26
  249. package/src/features/dashboard-layout/__tests__/dashboard-layout.handler.test.ts +0 -388
  250. package/src/features/dashboard-layout/dashboard-layout.handler.ts +0 -206
  251. package/src/features/dashboard-layout/index.ts +0 -5
  252. package/src/features/draft/draft.handler.ts +0 -195
  253. package/src/features/draft/draft.middleware.ts +0 -66
  254. package/src/features/draft/index.ts +0 -5
  255. package/src/features/email/email.service.ts +0 -98
  256. package/src/features/email/email.types.ts +0 -119
  257. package/src/features/email/providers/resend.ts +0 -67
  258. package/src/features/email/providers/smtp.ts +0 -55
  259. package/src/features/email/templates/automation-mail.ts +0 -19
  260. package/src/features/email/templates/password-changed.ts +0 -63
  261. package/src/features/email/templates/password-reset.ts +0 -68
  262. package/src/features/email/templates/shell.ts +0 -96
  263. package/src/features/notifications/index.ts +0 -5
  264. package/src/features/notifications/notifications.handler.ts +0 -105
  265. package/src/features/password-reset/index.ts +0 -19
  266. package/src/features/password-reset/request.ts +0 -92
  267. package/src/features/password-reset/reset.ts +0 -102
  268. package/src/features/rotate-field/index.ts +0 -5
  269. package/src/features/rotate-field/rotate-field.handler.ts +0 -132
  270. package/src/features/rotate-field/rotate-field.schema.ts +0 -17
  271. package/src/features/schema/schema.handler.ts +0 -131
  272. package/src/features/seeds/index.ts +0 -5
  273. package/src/features/seeds/seeds.handler.test.ts +0 -1199
  274. package/src/features/seeds/seeds.handler.ts +0 -558
  275. package/src/features/settings/__tests__/settings.handler.test.ts +0 -555
  276. package/src/features/settings/settings.handler.ts +0 -392
  277. package/src/features/setup/index.ts +0 -288
  278. package/src/features/stats/index.ts +0 -5
  279. package/src/features/stats/stats.handler.ts +0 -420
  280. package/src/features/webhooks/index.ts +0 -63
  281. package/src/index.ts +0 -65
  282. package/src/media-utils.ts +0 -82
  283. package/src/middleware/auth-providers.middleware.test.ts +0 -85
  284. package/src/middleware/auth-providers.middleware.ts +0 -45
  285. package/src/middleware/observability.middleware.test.ts +0 -93
  286. package/src/middleware/observability.middleware.ts +0 -70
  287. package/src/middleware/rate-limit.middleware.ts +0 -45
  288. package/src/middleware/repository.middleware.ts +0 -117
  289. package/src/middleware/seed-registry.middleware.test.ts +0 -97
  290. package/src/middleware/seed-registry.middleware.ts +0 -21
  291. package/src/middleware/storage.middleware.ts +0 -25
  292. package/src/middleware.ts +0 -45
  293. package/src/public/access-policy.ts +0 -27
  294. package/src/public/api-key-middleware.ts +0 -57
  295. package/src/public/cache-utils.ts +0 -38
  296. package/src/public/entry-projection.ts +0 -46
  297. package/src/public/idempotency.ts +0 -23
  298. package/src/public/index.ts +0 -16
  299. package/src/public/problem-details.ts +0 -124
  300. package/src/public/public-add.ts +0 -114
  301. package/src/public/public-edit.ts +0 -163
  302. package/src/public/public-errors.ts +0 -19
  303. package/src/public/public-read.ts +0 -63
  304. package/src/public/public-routes.ts +0 -88
  305. package/src/public/query-builder.test.ts +0 -224
  306. package/src/public/query-builder.ts +0 -156
  307. package/src/public/rate-limit-middleware.ts +0 -34
  308. package/src/public/read-list.ts +0 -54
  309. package/src/public/read-single.ts +0 -48
  310. package/src/public/response-builder.ts +0 -30
  311. package/src/public/sanitize.ts +0 -69
  312. package/src/rate-limit/cloudflare-rate-limiter.test.ts +0 -30
  313. package/src/rate-limit/cloudflare-rate-limiter.ts +0 -15
  314. package/src/rate-limit/in-memory-rate-limiter.test.ts +0 -37
  315. package/src/rate-limit/in-memory-rate-limiter.ts +0 -17
  316. package/src/rate-limit/no-op-rate-limiter.test.ts +0 -22
  317. package/src/rate-limit/no-op-rate-limiter.ts +0 -11
  318. package/src/search-utils.test.ts +0 -211
  319. package/src/search-utils.ts +0 -213
  320. package/src/search.ts +0 -65
  321. package/src/shared/apply-policies.test.ts +0 -81
  322. package/src/shared/apply-policies.ts +0 -67
  323. package/src/shared/automations.repository.d1.ts +0 -150
  324. package/src/shared/background-notification-service.test.ts +0 -62
  325. package/src/shared/background-notification-service.ts +0 -52
  326. package/src/shared/base.repository.d1.ts +0 -32
  327. package/src/shared/content-utils.test.ts +0 -165
  328. package/src/shared/content-utils.ts +0 -86
  329. package/src/shared/content.repository.d1.test.ts +0 -507
  330. package/src/shared/content.repository.d1.ts +0 -851
  331. package/src/shared/d1-activity-log.repository.test.ts +0 -140
  332. package/src/shared/d1-activity-log.repository.ts +0 -105
  333. package/src/shared/d1-activity-logger.test.ts +0 -86
  334. package/src/shared/d1-activity-logger.ts +0 -67
  335. package/src/shared/d1-analytics.repository.test.ts +0 -78
  336. package/src/shared/d1-analytics.repository.ts +0 -85
  337. package/src/shared/d1-content-scan.repository.test.ts +0 -80
  338. package/src/shared/d1-content-scan.repository.ts +0 -37
  339. package/src/shared/d1-notification.repository.test.ts +0 -128
  340. package/src/shared/d1-notification.repository.ts +0 -118
  341. package/src/shared/d1-password-reset-token.repository.test.ts +0 -81
  342. package/src/shared/d1-password-reset-token.repository.ts +0 -56
  343. package/src/shared/d1-search.repository.test.ts +0 -87
  344. package/src/shared/d1-search.repository.ts +0 -88
  345. package/src/shared/d1-session.repository.test.ts +0 -125
  346. package/src/shared/d1-session.repository.ts +0 -102
  347. package/src/shared/d1-setup-checklist.repository.ts +0 -36
  348. package/src/shared/d1-user.repository.test.ts +0 -151
  349. package/src/shared/d1-user.repository.ts +0 -119
  350. package/src/shared/d1-widget.repository.test.ts +0 -267
  351. package/src/shared/d1-widget.repository.ts +0 -385
  352. package/src/shared/dashboard-layout.repository.d1.test.ts +0 -135
  353. package/src/shared/dashboard-layout.repository.d1.ts +0 -58
  354. package/src/shared/demo-data-sql.ts +0 -216
  355. package/src/shared/demo-data.repository.d1.ts +0 -20
  356. package/src/shared/execution-context-scheduler.ts +0 -13
  357. package/src/shared/fixed-clock.ts +0 -25
  358. package/src/shared/fts-sync.ts +0 -8
  359. package/src/shared/idempotency.repository.d1.test.ts +0 -83
  360. package/src/shared/idempotency.repository.d1.ts +0 -60
  361. package/src/shared/in-memory-activity-logger.ts +0 -19
  362. package/src/shared/in-memory-notification-service.ts +0 -19
  363. package/src/shared/in-memory-seed.repository.ts +0 -58
  364. package/src/shared/media.repository.d1.test.ts +0 -107
  365. package/src/shared/media.repository.d1.ts +0 -68
  366. package/src/shared/qstash-notification-service.test.ts +0 -67
  367. package/src/shared/qstash-notification-service.ts +0 -55
  368. package/src/shared/query-utils.ts +0 -141
  369. package/src/shared/request-utils.ts +0 -26
  370. package/src/shared/schema-mutator.d1.test.ts +0 -142
  371. package/src/shared/schema-mutator.d1.ts +0 -64
  372. package/src/shared/seed-layout.repository.d1.test.ts +0 -114
  373. package/src/shared/seed-layout.repository.d1.ts +0 -62
  374. package/src/shared/seed-registry-cache.test.ts +0 -68
  375. package/src/shared/seed-registry-cache.ts +0 -49
  376. package/src/shared/seed.repository.d1.test.ts +0 -143
  377. package/src/shared/seed.repository.d1.ts +0 -98
  378. package/src/shared/sequential-id-generator.ts +0 -33
  379. package/src/shared/site-settings.repository.d1.ts +0 -53
  380. package/src/shared/storage/factory.ts +0 -41
  381. package/src/shared/storage/s3-bucket.ts +0 -195
  382. package/src/shared/storage-utils.ts +0 -40
  383. package/src/shared/system-stats.repository.d1.test.ts +0 -58
  384. package/src/shared/system-stats.repository.d1.ts +0 -48
  385. package/src/types.ts +0 -90
  386. package/src/upload.ts +0 -198
  387. package/src/widget.test.ts +0 -85
  388. package/src/widget.ts +0 -251
@@ -1,555 +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 { describe, it, expect, vi } from 'vitest'
6
- import { Hono } from 'hono'
7
- import { settingsApp } from '../settings.handler'
8
-
9
- // ---------------------------------------------------------------------------
10
- // Helpers and Mocks
11
- // ---------------------------------------------------------------------------
12
-
13
- function buildApp(mocks: any = {}) {
14
- const app = new Hono()
15
- app.use('*', async (c, next) => {
16
- c.set('siteSettingsRepository', mocks.siteSettingsRepository ?? {
17
- getAll: vi.fn().mockResolvedValue({
18
- siteTitle: 'Beech CMS',
19
- defaultLanguage: 'en',
20
- timezone: 'Europe/Rome',
21
- currency: 'EUR',
22
- companyName: 'Flavio Corp',
23
- companyWebsite: 'https://flavio.corp',
24
- companyAbbreviation: 'FC',
25
- }),
26
- setMany: vi.fn().mockResolvedValue(undefined),
27
- })
28
-
29
- c.set('userRepository', mocks.userRepository ?? {
30
- findById: vi.fn().mockResolvedValue({
31
- id: 'u1',
32
- email: 'test@beechcms.com',
33
- name: 'Test',
34
- surname: 'User',
35
- passwordHash: 'hashed-pwd',
36
- avatarUrl: null,
37
- notificationPreferences: JSON.stringify({
38
- contentCreate: true,
39
- contentUpdate: false,
40
- contentDelete: true,
41
- mediaUpload: true,
42
- }),
43
- }),
44
- emailBelongsToAnotherUser: vi.fn().mockResolvedValue(false),
45
- updateProfile: vi.fn().mockResolvedValue(undefined),
46
- updatePasswordHash: vi.fn().mockResolvedValue(undefined),
47
- updateAvatarUrl: vi.fn().mockResolvedValue(undefined),
48
- updateNotificationPreferences: vi.fn().mockResolvedValue(undefined),
49
- })
50
-
51
- c.set('sessionRepository', mocks.sessionRepository ?? {
52
- listActiveForUser: vi.fn().mockResolvedValue([
53
- { id: 'sess-1', userAgent: 'Mozilla/5.0', expiresAt: 2000000000 },
54
- ]),
55
- revokeById: vi.fn().mockResolvedValue(true),
56
- })
57
-
58
- c.set('activityLogRepository', mocks.activityLogRepository ?? {
59
- list: vi.fn().mockResolvedValue([
60
- {
61
- id: 'log-1',
62
- action: 'create',
63
- entityType: 'post',
64
- entitySlug: 'first-post',
65
- details: { ip: '127.0.0.1' },
66
- createdAt: 1700000000,
67
- },
68
- ]),
69
- })
70
-
71
- c.set('mediaRepository', mocks.mediaRepository ?? {
72
- count: vi.fn().mockResolvedValue(5),
73
- list: vi.fn().mockResolvedValue({
74
- items: [
75
- { key: 'media/img1.png', size: 1024 },
76
- { key: 'media/img2.png', size: 2048 },
77
- ],
78
- }),
79
- })
80
-
81
- c.set('systemStatsRepository', mocks.systemStatsRepository ?? {
82
- getStorageUsage: vi.fn().mockResolvedValue(3072),
83
- })
84
-
85
- c.set('seedRegistry', mocks.seedRegistry ?? {
86
- all: vi.fn().mockReturnValue([{ slug: 'posts' }]),
87
- })
88
-
89
- c.set('contentScanRepository', mocks.contentScanRepository ?? {
90
- getReferencedMediaKeys: vi.fn().mockResolvedValue(new Set(['media/img1.png'])),
91
- })
92
-
93
- c.set('hashProvider', mocks.hashProvider ?? {
94
- verify: vi.fn().mockResolvedValue(true),
95
- hash: vi.fn().mockResolvedValue('new-hashed-pwd'),
96
- })
97
-
98
- c.set('jwtPayload', mocks.jwtPayload ?? { sub: 'u1' })
99
-
100
- c.env = mocks.env ?? {
101
- DATE_FORMAT: 'YYYY-MM-DD',
102
- EMAIL_PROVIDER: 'smtp',
103
- }
104
-
105
- await next()
106
- })
107
-
108
- app.route('/', settingsApp)
109
- return app
110
- }
111
-
112
- // ---------------------------------------------------------------------------
113
- // Tests
114
- // ---------------------------------------------------------------------------
115
-
116
- describe('Settings Handler', () => {
117
- describe('GET /', () => {
118
- it('returns site settings configuration', async () => {
119
- const app = buildApp()
120
- const res = await app.request('/')
121
- expect(res.status).toBe(200)
122
- const body = await res.json() as any
123
- expect(body.siteTitle).toBe('Beech CMS')
124
- expect(body.company.name).toBe('Flavio Corp')
125
- expect(body.dateFormat).toBe('YYYY-MM-DD')
126
- expect(body.features.email).toBe(true)
127
- })
128
- })
129
-
130
- describe('PUT /', () => {
131
- it('returns 400 for invalid JSON', async () => {
132
- const app = buildApp()
133
- const res = await app.request('/', {
134
- method: 'PUT',
135
- headers: { 'Content-Type': 'application/json' },
136
- body: 'not-json',
137
- })
138
- expect(res.status).toBe(400)
139
- const body = await res.json() as any
140
- expect(body.error).toBe('Invalid JSON body')
141
- })
142
-
143
- it('returns 400 for invalid default language', async () => {
144
- const app = buildApp()
145
- const res = await app.request('/', {
146
- method: 'PUT',
147
- headers: { 'Content-Type': 'application/json' },
148
- body: JSON.stringify({ defaultLanguage: 'fr' }),
149
- })
150
- expect(res.status).toBe(400)
151
- const body = await res.json() as any
152
- expect(body.detail).toContain('Invalid default language')
153
- })
154
-
155
- it('returns 400 for invalid company website URL', async () => {
156
- const app = buildApp()
157
- const res = await app.request('/', {
158
- method: 'PUT',
159
- headers: { 'Content-Type': 'application/json' },
160
- body: JSON.stringify({ company: { website: 'not-a-valid-url' } }),
161
- })
162
- expect(res.status).toBe(400)
163
- const body = await res.json() as any
164
- expect(body.detail).toContain('Invalid company website URL')
165
- })
166
-
167
- it('updates site settings and syncs company name to siteTitle if siteTitle is omitted', async () => {
168
- const setManySpy = vi.fn().mockResolvedValue(undefined)
169
- const app = buildApp({
170
- siteSettingsRepository: {
171
- getAll: vi.fn(),
172
- setMany: setManySpy,
173
- },
174
- })
175
-
176
- const res = await app.request('/', {
177
- method: 'PUT',
178
- headers: { 'Content-Type': 'application/json' },
179
- body: JSON.stringify({
180
- defaultLanguage: 'it',
181
- company: {
182
- name: 'New Corp',
183
- website: 'https://newcorp.com',
184
- abbreviation: 'NC',
185
- },
186
- }),
187
- })
188
-
189
- expect(res.status).toBe(200)
190
- expect(setManySpy).toHaveBeenCalledWith({
191
- defaultLanguage: 'it',
192
- companyName: 'New Corp',
193
- companyWebsite: 'https://newcorp.com',
194
- companyAbbreviation: 'NC',
195
- siteTitle: 'New Corp',
196
- })
197
- })
198
-
199
- it('allows resetting company fields by passing null', async () => {
200
- const setManySpy = vi.fn().mockResolvedValue(undefined)
201
- const app = buildApp({
202
- siteSettingsRepository: {
203
- getAll: vi.fn(),
204
- setMany: setManySpy,
205
- },
206
- })
207
-
208
- const res = await app.request('/', {
209
- method: 'PUT',
210
- headers: { 'Content-Type': 'application/json' },
211
- body: JSON.stringify({
212
- company: null,
213
- }),
214
- })
215
-
216
- expect(res.status).toBe(200)
217
- expect(setManySpy).toHaveBeenCalledWith({
218
- companyName: null,
219
- companyWebsite: null,
220
- companyAbbreviation: null,
221
- })
222
- })
223
- })
224
-
225
- describe('GET /me', () => {
226
- it('returns 404 if current user is not found', async () => {
227
- const app = buildApp({
228
- userRepository: {
229
- findById: vi.fn().mockResolvedValue(null),
230
- },
231
- })
232
- const res = await app.request('/me')
233
- expect(res.status).toBe(404)
234
- const body = await res.json() as any
235
- expect(body.error).toBe('User not found')
236
- })
237
-
238
- it('returns current user profile and notification preferences', async () => {
239
- const app = buildApp()
240
- const res = await app.request('/me')
241
- expect(res.status).toBe(200)
242
- const body = await res.json() as any
243
- expect(body.email).toBe('test@beechcms.com')
244
- expect(body.surname).toBe('User')
245
- expect(body.avatarUrl).toContain('gravatar.com')
246
- expect(body.notificationPrefs.contentUpdate).toBe(false)
247
- })
248
- })
249
-
250
- describe('PUT /profile', () => {
251
- it('returns 400 for invalid JSON', async () => {
252
- const app = buildApp()
253
- const res = await app.request('/profile', {
254
- method: 'PUT',
255
- headers: { 'Content-Type': 'application/json' },
256
- body: 'invalid',
257
- })
258
- expect(res.status).toBe(400)
259
- })
260
-
261
- it('returns 400 for invalid email format', async () => {
262
- const app = buildApp()
263
- const res = await app.request('/profile', {
264
- method: 'PUT',
265
- headers: { 'Content-Type': 'application/json' },
266
- body: JSON.stringify({ email: 'invalid-email' }),
267
- })
268
- expect(res.status).toBe(400)
269
- const body = await res.json() as any
270
- expect(body.detail).toBe('Invalid email format')
271
- })
272
-
273
- it('returns 400 if name is too long', async () => {
274
- const app = buildApp()
275
- const res = await app.request('/profile', {
276
- method: 'PUT',
277
- headers: { 'Content-Type': 'application/json' },
278
- body: JSON.stringify({ name: 'A'.repeat(101) }),
279
- })
280
- expect(res.status).toBe(400)
281
- const body = await res.json() as any
282
- expect(body.detail).toContain('Name is too long')
283
- })
284
-
285
- it('returns 400 if surname is too long', async () => {
286
- const app = buildApp()
287
- const res = await app.request('/profile', {
288
- method: 'PUT',
289
- headers: { 'Content-Type': 'application/json' },
290
- body: JSON.stringify({ surname: 'A'.repeat(101) }),
291
- })
292
- expect(res.status).toBe(400)
293
- const body = await res.json() as any
294
- expect(body.detail).toContain('Surname is too long')
295
- })
296
-
297
- it('returns 400 if no fields to update are provided', async () => {
298
- const app = buildApp()
299
- const res = await app.request('/profile', {
300
- method: 'PUT',
301
- headers: { 'Content-Type': 'application/json' },
302
- body: JSON.stringify({}),
303
- })
304
- expect(res.status).toBe(400)
305
- const body = await res.json() as any
306
- expect(body.error).toBe('No fields to update')
307
- })
308
-
309
- it('returns 409 if email is already in use by another user', async () => {
310
- const app = buildApp({
311
- userRepository: {
312
- emailBelongsToAnotherUser: vi.fn().mockResolvedValue(true),
313
- },
314
- })
315
- const res = await app.request('/profile', {
316
- method: 'PUT',
317
- headers: { 'Content-Type': 'application/json' },
318
- body: JSON.stringify({ email: 'taken@beechcms.com' }),
319
- })
320
- expect(res.status).toBe(409)
321
- const body = await res.json() as any
322
- expect(body.detail).toBe('Email address is already in use')
323
- })
324
-
325
- it('updates user profile successfully', async () => {
326
- const updateProfileSpy = vi.fn().mockResolvedValue(undefined)
327
- const app = buildApp({
328
- userRepository: {
329
- emailBelongsToAnotherUser: vi.fn().mockResolvedValue(false),
330
- updateProfile: updateProfileSpy,
331
- },
332
- })
333
- const res = await app.request('/profile', {
334
- method: 'PUT',
335
- headers: { 'Content-Type': 'application/json' },
336
- body: JSON.stringify({ name: 'NewName', surname: 'NewSurname', email: 'new@beechcms.com' }),
337
- })
338
- expect(res.status).toBe(200)
339
- expect(updateProfileSpy).toHaveBeenCalledWith('u1', {
340
- name: 'NewName',
341
- surname: 'NewSurname',
342
- email: 'new@beechcms.com',
343
- })
344
- })
345
- })
346
-
347
- describe('PUT /password', () => {
348
- it('returns 400 if currentPassword or newPassword is missing', async () => {
349
- const app = buildApp()
350
- const res = await app.request('/password', {
351
- method: 'PUT',
352
- headers: { 'Content-Type': 'application/json' },
353
- body: JSON.stringify({ currentPassword: 'pwd' }),
354
- })
355
- expect(res.status).toBe(400)
356
- })
357
-
358
- it('returns 400 if newPassword is too short', async () => {
359
- const app = buildApp()
360
- const res = await app.request('/password', {
361
- method: 'PUT',
362
- headers: { 'Content-Type': 'application/json' },
363
- body: JSON.stringify({ currentPassword: 'pwd', newPassword: 'short' }),
364
- })
365
- expect(res.status).toBe(400)
366
- })
367
-
368
- it('returns 400 if newPassword is too long', async () => {
369
- const app = buildApp()
370
- const res = await app.request('/password', {
371
- method: 'PUT',
372
- headers: { 'Content-Type': 'application/json' },
373
- body: JSON.stringify({ currentPassword: 'pwd', newPassword: 'A'.repeat(129) }),
374
- })
375
- expect(res.status).toBe(400)
376
- })
377
-
378
- it('returns 404 if user is not found', async () => {
379
- const app = buildApp({
380
- userRepository: {
381
- findById: vi.fn().mockResolvedValue(null),
382
- },
383
- })
384
- const res = await app.request('/password', {
385
- method: 'PUT',
386
- headers: { 'Content-Type': 'application/json' },
387
- body: JSON.stringify({ currentPassword: 'pwd', newPassword: 'new-valid-pwd' }),
388
- })
389
- expect(res.status).toBe(404)
390
- })
391
-
392
- it('returns 401 if current password verification fails', async () => {
393
- const app = buildApp({
394
- hashProvider: {
395
- verify: vi.fn().mockResolvedValue(false),
396
- },
397
- })
398
- const res = await app.request('/password', {
399
- method: 'PUT',
400
- headers: { 'Content-Type': 'application/json' },
401
- body: JSON.stringify({ currentPassword: 'pwd', newPassword: 'new-valid-pwd' }),
402
- })
403
- expect(res.status).toBe(401)
404
- })
405
-
406
- it('updates password successfully if current password is correct', async () => {
407
- const updatePasswordHashSpy = vi.fn().mockResolvedValue(undefined)
408
- const app = buildApp({
409
- userRepository: {
410
- findById: vi.fn().mockResolvedValue({ passwordHash: 'old-hash' }),
411
- updatePasswordHash: updatePasswordHashSpy,
412
- },
413
- hashProvider: {
414
- verify: vi.fn().mockResolvedValue(true),
415
- hash: vi.fn().mockResolvedValue('new-hashed-pwd'),
416
- },
417
- })
418
- const res = await app.request('/password', {
419
- method: 'PUT',
420
- headers: { 'Content-Type': 'application/json' },
421
- body: JSON.stringify({ currentPassword: 'pwd', newPassword: 'new-valid-pwd' }),
422
- })
423
- expect(res.status).toBe(200)
424
- expect(updatePasswordHashSpy).toHaveBeenCalledWith('u1', 'new-hashed-pwd')
425
- })
426
- })
427
-
428
- describe('PUT /avatar', () => {
429
- it('updates avatar URL', async () => {
430
- const updateAvatarSpy = vi.fn().mockResolvedValue(undefined)
431
- const app = buildApp({
432
- userRepository: {
433
- updateAvatarUrl: updateAvatarSpy,
434
- },
435
- })
436
- const res = await app.request('/avatar', {
437
- method: 'PUT',
438
- headers: { 'Content-Type': 'application/json' },
439
- body: JSON.stringify({ avatarUrl: 'https://beechcms.com/avatar.png' }),
440
- })
441
- expect(res.status).toBe(200)
442
- expect(updateAvatarSpy).toHaveBeenCalledWith('u1', 'https://beechcms.com/avatar.png')
443
- })
444
- })
445
-
446
- describe('GET /sessions', () => {
447
- it('returns a list of user active sessions', async () => {
448
- const app = buildApp()
449
- const res = await app.request('/sessions')
450
- expect(res.status).toBe(200)
451
- const body = await res.json() as any[]
452
- expect(body).toHaveLength(1)
453
- expect(body[0].id).toBe('sess-1')
454
- })
455
- })
456
-
457
- describe('DELETE /sessions/:id', () => {
458
- it('returns 404 if session to revoke is not found', async () => {
459
- const app = buildApp({
460
- sessionRepository: {
461
- revokeById: vi.fn().mockResolvedValue(false),
462
- },
463
- })
464
- const res = await app.request('/sessions/unknown', {
465
- method: 'DELETE',
466
- })
467
- expect(res.status).toBe(404)
468
- })
469
-
470
- it('revokes session successfully', async () => {
471
- const revokeSpy = vi.fn().mockResolvedValue(true)
472
- const app = buildApp({
473
- sessionRepository: {
474
- revokeById: revokeSpy,
475
- },
476
- })
477
- const res = await app.request('/sessions/sess-1', {
478
- method: 'DELETE',
479
- })
480
- expect(res.status).toBe(200)
481
- expect(revokeSpy).toHaveBeenCalledWith('sess-1', 'u1', expect.any(Number))
482
- })
483
- })
484
-
485
- describe('GET /activity', () => {
486
- it('returns user activity logs in legacy format', async () => {
487
- const app = buildApp()
488
- const res = await app.request('/activity')
489
- expect(res.status).toBe(200)
490
- const body = await res.json() as any[]
491
- expect(body).toHaveLength(1)
492
- expect(body[0].id).toBe('log-1')
493
- expect(body[0].entity_type).toBe('post')
494
- expect(body[0].entity_slug).toBe('first-post')
495
- expect(body[0].details).toBe('{"ip":"127.0.0.1"}')
496
- })
497
- })
498
-
499
- describe('GET /storage', () => {
500
- it('returns storage metrics and orphaned media files', async () => {
501
- const app = buildApp()
502
- const res = await app.request('/storage')
503
- expect(res.status).toBe(200)
504
- const body = await res.json() as any
505
- expect(body.totalBytes).toBe(3072)
506
- expect(body.fileCount).toBe(5)
507
- expect(body.orphans).toHaveLength(1)
508
- expect(body.orphans[0].key).toBe('media/img2.png')
509
- })
510
- })
511
-
512
- describe('GET /notifications', () => {
513
- it('returns user notification preferences', async () => {
514
- const app = buildApp()
515
- const res = await app.request('/notifications')
516
- expect(res.status).toBe(200)
517
- const body = await res.json() as any
518
- expect(body.contentCreate).toBe(true)
519
- expect(body.contentUpdate).toBe(false)
520
- expect(body.contentDelete).toBe(true)
521
- expect(body.mediaUpload).toBe(true)
522
- })
523
- })
524
-
525
- describe('PUT /notifications', () => {
526
- it('updates user notification preferences', async () => {
527
- const updateNotificationSpy = vi.fn().mockResolvedValue(undefined)
528
- const app = buildApp({
529
- userRepository: {
530
- updateNotificationPreferences: updateNotificationSpy,
531
- },
532
- })
533
- const res = await app.request('/notifications', {
534
- method: 'PUT',
535
- headers: { 'Content-Type': 'application/json' },
536
- body: JSON.stringify({
537
- contentCreate: true,
538
- contentUpdate: true,
539
- contentDelete: false,
540
- mediaUpload: false,
541
- }),
542
- })
543
- expect(res.status).toBe(200)
544
- expect(updateNotificationSpy).toHaveBeenCalledWith(
545
- 'u1',
546
- JSON.stringify({
547
- contentCreate: true,
548
- contentUpdate: true,
549
- contentDelete: false,
550
- mediaUpload: false,
551
- })
552
- )
553
- })
554
- })
555
- })