@beechcms/api 0.6.0-preview.2 → 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 (375) hide show
  1. package/README.md +4 -4
  2. package/assets/dashboard/assets/chart-Cws4Yj6K.js +39 -0
  3. package/assets/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  4. package/assets/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  5. package/assets/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  6. package/assets/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  7. package/assets/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  8. package/assets/dashboard/assets/index-BjPpppHe.css +1 -0
  9. package/assets/dashboard/assets/index-CrW-zhkA.js +642 -0
  10. package/assets/dashboard/assets/lora-cyrillic-ext-wght-normal-YcVxMP-u.woff2 +0 -0
  11. package/assets/dashboard/assets/lora-cyrillic-wght-normal-UWPuZLjM.woff2 +0 -0
  12. package/assets/dashboard/assets/lora-latin-ext-wght-normal-C2Wlntb9.woff2 +0 -0
  13. package/assets/dashboard/assets/lora-latin-wght-normal-BiLcIKcI.woff2 +0 -0
  14. package/assets/dashboard/assets/lora-math-wght-normal-sOy7rEfW.woff2 +0 -0
  15. package/assets/dashboard/assets/lora-symbols-wght-normal-DQ5VrUkH.woff2 +0 -0
  16. package/assets/dashboard/assets/lora-vietnamese-wght-normal-CfJ7gtf3.woff2 +0 -0
  17. package/assets/dashboard/assets/pie-chart-recharts-CAxoDQp2.js +1 -0
  18. package/assets/dashboard/assets/timeseries-chart-recharts-CixDW-LM.js +1 -0
  19. package/assets/dashboard/index.html +2 -2
  20. package/dist/auth/__fixtures__/in-memory-hash-provider.d.ts +5 -0
  21. package/dist/auth/__fixtures__/static-token-service.d.ts +6 -0
  22. package/dist/auth/bcrypt-hash-provider.d.ts +8 -0
  23. package/dist/auth/constants.d.ts +10 -0
  24. package/dist/auth/jose-token-service.d.ts +14 -0
  25. package/dist/auth/login.d.ts +32 -0
  26. package/dist/auth/refresh.d.ts +1 -0
  27. package/dist/factory.d.ts +39 -0
  28. package/dist/features/automations/action-executors/create-entry.executor.d.ts +7 -0
  29. package/dist/features/automations/action-executors/edit-field.executor.d.ts +7 -0
  30. package/dist/features/automations/action-executors/index.d.ts +13 -0
  31. package/dist/features/automations/action-executors/send-mail.executor.d.ts +7 -0
  32. package/dist/features/automations/action-executors/set-variable.executor.d.ts +15 -0
  33. package/dist/features/automations/action-executors/webhook.executor.d.ts +7 -0
  34. package/dist/features/automations/automation-runner.d.ts +13 -0
  35. package/dist/features/automations/automation-runner.utils.d.ts +3 -0
  36. package/dist/features/automations/automations.handler.d.ts +7 -0
  37. package/dist/features/automations/automations.schema.d.ts +191 -0
  38. package/dist/features/automations/context-resolver.d.ts +8 -0
  39. package/dist/features/automations/cron-runner.d.ts +9 -0
  40. package/dist/features/automations/cron-runner.utils.d.ts +1 -0
  41. package/dist/features/automations/filter-translation.d.ts +9 -0
  42. package/dist/features/automations/index.d.ts +7 -0
  43. package/dist/features/automations/template-grammar.d.ts +73 -0
  44. package/dist/features/automations/var-access-resolver.d.ts +6 -0
  45. package/dist/features/automations/when-evaluator.d.ts +3 -0
  46. package/dist/features/automations/when-pushdown.d.ts +2 -0
  47. package/dist/features/backrefs/backrefs.handler.d.ts +3 -0
  48. package/dist/features/backrefs/d1-backref.repository.d.ts +17 -0
  49. package/dist/features/backrefs/index.d.ts +1 -0
  50. package/dist/features/content/constants.d.ts +12 -0
  51. package/dist/features/content/handlers/bulk.handler.d.ts +3 -0
  52. package/dist/features/content/handlers/create.d.ts +3 -0
  53. package/dist/features/content/handlers/delete.d.ts +3 -0
  54. package/dist/features/content/handlers/facets.d.ts +3 -0
  55. package/dist/features/content/handlers/get.d.ts +4 -0
  56. package/dist/features/content/handlers/helpers.d.ts +12 -0
  57. package/dist/features/content/handlers/list.d.ts +3 -0
  58. package/dist/features/content/handlers/update.d.ts +3 -0
  59. package/dist/features/content/index.d.ts +4 -0
  60. package/dist/features/dashboard-layout/dashboard-layout.handler.d.ts +7 -0
  61. package/dist/features/dashboard-layout/index.d.ts +1 -0
  62. package/dist/features/draft/draft.handler.d.ts +4 -0
  63. package/dist/features/draft/draft.middleware.d.ts +9 -0
  64. package/dist/features/draft/index.d.ts +1 -0
  65. package/{src/features/email/email.provider.ts → dist/features/email/email.provider.d.ts} +19 -24
  66. package/dist/features/email/email.service.d.ts +13 -0
  67. package/dist/features/email/email.types.d.ts +94 -0
  68. package/{src/features/email/index.ts → dist/features/email/index.d.ts} +3 -16
  69. package/dist/features/email/providers/resend.d.ts +36 -0
  70. package/dist/features/email/providers/smtp.d.ts +11 -0
  71. package/dist/features/email/templates/automation-mail.d.ts +8 -0
  72. package/dist/features/email/templates/password-changed.d.ts +15 -0
  73. package/dist/features/email/templates/password-reset.d.ts +18 -0
  74. package/dist/features/email/templates/shell.d.ts +58 -0
  75. package/dist/features/notifications/index.d.ts +1 -0
  76. package/dist/features/notifications/notifications.handler.d.ts +15 -0
  77. package/dist/features/password-reset/index.d.ts +6 -0
  78. package/dist/features/password-reset/request.d.ts +10 -0
  79. package/dist/features/password-reset/reset.d.ts +9 -0
  80. package/dist/features/rotate-field/index.d.ts +1 -0
  81. package/dist/features/rotate-field/rotate-field.handler.d.ts +7 -0
  82. package/dist/features/rotate-field/rotate-field.schema.d.ts +11 -0
  83. package/dist/features/schema/schema.handler.d.ts +7 -0
  84. package/dist/features/seeds/index.d.ts +1 -0
  85. package/dist/features/seeds/seeds.handler.d.ts +6 -0
  86. package/dist/features/settings/settings.handler.d.ts +7 -0
  87. package/dist/features/setup/index.d.ts +7 -0
  88. package/dist/features/stats/index.d.ts +1 -0
  89. package/dist/features/stats/stats.handler.d.ts +7 -0
  90. package/dist/features/webhooks/index.d.ts +3 -0
  91. package/dist/index.d.ts +6 -0
  92. package/dist/index.js +9666 -0
  93. package/dist/media-utils.d.ts +25 -0
  94. package/dist/middleware/auth-providers.middleware.d.ts +8 -0
  95. package/dist/middleware/observability.middleware.d.ts +20 -0
  96. package/dist/middleware/rate-limit.middleware.d.ts +9 -0
  97. package/dist/middleware/repository.middleware.d.ts +34 -0
  98. package/dist/middleware/seed-registry.middleware.d.ts +10 -0
  99. package/dist/middleware/storage.middleware.d.ts +7 -0
  100. package/dist/middleware.d.ts +11 -0
  101. package/dist/public/access-policy.d.ts +12 -0
  102. package/dist/public/api-key-middleware.d.ts +6 -0
  103. package/dist/public/cache-utils.d.ts +10 -0
  104. package/dist/public/entry-projection.d.ts +2 -0
  105. package/dist/public/idempotency.d.ts +9 -0
  106. package/dist/public/index.d.ts +11 -0
  107. package/dist/public/problem-details.d.ts +31 -0
  108. package/dist/public/public-add.d.ts +3 -0
  109. package/dist/public/public-edit.d.ts +5 -0
  110. package/dist/public/public-errors.d.ts +13 -0
  111. package/dist/public/public-read.d.ts +3 -0
  112. package/dist/public/public-routes.d.ts +3 -0
  113. package/dist/public/query-builder.d.ts +28 -0
  114. package/dist/public/rate-limit-middleware.d.ts +3 -0
  115. package/dist/public/read-list.d.ts +26 -0
  116. package/dist/public/read-single.d.ts +22 -0
  117. package/dist/public/response-builder.d.ts +22 -0
  118. package/dist/public/sanitize.d.ts +23 -0
  119. package/{src/public/slug-utils.ts → dist/public/slug-utils.d.ts} +3 -10
  120. package/dist/rate-limit/cloudflare-rate-limiter.d.ts +6 -0
  121. package/dist/rate-limit/in-memory-rate-limiter.d.ts +7 -0
  122. package/dist/rate-limit/no-op-rate-limiter.d.ts +4 -0
  123. package/dist/search-utils.d.ts +54 -0
  124. package/dist/search.d.ts +6 -0
  125. package/dist/shared/apply-policies.d.ts +10 -0
  126. package/dist/shared/automations.repository.d1.d.ts +12 -0
  127. package/dist/shared/background-notification-service.d.ts +18 -0
  128. package/dist/shared/base.repository.d1.d.ts +18 -0
  129. package/dist/shared/content-utils.d.ts +21 -0
  130. package/dist/shared/content.repository.d1.d.ts +68 -0
  131. package/dist/shared/d1-activity-log.repository.d.ts +13 -0
  132. package/dist/shared/d1-activity-logger.d.ts +20 -0
  133. package/dist/shared/d1-analytics.repository.d.ts +20 -0
  134. package/dist/shared/d1-content-scan.repository.d.ts +7 -0
  135. package/dist/shared/d1-notification.repository.d.ts +17 -0
  136. package/dist/shared/d1-password-reset-token.repository.d.ts +10 -0
  137. package/dist/shared/d1-search.repository.d.ts +14 -0
  138. package/dist/shared/d1-session.repository.d.ts +12 -0
  139. package/dist/shared/d1-setup-checklist.repository.d.ts +12 -0
  140. package/dist/shared/d1-user.repository.d.ts +18 -0
  141. package/dist/shared/d1-widget.repository.d.ts +31 -0
  142. package/dist/shared/dashboard-layout.repository.d1.d.ts +9 -0
  143. package/dist/shared/demo-data-sql.d.ts +1 -0
  144. package/dist/shared/demo-data.repository.d1.d.ts +6 -0
  145. package/dist/shared/execution-context-scheduler.d.ts +6 -0
  146. package/dist/shared/fixed-clock.d.ts +13 -0
  147. package/dist/shared/fts-sync.d.ts +1 -0
  148. package/dist/shared/idempotency.repository.d1.d.ts +16 -0
  149. package/dist/shared/in-memory-activity-logger.d.ts +11 -0
  150. package/dist/shared/in-memory-notification-service.d.ts +11 -0
  151. package/dist/shared/in-memory-seed.repository.d.ts +18 -0
  152. package/dist/shared/media.repository.d1.d.ts +35 -0
  153. package/dist/shared/qstash-notification-service.d.ts +18 -0
  154. package/dist/shared/query-utils.d.ts +36 -0
  155. package/dist/shared/request-utils.d.ts +13 -0
  156. package/dist/shared/schema-mutator.d1.d.ts +12 -0
  157. package/dist/shared/seed-layout.repository.d1.d.ts +9 -0
  158. package/dist/shared/seed-registry-cache.d.ts +12 -0
  159. package/dist/shared/seed.repository.d1.d.ts +13 -0
  160. package/dist/shared/sequential-id-generator.d.ts +13 -0
  161. package/dist/shared/site-settings.repository.d1.d.ts +7 -0
  162. package/dist/shared/storage/factory.d.ts +8 -0
  163. package/dist/shared/storage/s3-bucket.d.ts +43 -0
  164. package/dist/shared/storage-utils.d.ts +7 -0
  165. package/dist/shared/system-stats.repository.d1.d.ts +25 -0
  166. package/dist/types.d.ts +85 -0
  167. package/dist/upload.d.ts +16 -0
  168. package/dist/widget.d.ts +7 -0
  169. package/package.json +27 -18
  170. package/assets/dashboard/assets/chart-BrJFdsGZ.js +0 -39
  171. package/assets/dashboard/assets/index-CIaoMxuB.css +0 -1
  172. package/assets/dashboard/assets/index-wTKgygsg.js +0 -636
  173. package/assets/dashboard/assets/pie-chart-recharts-BEaE1FOE.js +0 -1
  174. package/assets/dashboard/assets/timeseries-chart-recharts-DmWM6imF.js +0 -1
  175. package/src/auth/__fixtures__/in-memory-hash-provider.ts +0 -17
  176. package/src/auth/__fixtures__/static-token-service.ts +0 -22
  177. package/src/auth/bcrypt-hash-provider.ts +0 -24
  178. package/src/auth/constants.ts +0 -14
  179. package/src/auth/generate-refresh-token.test.ts +0 -23
  180. package/src/auth/hash-provider.test.ts +0 -55
  181. package/src/auth/jose-token-service.ts +0 -62
  182. package/src/auth/jwt-claims-passthrough.test.ts +0 -87
  183. package/src/auth/login.test.ts +0 -100
  184. package/src/auth/login.ts +0 -78
  185. package/src/auth/refresh.ts +0 -11
  186. package/src/auth/token-service.test.ts +0 -90
  187. package/src/factory.ts +0 -370
  188. package/src/features/automations/__tests__/action-executors.test.ts +0 -255
  189. package/src/features/automations/__tests__/automation-runner.test.ts +0 -196
  190. package/src/features/automations/__tests__/automation-runner.utils.test.ts +0 -60
  191. package/src/features/automations/__tests__/automations.handler.test.ts +0 -264
  192. package/src/features/automations/__tests__/automations.repository.test.ts +0 -163
  193. package/src/features/automations/__tests__/automations.schema.test.ts +0 -224
  194. package/src/features/automations/__tests__/context-resolver.test.ts +0 -126
  195. package/src/features/automations/__tests__/cron-runner.test.ts +0 -267
  196. package/src/features/automations/__tests__/cron-runner.utils.test.ts +0 -144
  197. package/src/features/automations/__tests__/set-variable.executor.test.ts +0 -383
  198. package/src/features/automations/__tests__/template-grammar.test.ts +0 -308
  199. package/src/features/automations/__tests__/webhook.executor.test.ts +0 -142
  200. package/src/features/automations/__tests__/when-evaluator.test.ts +0 -274
  201. package/src/features/automations/__tests__/when-pushdown.test.ts +0 -281
  202. package/src/features/automations/action-executors/create-entry.executor.ts +0 -27
  203. package/src/features/automations/action-executors/edit-field.executor.ts +0 -26
  204. package/src/features/automations/action-executors/index.ts +0 -37
  205. package/src/features/automations/action-executors/send-mail.executor.ts +0 -53
  206. package/src/features/automations/action-executors/set-variable.executor.ts +0 -159
  207. package/src/features/automations/action-executors/webhook.executor.ts +0 -67
  208. package/src/features/automations/automation-runner.ts +0 -85
  209. package/src/features/automations/automation-runner.utils.ts +0 -47
  210. package/src/features/automations/automations.handler.ts +0 -197
  211. package/src/features/automations/automations.schema.ts +0 -177
  212. package/src/features/automations/context-resolver.ts +0 -152
  213. package/src/features/automations/cron-runner.ts +0 -140
  214. package/src/features/automations/cron-runner.utils.ts +0 -44
  215. package/src/features/automations/filter-translation.ts +0 -46
  216. package/src/features/automations/index.ts +0 -16
  217. package/src/features/automations/template-grammar.ts +0 -245
  218. package/src/features/automations/var-access-resolver.ts +0 -140
  219. package/src/features/automations/when-evaluator.ts +0 -87
  220. package/src/features/automations/when-pushdown.ts +0 -57
  221. package/src/features/backrefs/__tests__/backrefs.handler.test.ts +0 -359
  222. package/src/features/backrefs/backrefs.handler.ts +0 -168
  223. package/src/features/backrefs/d1-backref.repository.ts +0 -84
  224. package/src/features/backrefs/index.ts +0 -5
  225. package/src/features/content/constants.ts +0 -16
  226. package/src/features/content/handlers/bulk.handler.ts +0 -185
  227. package/src/features/content/handlers/create.ts +0 -129
  228. package/src/features/content/handlers/delete.ts +0 -62
  229. package/src/features/content/handlers/facets.ts +0 -49
  230. package/src/features/content/handlers/get.ts +0 -120
  231. package/src/features/content/handlers/helpers.test.ts +0 -180
  232. package/src/features/content/handlers/helpers.ts +0 -93
  233. package/src/features/content/handlers/list.ts +0 -174
  234. package/src/features/content/handlers/update.ts +0 -174
  235. package/src/features/content/index.ts +0 -26
  236. package/src/features/dashboard-layout/__tests__/dashboard-layout.handler.test.ts +0 -388
  237. package/src/features/dashboard-layout/dashboard-layout.handler.ts +0 -206
  238. package/src/features/dashboard-layout/index.ts +0 -5
  239. package/src/features/draft/draft.handler.ts +0 -195
  240. package/src/features/draft/draft.middleware.ts +0 -66
  241. package/src/features/draft/index.ts +0 -5
  242. package/src/features/email/email.service.ts +0 -98
  243. package/src/features/email/email.types.ts +0 -119
  244. package/src/features/email/providers/resend.ts +0 -67
  245. package/src/features/email/providers/smtp.ts +0 -55
  246. package/src/features/email/templates/automation-mail.ts +0 -19
  247. package/src/features/email/templates/password-changed.ts +0 -63
  248. package/src/features/email/templates/password-reset.ts +0 -68
  249. package/src/features/email/templates/shell.ts +0 -96
  250. package/src/features/notifications/index.ts +0 -5
  251. package/src/features/notifications/notifications.handler.ts +0 -105
  252. package/src/features/password-reset/index.ts +0 -19
  253. package/src/features/password-reset/request.ts +0 -92
  254. package/src/features/password-reset/reset.ts +0 -102
  255. package/src/features/rotate-field/index.ts +0 -5
  256. package/src/features/rotate-field/rotate-field.handler.ts +0 -132
  257. package/src/features/rotate-field/rotate-field.schema.ts +0 -17
  258. package/src/features/schema/schema.handler.ts +0 -131
  259. package/src/features/seeds/index.ts +0 -5
  260. package/src/features/seeds/seeds.handler.test.ts +0 -1199
  261. package/src/features/seeds/seeds.handler.ts +0 -558
  262. package/src/features/settings/__tests__/settings.handler.test.ts +0 -555
  263. package/src/features/settings/settings.handler.ts +0 -392
  264. package/src/features/setup/index.ts +0 -288
  265. package/src/features/stats/index.ts +0 -5
  266. package/src/features/stats/stats.handler.ts +0 -420
  267. package/src/features/webhooks/index.ts +0 -63
  268. package/src/index.ts +0 -65
  269. package/src/media-utils.ts +0 -82
  270. package/src/middleware/auth-providers.middleware.test.ts +0 -85
  271. package/src/middleware/auth-providers.middleware.ts +0 -45
  272. package/src/middleware/observability.middleware.test.ts +0 -93
  273. package/src/middleware/observability.middleware.ts +0 -70
  274. package/src/middleware/rate-limit.middleware.ts +0 -45
  275. package/src/middleware/repository.middleware.ts +0 -117
  276. package/src/middleware/seed-registry.middleware.test.ts +0 -97
  277. package/src/middleware/seed-registry.middleware.ts +0 -21
  278. package/src/middleware/storage.middleware.ts +0 -25
  279. package/src/middleware.ts +0 -45
  280. package/src/public/access-policy.ts +0 -27
  281. package/src/public/api-key-middleware.ts +0 -57
  282. package/src/public/cache-utils.ts +0 -38
  283. package/src/public/entry-projection.ts +0 -46
  284. package/src/public/idempotency.ts +0 -23
  285. package/src/public/index.ts +0 -16
  286. package/src/public/problem-details.ts +0 -124
  287. package/src/public/public-add.ts +0 -114
  288. package/src/public/public-edit.ts +0 -163
  289. package/src/public/public-errors.ts +0 -19
  290. package/src/public/public-read.ts +0 -63
  291. package/src/public/public-routes.ts +0 -88
  292. package/src/public/query-builder.test.ts +0 -224
  293. package/src/public/query-builder.ts +0 -156
  294. package/src/public/rate-limit-middleware.ts +0 -34
  295. package/src/public/read-list.ts +0 -54
  296. package/src/public/read-single.ts +0 -48
  297. package/src/public/response-builder.ts +0 -30
  298. package/src/public/sanitize.ts +0 -69
  299. package/src/rate-limit/cloudflare-rate-limiter.test.ts +0 -30
  300. package/src/rate-limit/cloudflare-rate-limiter.ts +0 -15
  301. package/src/rate-limit/in-memory-rate-limiter.test.ts +0 -37
  302. package/src/rate-limit/in-memory-rate-limiter.ts +0 -17
  303. package/src/rate-limit/no-op-rate-limiter.test.ts +0 -22
  304. package/src/rate-limit/no-op-rate-limiter.ts +0 -11
  305. package/src/search-utils.test.ts +0 -211
  306. package/src/search-utils.ts +0 -213
  307. package/src/search.ts +0 -65
  308. package/src/shared/apply-policies.test.ts +0 -81
  309. package/src/shared/apply-policies.ts +0 -67
  310. package/src/shared/automations.repository.d1.ts +0 -150
  311. package/src/shared/background-notification-service.test.ts +0 -62
  312. package/src/shared/background-notification-service.ts +0 -52
  313. package/src/shared/base.repository.d1.ts +0 -32
  314. package/src/shared/content-utils.test.ts +0 -165
  315. package/src/shared/content-utils.ts +0 -86
  316. package/src/shared/content.repository.d1.test.ts +0 -507
  317. package/src/shared/content.repository.d1.ts +0 -851
  318. package/src/shared/d1-activity-log.repository.test.ts +0 -140
  319. package/src/shared/d1-activity-log.repository.ts +0 -105
  320. package/src/shared/d1-activity-logger.test.ts +0 -86
  321. package/src/shared/d1-activity-logger.ts +0 -67
  322. package/src/shared/d1-analytics.repository.test.ts +0 -78
  323. package/src/shared/d1-analytics.repository.ts +0 -85
  324. package/src/shared/d1-content-scan.repository.test.ts +0 -80
  325. package/src/shared/d1-content-scan.repository.ts +0 -37
  326. package/src/shared/d1-notification.repository.test.ts +0 -128
  327. package/src/shared/d1-notification.repository.ts +0 -118
  328. package/src/shared/d1-password-reset-token.repository.test.ts +0 -81
  329. package/src/shared/d1-password-reset-token.repository.ts +0 -56
  330. package/src/shared/d1-search.repository.test.ts +0 -87
  331. package/src/shared/d1-search.repository.ts +0 -88
  332. package/src/shared/d1-session.repository.test.ts +0 -125
  333. package/src/shared/d1-session.repository.ts +0 -102
  334. package/src/shared/d1-setup-checklist.repository.ts +0 -36
  335. package/src/shared/d1-user.repository.test.ts +0 -151
  336. package/src/shared/d1-user.repository.ts +0 -119
  337. package/src/shared/d1-widget.repository.test.ts +0 -267
  338. package/src/shared/d1-widget.repository.ts +0 -385
  339. package/src/shared/dashboard-layout.repository.d1.test.ts +0 -135
  340. package/src/shared/dashboard-layout.repository.d1.ts +0 -58
  341. package/src/shared/demo-data-sql.ts +0 -216
  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 -58
  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.test.ts +0 -142
  358. package/src/shared/schema-mutator.d1.ts +0 -64
  359. package/src/shared/seed-layout.repository.d1.test.ts +0 -114
  360. package/src/shared/seed-layout.repository.d1.ts +0 -62
  361. package/src/shared/seed-registry-cache.test.ts +0 -68
  362. package/src/shared/seed-registry-cache.ts +0 -49
  363. package/src/shared/seed.repository.d1.test.ts +0 -143
  364. package/src/shared/seed.repository.d1.ts +0 -98
  365. package/src/shared/sequential-id-generator.ts +0 -33
  366. package/src/shared/site-settings.repository.d1.ts +0 -53
  367. package/src/shared/storage/factory.ts +0 -41
  368. package/src/shared/storage/s3-bucket.ts +0 -195
  369. package/src/shared/storage-utils.ts +0 -40
  370. package/src/shared/system-stats.repository.d1.test.ts +0 -58
  371. package/src/shared/system-stats.repository.d1.ts +0 -48
  372. package/src/types.ts +0 -90
  373. package/src/upload.ts +0 -198
  374. package/src/widget.test.ts +0 -85
  375. package/src/widget.ts +0 -251
