@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,44 +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 function cronMatches(expression: string | null, scheduledTime: number): boolean {
6
- if (!expression) return false
7
- const parts = expression.trim().split(/\s+/)
8
- if (parts.length !== 5) return false
9
-
10
- const d = new Date(scheduledTime)
11
- const actual = [
12
- d.getUTCMinutes(),
13
- d.getUTCHours(),
14
- d.getUTCDate(),
15
- d.getUTCMonth() + 1,
16
- d.getUTCDay(),
17
- ] as const
18
-
19
- return parts.every((field, i) => matchField(field, actual[i]))
20
- }
21
-
22
- function matchField(field: string, value: number): boolean {
23
- if (field === '*') return true
24
- if (field.includes(',')) {
25
- return field.split(',').some((part) => matchField(part, value))
26
- }
27
- if (field.includes('/')) {
28
- const [rangePart, stepPart] = field.split('/')
29
- const step = Number(stepPart)
30
- if (!Number.isFinite(step) || step <= 0) return false
31
- if (rangePart === '*') return value % step === 0
32
- if (rangePart.includes('-')) {
33
- const [lo, hi] = rangePart.split('-').map(Number)
34
- return value >= lo && value <= hi && (value - lo) % step === 0
35
- }
36
- return false
37
- }
38
- if (field.includes('-')) {
39
- const [lo, hi] = field.split('-').map(Number)
40
- return Number.isFinite(lo) && Number.isFinite(hi) && value >= lo && value <= hi
41
- }
42
- const n = Number(field)
43
- return Number.isFinite(n) && n === value
44
- }
@@ -1,46 +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 helper: converts a TriggerCondition into a FilterGroup accepted by
7
- * ContentRepository.findMany. Used by cron-runner and context-resolver.
8
- *
9
- * TODO Sprint 8 (Task 12): when-pushdown.ts will call extractPushdownFilters
10
- * to convert safe WhenNode predicates to FilterGroup[] for SQL pre-filtering.
11
- */
12
- import type { BranchType, FilterGroup, FilterOperator, FilterType, Seed, TriggerCondition } from '@beechcms/core'
13
-
14
- const SYSTEM_COLUMNS = new Set(['id', 'slug', 'status', 'created_at', 'updated_at'])
15
-
16
- function mapBranchTypeToFilterType(type: BranchType): FilterType {
17
- switch (type) {
18
- case 'number': return 'number'
19
- case 'boolean': return 'boolean'
20
- case 'date': return 'date'
21
- case 'tags': return 'tags'
22
- case 'json': return 'json'
23
- default: return 'text'
24
- }
25
- }
26
-
27
- function mapOp(op: TriggerCondition['op']): FilterOperator {
28
- switch (op) {
29
- case 'isempty': return 'is_empty'
30
- case 'isnotempty': return 'is_not_empty'
31
- default: return op
32
- }
33
- }
34
-
35
- export function conditionToFilterGroup(c: TriggerCondition, seed: Seed): FilterGroup {
36
- const branch = seed.branches.find((b) => b.alias === c.field)
37
- const type: FilterType = branch
38
- ? mapBranchTypeToFilterType(branch.type)
39
- : SYSTEM_COLUMNS.has(c.field) ? 'system' : 'text'
40
-
41
- return {
42
- column: c.field,
43
- type,
44
- conditions: [{ op: mapOp(c.op), value: c.value as string | number | boolean | null }],
45
- }
46
- }
@@ -1,16 +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 { AutomationRunner } from './automation-runner'
6
- export type { AutomationRunnerDeps } from './automation-runner'
7
- export { runCronAutomations } from './cron-runner'
8
- export type { CronRunnerDeps } from './cron-runner'
9
- export { automationsApp } from './automations.handler'
10
- export {
11
- createAutomationSchema,
12
- updateAutomationSchema,
13
- toggleAutomationSchema,
14
- automationActionSchema,
15
- } from './automations.schema'
16
- export type { CreateAutomationBody, UpdateAutomationBody } from './automations.schema'
@@ -1,245 +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
- * Pure template-key parser for the automation template engine.
7
- *
8
- * Grammar (Sprint 6):
9
- * simple: {{title}}, {{author.name}}
10
- * scoped: {{<scope>:<selector>:<field>}}
11
- *
12
- * Grammar (Sprint 7):
13
- * var_access: {{varname.firstone.campo}}, {{varname.count.(status=paid)}}
14
- * {{varname.array[id1,id2].count}}
15
- *
16
- * Scopes: this | batch | <seedSlug> | <contextKey>
17
- * Selectors: lastone | firstone | all | byid(<id>) | where(<alias>=<value>)
18
- * Fields: branch alias, system column, or aggregate (count/sum/avg/min/max/pluck)
19
- *
20
- * Sugar:
21
- * {{batch:count}} → batch:all:count
22
- * {{<scope>:<field>}} → <scope>:lastone:<field> (default selector)
23
- *
24
- * TODO Sprint 8: extend ParsedKey to support WhenOperand refs once the
25
- * recursive when-group evaluator (Tasks 10-16) is implemented.
26
- */
27
-
28
- export { AUTOMATION_RESERVED_WORDS } from '@beechcms/core'
29
-
30
- // ---------------------------------------------------------------------------
31
- // Sprint 7 types: var_access parsed key
32
- // ---------------------------------------------------------------------------
33
-
34
- export type VarStep =
35
- | { type: 'field'; name: string }
36
- | { type: 'nav'; nav: 'firstone' | 'lastone' }
37
- | { type: 'agg'; op: 'count' | 'sum' | 'avg' | 'min' | 'max' | 'pluck'; field?: string }
38
- | { type: 'array'; ids: string[] }
39
-
40
- export interface InlineCondition {
41
- column: string
42
- op: '=' | '!=' | '<' | '>' | '<=' | '>='
43
- value: string
44
- }
45
-
46
- // ---------------------------------------------------------------------------
47
-
48
- export type AutomationContextSelector =
49
- | { kind: 'lastone' }
50
- | { kind: 'firstone' }
51
- | { kind: 'all' }
52
- | { kind: 'byid'; id: string }
53
- | { kind: 'where'; alias: string; value: string }
54
-
55
- export type AggregateOp = 'count' | 'sum' | 'avg' | 'min' | 'max' | 'pluck'
56
-
57
- export type ParsedKey =
58
- | { kind: 'simple'; path: string }
59
- | {
60
- kind: 'scoped'
61
- scope: string
62
- selector: AutomationContextSelector
63
- op: 'field' | AggregateOp
64
- field: string | null
65
- }
66
- | {
67
- kind: 'var_access'
68
- name: string
69
- steps: VarStep[]
70
- conditions: InlineCondition[]
71
- }
72
-
73
- const SLUG_RE = /^[a-zA-Z0-9_-]+$/
74
- const AGGREGATE_OPS = new Set<string>(['count', 'sum', 'avg', 'min', 'max', 'pluck'])
75
- const NAV_OPS = new Set<string>(['firstone', 'lastone'])
76
- const INLINE_COND_RE = /^\(([\w]+)\s*(=|!=|<=|>=|<|>)\s*([^)]+)\)$/
77
-
78
- /**
79
- * Split `raw` on `:` but treat content inside `(...)` as atomic.
80
- */
81
- function splitKey(raw: string): string[] {
82
- const tokens: string[] = []
83
- let depth = 0
84
- let current = ''
85
-
86
- for (const ch of raw) {
87
- if (ch === '(') {
88
- depth++
89
- current += ch
90
- } else if (ch === ')') {
91
- depth--
92
- current += ch
93
- } else if (ch === ':' && depth === 0) {
94
- tokens.push(current)
95
- current = ''
96
- } else {
97
- current += ch
98
- }
99
- }
100
- if (current) tokens.push(current)
101
- return tokens
102
- }
103
-
104
- /**
105
- * Split `raw` on `.` treating `[...]` and `(...)` as atomic blocks.
106
- */
107
- function splitDot(raw: string): string[] {
108
- const tokens: string[] = []
109
- let depth = 0
110
- let current = ''
111
-
112
- for (const ch of raw) {
113
- if (ch === '[' || ch === '(') {
114
- depth++
115
- current += ch
116
- } else if (ch === ']' || ch === ')') {
117
- depth--
118
- current += ch
119
- } else if (ch === '.' && depth === 0) {
120
- tokens.push(current)
121
- current = ''
122
- } else {
123
- current += ch
124
- }
125
- }
126
- if (current) tokens.push(current)
127
- return tokens
128
- }
129
-
130
- function parseSelector(token: string): AutomationContextSelector | null {
131
- if (token === 'lastone') return { kind: 'lastone' }
132
- if (token === 'firstone') return { kind: 'firstone' }
133
- if (token === 'all') return { kind: 'all' }
134
-
135
- const byidMatch = token.match(/^byid\((.+)\)$/)
136
- if (byidMatch) return { kind: 'byid', id: byidMatch[1] }
137
-
138
- const whereMatch = token.match(/^where\(([^=]+)=(.+)\)$/)
139
- if (whereMatch) return { kind: 'where', alias: whereMatch[1], value: whereMatch[2] }
140
-
141
- return null
142
- }
143
-
144
- function isKnownScope(token: string): boolean {
145
- return token === 'this' || token === 'batch' || SLUG_RE.test(token)
146
- }
147
-
148
- export function parseTemplateKey(raw: string): ParsedKey | null {
149
- if (!raw) return null
150
-
151
- const trimmed = raw.trim()
152
-
153
- // Step 1: if contains `:` at depth 0 → existing scoped / sugar logic
154
- const colonTokens = splitKey(trimmed)
155
- if (colonTokens.length > 1) {
156
- const [scopeToken, ...rest] = colonTokens
157
- if (!isKnownScope(scopeToken)) return null
158
-
159
- if (rest.length === 1) {
160
- const fieldOrAggregate = rest[0]
161
- if (AGGREGATE_OPS.has(fieldOrAggregate)) {
162
- return { kind: 'scoped', scope: scopeToken, selector: { kind: 'all' }, op: fieldOrAggregate as AggregateOp, field: null }
163
- }
164
- return { kind: 'scoped', scope: scopeToken, selector: { kind: 'lastone' }, op: 'field', field: fieldOrAggregate }
165
- }
166
-
167
- const selectorToken = rest[0]
168
- const selector = parseSelector(selectorToken)
169
- if (!selector) return null
170
-
171
- const fieldTokens = rest.slice(1)
172
- if (fieldTokens.length === 0) return null
173
-
174
- const opToken = fieldTokens[0]
175
- if (AGGREGATE_OPS.has(opToken)) {
176
- if (selector.kind !== 'all') return null
177
- const subField = fieldTokens[1] ?? null
178
- return { kind: 'scoped', scope: scopeToken, selector, op: opToken as AggregateOp, field: subField }
179
- }
180
-
181
- return { kind: 'scoped', scope: scopeToken, selector, op: 'field', field: opToken }
182
- }
183
-
184
- // Step 2: tokenise on `.` at depth 0
185
- const dotTokens = splitDot(trimmed)
186
-
187
- // Step 3: if no token contains `[` or `(`, return simple (fast path)
188
- if (!dotTokens.some((t) => t.includes('[') || t.includes('('))) {
189
- return { kind: 'simple', path: trimmed }
190
- }
191
-
192
- // Step 4: build var_access
193
- const [nameToken, ...stepTokens] = dotTokens
194
- const steps: VarStep[] = []
195
- const conditions: InlineCondition[] = []
196
-
197
- let i = 0
198
- while (i < stepTokens.length) {
199
- const token = stepTokens[i]
200
-
201
- // Inline condition: (col op val)
202
- const condMatch = token.match(INLINE_COND_RE)
203
- if (condMatch) {
204
- conditions.push({ column: condMatch[1], op: condMatch[2] as InlineCondition['op'], value: condMatch[3].trim() })
205
- i++
206
- continue
207
- }
208
-
209
- // Array selector: array[id1,id2,...]
210
- const arrayMatch = token.match(/^array\[([^\]]*)\]$/)
211
- if (arrayMatch) {
212
- const ids = arrayMatch[1].split(',').map((s) => s.trim()).filter(Boolean)
213
- steps.push({ type: 'array', ids })
214
- i++
215
- continue
216
- }
217
-
218
- // Nav: firstone / lastone
219
- if (NAV_OPS.has(token)) {
220
- steps.push({ type: 'nav', nav: token as 'firstone' | 'lastone' })
221
- i++
222
- continue
223
- }
224
-
225
- // Aggregate: count | sum | avg | min | max | pluck
226
- if (AGGREGATE_OPS.has(token)) {
227
- const nextToken = stepTokens[i + 1]
228
- // Consume the next token as field if it's a plain identifier (no special chars)
229
- if (nextToken && !nextToken.includes('[') && !nextToken.includes('(') && !AGGREGATE_OPS.has(nextToken) && !NAV_OPS.has(nextToken)) {
230
- steps.push({ type: 'agg', op: token as VarStep & { type: 'agg' } extends { op: infer O } ? O : never, field: nextToken })
231
- i += 2
232
- } else {
233
- steps.push({ type: 'agg', op: token as any })
234
- i++
235
- }
236
- continue
237
- }
238
-
239
- // Plain field
240
- steps.push({ type: 'field', name: token })
241
- i++
242
- }
243
-
244
- return { kind: 'var_access', name: nameToken, steps, conditions }
245
- }
@@ -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 { Seed } from '@beechcms/core'
6
- import type { ParsedKey, InlineCondition } from './template-grammar'
7
- import { materializeCollection } from './action-executors/set-variable.executor'
8
-
9
- type VarAccessParsed = Extract<ParsedKey, { kind: 'var_access' }>
10
-
11
- function toNumeric(v: unknown): number {
12
- const n = Number(v)
13
- if (Number.isFinite(n)) return n
14
- if (typeof v === 'string') {
15
- const d = Date.parse(v)
16
- if (!Number.isNaN(d)) return d / 1000
17
- }
18
- return NaN
19
- }
20
-
21
- function numericCoerce(a: unknown, b: unknown): { left: unknown; right: unknown } {
22
- const na = toNumeric(a)
23
- const nb = toNumeric(b)
24
- const numeric = Number.isFinite(na) || Number.isFinite(nb)
25
- return { left: numeric ? na : a, right: numeric ? nb : b }
26
- }
27
-
28
- function applyCondition(record: Record<string, unknown>, cond: InlineCondition): boolean {
29
- const raw = record[cond.column]
30
- const { left, right } = numericCoerce(raw, cond.value)
31
- switch (cond.op) {
32
- case '=': return left === right
33
- case '!=': return left !== right
34
- case '<': return (left as number) < (right as number)
35
- case '>': return (left as number) > (right as number)
36
- case '<=': return (left as number) <= (right as number)
37
- case '>=': return (left as number) >= (right as number)
38
- }
39
- }
40
-
41
- function applyConditions(
42
- record: Record<string, unknown>,
43
- conditions: InlineCondition[],
44
- ): boolean {
45
- return conditions.every((c) => applyCondition(record, c))
46
- }
47
-
48
- function filterItems(
49
- items: Array<Record<string, unknown>>,
50
- conditions: InlineCondition[],
51
- ): Array<Record<string, unknown>> {
52
- if (conditions.length === 0) return items
53
- return items.filter((r) => applyConditions(r, conditions))
54
- }
55
-
56
- function getItems(value: unknown): Array<Record<string, unknown>> | null {
57
- if (!value || typeof value !== 'object') return null
58
- const items = (value as any)['_items']
59
- return Array.isArray(items) ? items : null
60
- }
61
-
62
- const EMPTY_SEED = { branches: [] } as unknown as Seed
63
-
64
- export function resolveVarAccess(
65
- parsed: VarAccessParsed,
66
- variables: Record<string, unknown>,
67
- onMissing?: (field: string) => void,
68
- ): unknown {
69
- if (!(parsed.name in variables)) {
70
- onMissing?.(parsed.name)
71
- return undefined
72
- }
73
-
74
- let current: unknown = variables[parsed.name]
75
- const { steps, conditions } = parsed
76
-
77
- for (let i = 0; i < steps.length; i++) {
78
- const step = steps[i]
79
-
80
- // ── array selector ─────────────────────────────────────────────────────
81
- if (step.type === 'array') {
82
- const items = getItems(current) ?? (Array.isArray(current) ? current as Array<Record<string, unknown>> : null)
83
- if (!items) return undefined
84
- const idSet = new Set(step.ids)
85
- const subset = items.filter((r) => idSet.has(String(r['id'] ?? '')))
86
- // Apply conditions to the subset before building the collection
87
- const filtered = filterItems(subset, conditions)
88
- current = materializeCollection(EMPTY_SEED, filtered, null)
89
- // Conditions consumed — no post-filter needed
90
- continue
91
- }
92
-
93
- // ── nav: firstone / lastone ────────────────────────────────────────────
94
- if (step.type === 'nav') {
95
- // Nav moves us from a collection to a single record.
96
- // Conditions are a guard on that record, NOT a pre-filter on _items.
97
- const record = (current as any)?.[step.nav] as Record<string, unknown> | null | undefined
98
- if (!record) { current = null; continue }
99
- // Apply conditions to the single record (post-filter)
100
- if (conditions.length > 0 && !applyConditions(record, conditions)) return undefined
101
- current = record
102
- continue
103
- }
104
-
105
- // ── aggregate ──────────────────────────────────────────────────────────
106
- if (step.type === 'agg') {
107
- // Apply conditions to _items before aggregating
108
- const items = getItems(current)
109
- if (items !== null) {
110
- const filtered = filterItems(items, conditions)
111
- current = materializeCollection(EMPTY_SEED, filtered, null)
112
- }
113
- if (step.op === 'count') {
114
- current = (current as any)?.['count']
115
- } else if (step.field) {
116
- const sub = (current as any)?.[step.op]
117
- current = typeof sub === 'object' && sub !== null ? sub[step.field] : sub
118
- } else {
119
- current = (current as any)?.[step.op]
120
- }
121
- // Conditions consumed by filtering _items
122
- return current
123
- }
124
-
125
- // ── field access ───────────────────────────────────────────────────────
126
- if (step.type === 'field') {
127
- current = (current as any)?.[step.name]
128
- }
129
- }
130
-
131
- // Post-filter on single record (conditions not consumed by agg or array)
132
- if (conditions.length > 0 && current !== null && current !== undefined) {
133
- if (typeof current === 'object' && !Array.isArray(current)) {
134
- if (!applyConditions(current as Record<string, unknown>, conditions)) return undefined
135
- }
136
- // For scalar values: conditions cannot be checked — pass through
137
- }
138
-
139
- return current
140
- }
@@ -1,87 +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 { WhenNode, WhenPredicate, WhenGroup, WhenOperand } from '@beechcms/core'
6
- import type { ResolvedContext } from './context-resolver'
7
- import { parseTemplateKey } from './template-grammar'
8
-
9
- export function evaluateWhen(
10
- node: WhenNode | null,
11
- context: ResolvedContext,
12
- ): boolean {
13
- if (!node) return true
14
- if (node.kind === 'predicate') return evalPredicate(node, context)
15
- return evalGroup(node, context)
16
- }
17
-
18
- function evalGroup(group: WhenGroup, context: ResolvedContext): boolean {
19
- if (group.children.length === 0) {
20
- const empty = group.op === 'AND'
21
- return group.negate ? !empty : empty
22
- }
23
-
24
- for (const child of group.children) {
25
- const r = evaluateWhen(child, context)
26
- if (group.op === 'AND' && !r) return group.negate ? true : false
27
- if (group.op === 'OR' && r) return group.negate ? false : true
28
- }
29
-
30
- const combined = group.op === 'AND'
31
- return group.negate ? !combined : combined
32
- }
33
-
34
- function resolveOperand(operand: WhenOperand, context: ResolvedContext): unknown {
35
- if (operand.kind === 'literal') return operand.value
36
-
37
- // this.field (dot notation from UI) → this:field (colon, parsed as scoped key)
38
- const key = operand.key.startsWith('this.') ? 'this:' + operand.key.slice(5) : operand.key
39
- const parsed = parseTemplateKey(key)
40
- if (!parsed) return null
41
-
42
- const val = context.lookup(parsed)
43
- return val ?? null
44
- }
45
-
46
- function evalPredicate(pred: WhenPredicate, context: ResolvedContext): boolean {
47
- const left = resolveOperand(pred.left, context)
48
- const right = pred.right !== undefined ? resolveOperand(pred.right, context) : undefined
49
- return compare(pred.op, left, right)
50
- }
51
-
52
- function compare(op: string, left: unknown, right: unknown): boolean {
53
- switch (op) {
54
- case 'isempty': return left == null || left === ''
55
- case 'isnotempty': return left != null && left !== ''
56
-
57
- case 'eq': return coerceEqual(left, right)
58
- case 'neq': return !coerceEqual(left, right)
59
-
60
- case 'gt': return Number(left) > Number(right)
61
- case 'gte': return Number(left) >= Number(right)
62
- case 'lt': return Number(left) < Number(right)
63
- case 'lte': return Number(left) <= Number(right)
64
-
65
- case 'contains': return typeof left === 'string' && typeof right === 'string' && left.includes(right)
66
- case 'startswith': return typeof left === 'string' && typeof right === 'string' && left.startsWith(right)
67
- case 'endswith': return typeof left === 'string' && typeof right === 'string' && left.endsWith(right)
68
-
69
- case 'in': return Array.isArray(right) && right.some((r) => coerceEqual(left, r))
70
- case 'notin': return !Array.isArray(right) || !right.some((r) => coerceEqual(left, r))
71
-
72
- case 'matches': {
73
- if (typeof left !== 'string' || typeof right !== 'string') return false
74
- try { return new RegExp(right).test(left) } catch { return false }
75
- }
76
-
77
- default: return false
78
- }
79
- }
80
-
81
- function coerceEqual(a: unknown, b: unknown): boolean {
82
- if (a === null && b === null) return true
83
- if (a === null || b === null) return false
84
- if (typeof a === 'number' && typeof b === 'string' && !Number.isNaN(Number(b))) return a === Number(b)
85
- if (typeof b === 'number' && typeof a === 'string' && !Number.isNaN(Number(a))) return Number(a) === b
86
- return a === b
87
- }
@@ -1,57 +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 { WhenNode, WhenPredicate, TriggerCondition, FilterGroup, Seed } from '@beechcms/core'
6
- import { conditionToFilterGroup } from './filter-translation'
7
-
8
- const PUSHDOWN_OPS = new Set<string>(['eq', 'neq', 'contains', 'gt', 'lt', 'isempty', 'isnotempty'])
9
-
10
- export function extractPushdownFilters(
11
- node: WhenNode | null,
12
- seed: Seed,
13
- ): FilterGroup[] {
14
- if (!node) return []
15
-
16
- // Single predicate at root
17
- if (node.kind === 'predicate') {
18
- const f = tryPushdown(node, seed)
19
- return f ? [f] : []
20
- }
21
-
22
- // Only extract direct predicate children of the outermost AND group (non-negated)
23
- if (node.kind === 'group' && node.op === 'AND' && !node.negate) {
24
- return node.children.flatMap((child) => {
25
- if (child.kind !== 'predicate') return []
26
- const f = tryPushdown(child, seed)
27
- return f ? [f] : []
28
- })
29
- }
30
-
31
- return []
32
- }
33
-
34
- function tryPushdown(pred: WhenPredicate, seed: Seed): FilterGroup | null {
35
- if (pred.left.kind !== 'ref') return null
36
-
37
- const key = pred.left.key
38
- if (!key.startsWith('this.')) return null
39
- const field = key.slice(5)
40
- if (!field) return null
41
-
42
- if (!PUSHDOWN_OPS.has(pred.op)) return null
43
-
44
- if (pred.op === 'isempty' || pred.op === 'isnotempty') {
45
- return conditionToFilterGroup(
46
- { field, op: pred.op as TriggerCondition['op'], value: null },
47
- seed,
48
- )
49
- }
50
-
51
- if (!pred.right || pred.right.kind !== 'literal') return null
52
-
53
- return conditionToFilterGroup(
54
- { field, op: pred.op as TriggerCondition['op'], value: pred.right.value },
55
- seed,
56
- )
57
- }