@@ -1,197 +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 { Hono } from 'hono'
7
- import type { Env, Variables } from '../../types'
8
- import { publicProblem } from '../../public/problem-details'
9
- import {
10
- createAutomationSchema,
11
- updateAutomationSchema,
12
- toggleAutomationSchema,
13
- } from './automations.schema'
14
-
15
- const automationsApp = new Hono<{ Bindings: Env; Variables: Variables }>()
16
-
17
- /**
18
- * GET /automations?seed=<slug>
19
- * Returns every automation declared for the given seed, newest first.
20
- */
21
- automationsApp.get('/', async (context) => {
22
- const seedSlug = context.req.query('seed')
23
- if (!seedSlug) {
24
- return publicProblem(context, {
25
- type: 'missing-seed',
26
- status: 400,
27
- title: 'Bad Request',
28
- detail: 'Query param `seed` is required',
29
- })
30
- }
31
- const repository = context.get('automationRepository')
32
- const automations = await repository.list(seedSlug)
33
- return context.json(automations)
34
- })
35
-
36
- /**
37
- * POST /automations
38
- * Creates a new automation. Body validated by `createAutomationSchema`.
39
- */
40
- automationsApp.post('/', async (context) => {
41
- let body: unknown
42
- try {
43
- body = await context.req.json()
44
- } catch {
45
- return publicProblem(context, {
46
- type: 'invalid-json',
47
- status: 400,
48
- title: 'Bad Request',
49
- detail: 'Request body is not valid JSON',
50
- })
51
- }
52
-
53
- const parsed = createAutomationSchema.safeParse(body)
54
- if (!parsed.success) {
55
- return publicProblem(context, {
56
- type: 'automation-validation-failed',
57
- status: 400,
58
- title: 'Bad Request',
59
- detail: parsed.error.message,
60
- })
61
- }
62
-
63
- const repository = context.get('automationRepository')
64
- const id = await repository.create({
65
- seed_slug: parsed.data.seed_slug,
66
- name: parsed.data.name,
67
- triggers: parsed.data.triggers,
68
- trigger_conditions: parsed.data.trigger_conditions ?? null,
69
- actions: parsed.data.actions,
70
- })
71
- return context.json({ id }, 201)
72
- })
73
-
74
- /**
75
- * GET /automations/:id
76
- */
77
- automationsApp.get('/:id', async (context) => {
78
- const id = context.req.param('id')
79
- const automation = await context.get('automationRepository').findById(id)
80
- if (!automation) {
81
- return publicProblem(context, {
82
- type: 'automation-not-found',
83
- status: 404,
84
- title: 'Not Found',
85
- detail: `Automation ${id} does not exist`,
86
- })
87
- }
88
- return context.json(automation)
89
- })
90
-
91
- /**
92
- * PUT /automations/:id
93
- * Full update — partial bodies allowed; cron expression validation
94
- * is enforced by the triggers array schema.
95
- */
96
- automationsApp.put('/:id', async (context) => {
97
- const id = context.req.param('id')
98
- const repository = context.get('automationRepository')
99
- const existing = await repository.findById(id)
100
- if (!existing) {
101
- return publicProblem(context, {
102
- type: 'automation-not-found',
103
- status: 404,
104
- title: 'Not Found',
105
- detail: `Automation ${id} does not exist`,
106
- })
107
- }
108
-
109
- let body: unknown
110
- try {
111
- body = await context.req.json()
112
- } catch {
113
- return publicProblem(context, {
114
- type: 'invalid-json',
115
- status: 400,
116
- title: 'Bad Request',
117
- detail: 'Request body is not valid JSON',
118
- })
119
- }
120
-
121
- const parsed = updateAutomationSchema.safeParse(body)
122
- if (!parsed.success) {
123
- return publicProblem(context, {
124
- type: 'automation-validation-failed',
125
- status: 400,
126
- title: 'Bad Request',
127
- detail: parsed.error.message,
128
- })
129
- }
130
-
131
- await repository.update(id, parsed.data)
132
- return context.body(null, 204)
133
- })
134
-
135
- /**
136
- * PATCH /automations/:id/toggle
137
- * Atomic single-field flip — does not require sending the full body.
138
- */
139
- automationsApp.patch('/:id/toggle', async (context) => {
140
- const id = context.req.param('id')
141
- const repository = context.get('automationRepository')
142
- const existing = await repository.findById(id)
143
- if (!existing) {
144
- return publicProblem(context, {
145
- type: 'automation-not-found',
146
- status: 404,
147
- title: 'Not Found',
148
- detail: `Automation ${id} does not exist`,
149
- })
150
- }
151
-
152
- let body: unknown
153
- try {
154
- body = await context.req.json()
155
- } catch {
156
- return publicProblem(context, {
157
- type: 'invalid-json',
158
- status: 400,
159
- title: 'Bad Request',
160
- detail: 'Request body is not valid JSON',
161
- })
162
- }
163
-
164
- const parsed = toggleAutomationSchema.safeParse(body)
165
- if (!parsed.success) {
166
- return publicProblem(context, {
167
- type: 'automation-validation-failed',
168
- status: 400,
169
- title: 'Bad Request',
170
- detail: parsed.error.message,
171
- })
172
- }
173
-
174
- await repository.toggle(id, parsed.data.enabled)
175
- return context.body(null, 204)
176
- })
177
-
178
- /**
179
- * DELETE /automations/:id
180
- */
181
- automationsApp.delete('/:id', async (context) => {
182
- const id = context.req.param('id')
183
- const repository = context.get('automationRepository')
184
- const existing = await repository.findById(id)
185
- if (!existing) {
186
- return publicProblem(context, {
187
- type: 'automation-not-found',
188
- status: 404,
189
- title: 'Not Found',
190
- detail: `Automation ${id} does not exist`,
191
- })
192
- }
193
- await repository.delete(id)
194
- return context.body(null, 204)
195
- })
196
-
197
- export { automationsApp }
@@ -1,177 +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
- // Mirror: apps/dashboard/src/features/automations/schema/automation.schema.ts — keep structurally identical.
6
- import { z } from 'zod'
7
- import type { WhenNode } from '@beechcms/core'
8
- import { isPrivateHost } from '@beechcms/core'
9
- import { AUTOMATION_RESERVED_WORDS } from './template-grammar'
10
-
11
- // ---------------------------------------------------------------------------
12
- // Trigger conditions — recursive WhenNode schema (Task 14)
13
- // ---------------------------------------------------------------------------
14
-
15
- const whenOperandSchema = z.union([
16
- z.object({ kind: z.literal('literal'), value: z.unknown() }),
17
- z.object({ kind: z.literal('ref'), key: z.string().min(1) }),
18
- ])
19
-
20
- const whenPredicateSchema = z.object({
21
- kind: z.literal('predicate'),
22
- left: whenOperandSchema,
23
- op: z.enum(['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'contains', 'startswith', 'endswith', 'in', 'notin', 'isempty', 'isnotempty', 'matches']),
24
- right: whenOperandSchema.optional(),
25
- })
26
-
27
- const whenNodeSchema: z.ZodType<WhenNode> = z.lazy(() =>
28
- z.union([
29
- whenPredicateSchema,
30
- z.object({
31
- kind: z.literal('group'),
32
- op: z.enum(['AND', 'OR']),
33
- children: z.array(whenNodeSchema).min(1),
34
- negate: z.boolean().optional(),
35
- }).refine(
36
- (g) => depthOf(g) <= 10,
37
- { message: 'WhenNode nesting exceeds maximum depth of 10' },
38
- ),
39
- ]),
40
- )
41
-
42
- function depthOf(node: unknown, d = 0): number {
43
- if (d > 10) return d
44
- if (typeof node !== 'object' || !node) return d
45
- const n = node as Record<string, unknown>
46
- if (n['kind'] === 'group' && Array.isArray(n['children'])) {
47
- return Math.max(...(n['children'] as unknown[]).map((c) => depthOf(c, d + 1)))
48
- }
49
- return d
50
- }
51
-
52
- const triggerConditionsSchema = whenNodeSchema.nullable().optional()
53
-
54
- const setVariableFilterSchema = z.object({
55
- field: z.string().min(1),
56
- op: z.enum(['eq', 'neq', 'contains', 'gt', 'lt', 'isempty', 'isnotempty']),
57
- value: z.unknown(),
58
- })
59
-
60
- // ---------------------------------------------------------------------------
61
- // Action schemas
62
- // ---------------------------------------------------------------------------
63
-
64
- const setVariableActionSchema = z.object({
65
- type: z.literal('set_variable'),
66
- name: z
67
- .string()
68
- .min(1)
69
- .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/)
70
- .refine((v) => !AUTOMATION_RESERVED_WORDS.has(v), {
71
- message: 'automations.editor.errors.variableNameReserved',
72
- }),
73
- seed_slug: z.string().min(1).optional(),
74
- fixed_id: z.string().min(1).optional(),
75
- column: z.string().min(1).optional(),
76
- filters: z.array(setVariableFilterSchema).default([]),
77
- order_by: z.string().optional(),
78
- order: z.enum(['asc', 'desc']).optional(),
79
- load_type: z.enum(['fruit', 'branch']).optional(), // accepted but ignored at runtime
80
- })
81
-
82
- const webhookActionSchema = z.object({
83
- type: z.literal('webhook'),
84
- url: z
85
- .string()
86
- .url()
87
- .refine((u) => {
88
- try { return new URL(u).protocol === 'https:' } catch { return false }
89
- }, { message: 'automations.editor.errors.webhookHttpsRequired' })
90
- .refine((u) => {
91
- try { return !isPrivateHost(new URL(u).hostname) } catch { return false }
92
- }, { message: 'automations.editor.errors.webhookPrivateHostBlocked' }),
93
- method: z.enum(['POST', 'GET', 'PUT']).optional(),
94
- headers: z.record(z.string(), z.string()).optional(),
95
- body_template: z.preprocess(
96
- (v) => (v == null ? '' : v),
97
- z.string().min(1, 'automations.editor.errors.bodyRequired'),
98
- ),
99
- })
100
-
101
- const sendMailActionSchema = z.object({
102
- type: z.literal('send_mail'),
103
- to: z.string().email(),
104
- subject_template: z.string().min(1),
105
- body_template: z.string().min(1),
106
- })
107
-
108
- const editFieldActionSchema = z.object({
109
- type: z.literal('edit_field'),
110
- field: z.string().min(1),
111
- value: z.unknown(),
112
- })
113
-
114
- const createEntryActionSchema = z.object({
115
- type: z.literal('create_entry'),
116
- seed_slug: z.string().min(1),
117
- field_map: z.record(z.string(), z.string()),
118
- })
119
-
120
- export const automationActionSchema = z.discriminatedUnion('type', [
121
- setVariableActionSchema,
122
- webhookActionSchema,
123
- sendMailActionSchema,
124
- editFieldActionSchema,
125
- createEntryActionSchema,
126
- ])
127
-
128
- // ---------------------------------------------------------------------------
129
- // Triggers schema
130
- // ---------------------------------------------------------------------------
131
-
132
- const automationTriggerSchema = z.object({
133
- event: z.enum(['create', 'update', 'delete', 'cron']),
134
- cron: z.string().nullable().optional(),
135
- })
136
-
137
- const triggersSchema = z
138
- .array(automationTriggerSchema)
139
- .min(1, 'At least one trigger is required')
140
- .refine(
141
- (triggers) => triggers.filter((t) => t.event === 'cron').length <= 1,
142
- { message: 'Only one cron trigger is allowed per automation' },
143
- )
144
- .refine(
145
- (triggers) => {
146
- const events = triggers.map((t) => t.event)
147
- return new Set(events).size === events.length
148
- },
149
- { message: 'Duplicate trigger events are not allowed' },
150
- )
151
- .refine(
152
- (triggers) => triggers.every((t) => t.event !== 'cron' || !!t.cron),
153
- { message: 'cron expression is required for cron triggers', path: ['cron'] },
154
- )
155
-
156
- // ---------------------------------------------------------------------------
157
- // Automation create/update schemas
158
- // ---------------------------------------------------------------------------
159
-
160
- const createAutomationBaseSchema = z.object({
161
- seed_slug: z.string().min(1),
162
- name: z.string().min(1).max(100),
163
- triggers: triggersSchema,
164
- trigger_conditions: triggerConditionsSchema,
165
- actions: z.array(automationActionSchema).min(1, 'At least one action is required'),
166
- })
167
-
168
- export const createAutomationSchema = createAutomationBaseSchema
169
-
170
- export const updateAutomationSchema = createAutomationBaseSchema.partial()
171
-
172
- export const toggleAutomationSchema = z.object({
173
- enabled: z.boolean(),
174
- })
175
-
176
- export type CreateAutomationBody = z.infer<typeof createAutomationSchema>
177
- export type UpdateAutomationBody = z.infer<typeof updateAutomationSchema>
@@ -1,152 +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 { Automation } from '@beechcms/core'
6
- import type { AutomationContextSelector, ParsedKey } from './template-grammar'
7
- import { resolvePath } from './automation-runner.utils'
8
-
9
- export interface ResolvedContext {
10
- lookup(key: ParsedKey, onMissing?: (field: string) => void): unknown
11
- triggerEntry: Record<string, unknown> | null
12
- }
13
-
14
- const MAX_PLUCK = 100
15
- const AGGREGATE_OPS = new Set(['count', 'sum', 'avg', 'min', 'max', 'pluck'])
16
-
17
- function applyAggregate(
18
- op: string,
19
- field: string | null,
20
- rows: Array<Record<string, unknown>>,
21
- onMissing?: (f: string) => void,
22
- ): unknown {
23
- switch (op) {
24
- case 'count':
25
- return rows.length
26
-
27
- case 'sum': {
28
- if (!field) { if (onMissing) onMissing('sum:field'); return 0 }
29
- return rows.reduce((acc, r) => {
30
- const v = Number(r[field])
31
- if (Number.isNaN(v)) { if (onMissing) onMissing(`sum:${field}:NaN`); return acc }
32
- return acc + v
33
- }, 0)
34
- }
35
-
36
- case 'avg': {
37
- if (!field || rows.length === 0) { if (onMissing && !field) onMissing('avg:field'); return 0 }
38
- const total = rows.reduce((acc, r) => {
39
- const v = Number(r[field])
40
- if (Number.isNaN(v)) { if (onMissing) onMissing(`avg:${field}:NaN`); return acc }
41
- return acc + v
42
- }, 0)
43
- return rows.length > 0 ? total / rows.length : 0
44
- }
45
-
46
- case 'min': {
47
- if (!field || rows.length === 0) { if (onMissing && !field) onMissing('min:field'); return null }
48
- return rows.reduce<number | null>((acc, r) => {
49
- const v = Number(r[field])
50
- if (Number.isNaN(v)) return acc
51
- return acc === null || v < acc ? v : acc
52
- }, null)
53
- }
54
-
55
- case 'max': {
56
- if (!field || rows.length === 0) { if (onMissing && !field) onMissing('max:field'); return null }
57
- return rows.reduce<number | null>((acc, r) => {
58
- const v = Number(r[field])
59
- if (Number.isNaN(v)) return acc
60
- return acc === null || v > acc ? v : acc
61
- }, null)
62
- }
63
-
64
- case 'pluck': {
65
- if (!field) { if (onMissing) onMissing('pluck:field'); return '' }
66
- const values = rows.slice(0, MAX_PLUCK).map((r) => String(r[field] ?? ''))
67
- const truncated = rows.length > MAX_PLUCK
68
- return values.join(', ') + (truncated ? ' …' : '')
69
- }
70
-
71
- default:
72
- return undefined
73
- }
74
- }
75
-
76
- export async function resolveAutomationContext(
77
- _automation: Automation,
78
- triggerEntry: Record<string, unknown> | null,
79
- batchEntries: Array<Record<string, unknown>>,
80
- ): Promise<ResolvedContext> {
81
- function lookup(parsed: ParsedKey, onMissing?: (field: string) => void): unknown {
82
- if (parsed.kind === 'simple') {
83
- if (parsed.path.startsWith('this.')) {
84
- const field = parsed.path.slice(5)
85
- const val = resolvePath(triggerEntry ?? {}, field)
86
- if (val === undefined && onMissing) onMissing(parsed.path)
87
- return val
88
- }
89
- const val = resolvePath(triggerEntry ?? {}, parsed.path)
90
- if (val === undefined && onMissing) onMissing(parsed.path)
91
- return val
92
- }
93
-
94
- if (parsed.kind !== 'scoped') {
95
- if (onMissing) onMissing(parsed.kind === 'var_access' ? parsed.name : 'unknown')
96
- return undefined
97
- }
98
-
99
- const { scope, selector: _selector, op, field } = parsed
100
-
101
- if (scope === 'this') {
102
- if (op !== 'field' || !field) { if (onMissing) onMissing(`this.${field}`); return undefined }
103
- const val = resolvePath(triggerEntry ?? {}, field)
104
- if (val === undefined && onMissing) onMissing(`this.${field}`)
105
- return val
106
- }
107
-
108
- if (scope === 'batch') {
109
- if (op === 'field') {
110
- if (!field) { if (onMissing) onMissing('batch.field'); return undefined }
111
- const val = resolvePath(batchEntries[0] ?? {}, field)
112
- if (val === undefined && onMissing) onMissing(`batch.${field}`)
113
- return val
114
- }
115
- return applyAggregate(op, field, batchEntries, onMissing)
116
- }
117
-
118
- if (onMissing) onMissing(scope)
119
- return undefined
120
- }
121
-
122
- return { lookup, triggerEntry }
123
- }
124
-
125
- export function deriveEntryContext(
126
- base: ResolvedContext,
127
- entry: Record<string, unknown>,
128
- ): ResolvedContext {
129
- return {
130
- lookup(parsed: ParsedKey, onMissing?: (field: string) => void): unknown {
131
- if (parsed.kind === 'simple') {
132
- if (parsed.path.startsWith('this.')) {
133
- const field = parsed.path.slice(5)
134
- const val = resolvePath(entry, field)
135
- if (val === undefined && onMissing) onMissing(parsed.path)
136
- return val
137
- }
138
- const val = resolvePath(entry, parsed.path)
139
- if (val === undefined && onMissing) onMissing(parsed.path)
140
- return val
141
- }
142
- if (parsed.kind === 'scoped' && parsed.scope === 'this') {
143
- if (parsed.op !== 'field' || !parsed.field) { if (onMissing) onMissing('this.field'); return undefined }
144
- const val = resolvePath(entry, parsed.field)
145
- if (val === undefined && onMissing) onMissing(`this.${parsed.field}`)
146
- return val
147
- }
148
- return base.lookup(parsed, onMissing)
149
- },
150
- triggerEntry: entry,
151
- }
152
- }
@@ -1,140 +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 {
6
- Automation,
7
- ContentRepository,
8
- FilterGroup,
9
- IAutomationRepository,
10
- IIdGenerator,
11
- Seed,
12
- } from '@beechcms/core'
13
- import { cronMatches } from './cron-runner.utils'
14
- import { executeAction } from './action-executors'
15
- import { resolveAutomationContext, deriveEntryContext } from './context-resolver'
16
- import { extractPushdownFilters } from './when-pushdown'
17
- import { evaluateWhen } from './when-evaluator'
18
-
19
- export interface CronRunnerDeps {
20
- automationRepository: IAutomationRepository
21
- contentRepository: ContentRepository
22
- getSeed: (slug: string) => Seed | null
23
- env: Record<string, string | undefined>
24
- idGenerator: IIdGenerator
25
- }
26
-
27
- // These actions mutate individual entries and must run once per entry.
28
- // All other actions (send_mail, webhook) run once per automation with a batch context.
29
- const PER_ENTRY_ACTIONS = new Set(['edit_field', 'create_entry'])
30
-
31
- export async function runCronAutomations(
32
- deps: CronRunnerDeps,
33
- scheduledTime: number,
34
- ): Promise<void> {
35
- console.log(`[cron] Starting runCronAutomations at scheduledTime: ${new Date(scheduledTime).toISOString()}`)
36
-
37
- let automations: Automation[]
38
- try {
39
- automations = await deps.automationRepository.findActive('*', 'cron')
40
- } catch (err) {
41
- console.error('[cron] Failed to fetch automations — is migration 0029_automations.sql applied?', err)
42
- return
43
- }
44
-
45
- console.log(`[cron] Found ${automations.length} active cron automation(s)`)
46
-
47
- for (const automation of automations) {
48
- const cronTrigger = automation.triggers.find((t) => t.event === 'cron')
49
- if (!cronMatches(cronTrigger?.cron ?? null, scheduledTime)) {
50
- console.log(`[cron] Skipping "${automation.name}": cron expression "${cronTrigger?.cron}" does not match.`)
51
- continue
52
- }
53
-
54
- const seed = deps.getSeed(automation.seed_slug)
55
- if (!seed) {
56
- console.warn('[cron] unknown seed', { automationId: automation.id, seedSlug: automation.seed_slug })
57
- continue
58
- }
59
-
60
- let entries: Array<Record<string, unknown>> = []
61
- try {
62
- entries = await fetchMatchingEntries(deps.contentRepository, seed, automation)
63
- console.log(`[cron] Fetched ${entries.length} matching entries for automation "${automation.name}"`)
64
- } catch (err) {
65
- console.error('[cron] fetch entries failed', { automationId: automation.id, err })
66
- continue
67
- }
68
-
69
- if (entries.length === 0) continue
70
-
71
- // Build the base ResolvedContext once per automation (shared seed-query cache).
72
- // triggerEntry = first entry; batchEntries = full SQL-filtered list.
73
- const batchResolved = await resolveAutomationContext(
74
- automation,
75
- entries[0] ?? null,
76
- entries,
77
- )
78
-
79
- const variables: Record<string, unknown> = {}
80
- const baseCtx = {
81
- env: deps.env,
82
- repository: deps.contentRepository,
83
- getSeed: deps.getSeed,
84
- seed,
85
- idGenerator: deps.idGenerator,
86
- variables,
87
- }
88
-
89
- for (const action of automation.actions) {
90
- if (PER_ENTRY_ACTIONS.has(action.type)) {
91
- for (const entry of entries) {
92
- // Per-entry: derive a lightweight context whose `this` is the current entry.
93
- // Seed-query cache is reused from batchResolved.
94
- const entryResolved = deriveEntryContext(batchResolved, entry)
95
- // In-memory per-entry condition check (Task 13)
96
- if (!evaluateWhen(automation.trigger_conditions, entryResolved)) continue
97
- try {
98
- await executeAction(action, { ...baseCtx, entry, context: entryResolved })
99
- } catch (err) {
100
- console.error('[cron] entry action failed', {
101
- automationId: automation.id,
102
- entryId: entry['id'],
103
- actionType: action.type,
104
- err,
105
- })
106
- }
107
- }
108
- } else {
109
- // Batch actions run once per automation with the shared batch context.
110
- try {
111
- await executeAction(action, { ...baseCtx, entry: entries[0] ?? {}, context: batchResolved })
112
- } catch (err) {
113
- console.error('[cron] batch action failed', {
114
- automationId: automation.id,
115
- actionType: action.type,
116
- err,
117
- })
118
- }
119
- }
120
- }
121
- }
122
- }
123
-
124
- async function fetchMatchingEntries(
125
- repository: ContentRepository,
126
- seed: Seed,
127
- automation: Automation,
128
- ): Promise<Array<Record<string, unknown>>> {
129
- // Task 12: push down only safe predicates to SQL (this.<field> = literal, AND group only).
130
- // OR branches, cross-seed refs, and gte/lte/etc. ops are evaluated in-memory by evaluateWhen().
131
- const filters: FilterGroup[] = automation.trigger_conditions
132
- ? extractPushdownFilters(automation.trigger_conditions, seed)
133
- : []
134
- const result = await repository.findMany(seed, {
135
- filters,
136
- status: null,
137
- pagination: { limit: 1000, offset: 0 },
138
- })
139
- return result.items
140
- }