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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/README.md +4 -4
  2. package/assets/dashboard/BeechLogo.svg +18 -18
  3. package/assets/dashboard/BeechLogoLIght.svg +48 -48
  4. package/assets/dashboard/assets/chart-Cws4Yj6K.js +39 -0
  5. package/assets/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  6. package/assets/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  7. package/assets/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  8. package/assets/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  9. package/assets/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  10. package/assets/dashboard/assets/index-BjPpppHe.css +1 -0
  11. package/assets/dashboard/assets/index-CrW-zhkA.js +642 -0
  12. package/assets/dashboard/assets/lora-cyrillic-ext-wght-normal-YcVxMP-u.woff2 +0 -0
  13. package/assets/dashboard/assets/lora-cyrillic-wght-normal-UWPuZLjM.woff2 +0 -0
  14. package/assets/dashboard/assets/lora-latin-ext-wght-normal-C2Wlntb9.woff2 +0 -0
  15. package/assets/dashboard/assets/lora-latin-wght-normal-BiLcIKcI.woff2 +0 -0
  16. package/assets/dashboard/assets/lora-math-wght-normal-sOy7rEfW.woff2 +0 -0
  17. package/assets/dashboard/assets/lora-symbols-wght-normal-DQ5VrUkH.woff2 +0 -0
  18. package/assets/dashboard/assets/lora-vietnamese-wght-normal-CfJ7gtf3.woff2 +0 -0
  19. package/assets/dashboard/assets/pie-chart-recharts-CAxoDQp2.js +1 -0
  20. package/assets/dashboard/assets/timeseries-chart-recharts-CixDW-LM.js +1 -0
  21. package/assets/dashboard/beechLogoDark.svg +48 -48
  22. package/assets/dashboard/index.html +18 -18
  23. package/assets/dashboard/noResult.svg +42 -42
  24. package/assets/dashboard/sol.svg +3 -3
  25. package/assets/dashboard/undraw_enter_nwx3.svg +36 -36
  26. package/dist/auth/__fixtures__/in-memory-hash-provider.d.ts +5 -0
  27. package/dist/auth/__fixtures__/static-token-service.d.ts +6 -0
  28. package/dist/auth/bcrypt-hash-provider.d.ts +8 -0
  29. package/dist/auth/constants.d.ts +10 -0
  30. package/dist/auth/jose-token-service.d.ts +14 -0
  31. package/dist/auth/login.d.ts +32 -0
  32. package/dist/auth/refresh.d.ts +1 -0
  33. package/dist/factory.d.ts +39 -0
  34. package/dist/features/automations/action-executors/create-entry.executor.d.ts +7 -0
  35. package/dist/features/automations/action-executors/edit-field.executor.d.ts +7 -0
  36. package/dist/features/automations/action-executors/index.d.ts +13 -0
  37. package/dist/features/automations/action-executors/send-mail.executor.d.ts +7 -0
  38. package/dist/features/automations/action-executors/set-variable.executor.d.ts +15 -0
  39. package/dist/features/automations/action-executors/webhook.executor.d.ts +7 -0
  40. package/dist/features/automations/automation-runner.d.ts +13 -0
  41. package/dist/features/automations/automation-runner.utils.d.ts +3 -0
  42. package/dist/features/automations/automations.handler.d.ts +7 -0
  43. package/dist/features/automations/automations.schema.d.ts +191 -0
  44. package/dist/features/automations/context-resolver.d.ts +8 -0
  45. package/dist/features/automations/cron-runner.d.ts +9 -0
  46. package/dist/features/automations/cron-runner.utils.d.ts +1 -0
  47. package/dist/features/automations/filter-translation.d.ts +9 -0
  48. package/dist/features/automations/index.d.ts +7 -0
  49. package/dist/features/automations/template-grammar.d.ts +73 -0
  50. package/dist/features/automations/var-access-resolver.d.ts +6 -0
  51. package/dist/features/automations/when-evaluator.d.ts +3 -0
  52. package/dist/features/automations/when-pushdown.d.ts +2 -0
  53. package/dist/features/backrefs/backrefs.handler.d.ts +3 -0
  54. package/dist/features/backrefs/d1-backref.repository.d.ts +17 -0
  55. package/dist/features/backrefs/index.d.ts +1 -0
  56. package/dist/features/content/constants.d.ts +12 -0
  57. package/dist/features/content/handlers/bulk.handler.d.ts +3 -0
  58. package/dist/features/content/handlers/create.d.ts +3 -0
  59. package/dist/features/content/handlers/delete.d.ts +3 -0
  60. package/dist/features/content/handlers/facets.d.ts +3 -0
  61. package/dist/features/content/handlers/get.d.ts +4 -0
  62. package/dist/features/content/handlers/helpers.d.ts +12 -0
  63. package/dist/features/content/handlers/list.d.ts +3 -0
  64. package/dist/features/content/handlers/update.d.ts +3 -0
  65. package/dist/features/content/index.d.ts +4 -0
  66. package/dist/features/dashboard-layout/dashboard-layout.handler.d.ts +7 -0
  67. package/dist/features/dashboard-layout/index.d.ts +1 -0
  68. package/dist/features/draft/draft.handler.d.ts +4 -0
  69. package/dist/features/draft/draft.middleware.d.ts +9 -0
  70. package/dist/features/draft/index.d.ts +1 -0
  71. package/{src/features/email/email.provider.ts → dist/features/email/email.provider.d.ts} +37 -42
  72. package/dist/features/email/email.service.d.ts +13 -0
  73. package/dist/features/email/email.types.d.ts +94 -0
  74. package/{src/features/email/index.ts → dist/features/email/index.d.ts} +20 -33
  75. package/dist/features/email/providers/resend.d.ts +36 -0
  76. package/dist/features/email/providers/smtp.d.ts +11 -0
  77. package/dist/features/email/templates/automation-mail.d.ts +8 -0
  78. package/dist/features/email/templates/password-changed.d.ts +15 -0
  79. package/dist/features/email/templates/password-reset.d.ts +18 -0
  80. package/dist/features/email/templates/shell.d.ts +58 -0
  81. package/dist/features/notifications/index.d.ts +1 -0
  82. package/dist/features/notifications/notifications.handler.d.ts +15 -0
  83. package/dist/features/password-reset/index.d.ts +6 -0
  84. package/dist/features/password-reset/request.d.ts +10 -0
  85. package/dist/features/password-reset/reset.d.ts +9 -0
  86. package/dist/features/rotate-field/index.d.ts +1 -0
  87. package/dist/features/rotate-field/rotate-field.handler.d.ts +7 -0
  88. package/dist/features/rotate-field/rotate-field.schema.d.ts +11 -0
  89. package/dist/features/schema/schema.handler.d.ts +7 -0
  90. package/dist/features/seeds/index.d.ts +1 -0
  91. package/dist/features/seeds/seeds.handler.d.ts +6 -0
  92. package/dist/features/settings/settings.handler.d.ts +7 -0
  93. package/dist/features/setup/index.d.ts +7 -0
  94. package/dist/features/stats/index.d.ts +1 -0
  95. package/dist/features/stats/stats.handler.d.ts +7 -0
  96. package/dist/features/webhooks/index.d.ts +3 -0
  97. package/dist/index.d.ts +6 -0
  98. package/dist/index.js +9666 -0
  99. package/dist/media-utils.d.ts +25 -0
  100. package/dist/middleware/auth-providers.middleware.d.ts +8 -0
  101. package/dist/middleware/observability.middleware.d.ts +20 -0
  102. package/dist/middleware/rate-limit.middleware.d.ts +9 -0
  103. package/dist/middleware/repository.middleware.d.ts +34 -0
  104. package/dist/middleware/seed-registry.middleware.d.ts +10 -0
  105. package/dist/middleware/storage.middleware.d.ts +7 -0
  106. package/dist/middleware.d.ts +11 -0
  107. package/dist/public/access-policy.d.ts +12 -0
  108. package/dist/public/api-key-middleware.d.ts +6 -0
  109. package/dist/public/cache-utils.d.ts +10 -0
  110. package/dist/public/entry-projection.d.ts +2 -0
  111. package/dist/public/idempotency.d.ts +9 -0
  112. package/dist/public/index.d.ts +11 -0
  113. package/dist/public/problem-details.d.ts +31 -0
  114. package/dist/public/public-add.d.ts +3 -0
  115. package/dist/public/public-edit.d.ts +5 -0
  116. package/dist/public/public-errors.d.ts +13 -0
  117. package/dist/public/public-read.d.ts +3 -0
  118. package/dist/public/public-routes.d.ts +3 -0
  119. package/dist/public/query-builder.d.ts +28 -0
  120. package/dist/public/rate-limit-middleware.d.ts +3 -0
  121. package/dist/public/read-list.d.ts +26 -0
  122. package/dist/public/read-single.d.ts +22 -0
  123. package/dist/public/response-builder.d.ts +22 -0
  124. package/dist/public/sanitize.d.ts +23 -0
  125. package/dist/public/slug-utils.d.ts +11 -0
  126. package/dist/rate-limit/cloudflare-rate-limiter.d.ts +6 -0
  127. package/dist/rate-limit/in-memory-rate-limiter.d.ts +7 -0
  128. package/dist/rate-limit/no-op-rate-limiter.d.ts +4 -0
  129. package/dist/search-utils.d.ts +54 -0
  130. package/dist/search.d.ts +6 -0
  131. package/dist/shared/apply-policies.d.ts +10 -0
  132. package/dist/shared/automations.repository.d1.d.ts +12 -0
  133. package/dist/shared/background-notification-service.d.ts +18 -0
  134. package/dist/shared/base.repository.d1.d.ts +18 -0
  135. package/dist/shared/content-utils.d.ts +21 -0
  136. package/dist/shared/content.repository.d1.d.ts +68 -0
  137. package/dist/shared/d1-activity-log.repository.d.ts +13 -0
  138. package/dist/shared/d1-activity-logger.d.ts +20 -0
  139. package/dist/shared/d1-analytics.repository.d.ts +20 -0
  140. package/dist/shared/d1-content-scan.repository.d.ts +7 -0
  141. package/dist/shared/d1-notification.repository.d.ts +17 -0
  142. package/dist/shared/d1-password-reset-token.repository.d.ts +10 -0
  143. package/dist/shared/d1-search.repository.d.ts +14 -0
  144. package/dist/shared/d1-session.repository.d.ts +12 -0
  145. package/dist/shared/d1-setup-checklist.repository.d.ts +12 -0
  146. package/dist/shared/d1-user.repository.d.ts +18 -0
  147. package/dist/shared/d1-widget.repository.d.ts +31 -0
  148. package/dist/shared/dashboard-layout.repository.d1.d.ts +9 -0
  149. package/dist/shared/demo-data-sql.d.ts +1 -0
  150. package/dist/shared/demo-data.repository.d1.d.ts +6 -0
  151. package/dist/shared/execution-context-scheduler.d.ts +6 -0
  152. package/dist/shared/fixed-clock.d.ts +13 -0
  153. package/dist/shared/fts-sync.d.ts +1 -0
  154. package/dist/shared/idempotency.repository.d1.d.ts +16 -0
  155. package/dist/shared/in-memory-activity-logger.d.ts +11 -0
  156. package/dist/shared/in-memory-notification-service.d.ts +11 -0
  157. package/dist/shared/in-memory-seed.repository.d.ts +18 -0
  158. package/dist/shared/media.repository.d1.d.ts +35 -0
  159. package/dist/shared/qstash-notification-service.d.ts +18 -0
  160. package/dist/shared/query-utils.d.ts +36 -0
  161. package/dist/shared/request-utils.d.ts +13 -0
  162. package/dist/shared/schema-mutator.d1.d.ts +12 -0
  163. package/dist/shared/seed-layout.repository.d1.d.ts +9 -0
  164. package/dist/shared/seed-registry-cache.d.ts +12 -0
  165. package/dist/shared/seed.repository.d1.d.ts +13 -0
  166. package/dist/shared/sequential-id-generator.d.ts +13 -0
  167. package/dist/shared/site-settings.repository.d1.d.ts +7 -0
  168. package/dist/shared/storage/factory.d.ts +8 -0
  169. package/dist/shared/storage/s3-bucket.d.ts +43 -0
  170. package/dist/shared/storage-utils.d.ts +7 -0
  171. package/dist/shared/system-stats.repository.d1.d.ts +25 -0
  172. package/dist/types.d.ts +85 -0
  173. package/dist/upload.d.ts +16 -0
  174. package/dist/widget.d.ts +7 -0
  175. package/migrations/0000_v040_base.sql +265 -265
  176. package/migrations/0029_automations.sql +14 -14
  177. package/migrations/0030_test_seeds.sql +125 -125
  178. package/package.json +27 -18
  179. package/assets/dashboard/assets/index-BSjk0Sx9.js +0 -634
  180. package/assets/dashboard/assets/index-kRCYVN2B.css +0 -1
  181. package/src/auth/__fixtures__/in-memory-hash-provider.ts +0 -17
  182. package/src/auth/__fixtures__/static-token-service.ts +0 -22
  183. package/src/auth/bcrypt-hash-provider.ts +0 -24
  184. package/src/auth/constants.ts +0 -14
  185. package/src/auth/generate-refresh-token.test.ts +0 -23
  186. package/src/auth/hash-provider.test.ts +0 -55
  187. package/src/auth/jose-token-service.ts +0 -62
  188. package/src/auth/jwt-claims-passthrough.test.ts +0 -87
  189. package/src/auth/login.test.ts +0 -100
  190. package/src/auth/login.ts +0 -78
  191. package/src/auth/refresh.ts +0 -11
  192. package/src/auth/token-service.test.ts +0 -90
  193. package/src/factory.ts +0 -368
  194. package/src/features/automations/__tests__/action-executors.test.ts +0 -255
  195. package/src/features/automations/__tests__/automation-runner.test.ts +0 -196
  196. package/src/features/automations/__tests__/automation-runner.utils.test.ts +0 -60
  197. package/src/features/automations/__tests__/automations.handler.test.ts +0 -264
  198. package/src/features/automations/__tests__/automations.repository.test.ts +0 -163
  199. package/src/features/automations/__tests__/automations.schema.test.ts +0 -224
  200. package/src/features/automations/__tests__/context-resolver.test.ts +0 -126
  201. package/src/features/automations/__tests__/cron-runner.test.ts +0 -267
  202. package/src/features/automations/__tests__/cron-runner.utils.test.ts +0 -144
  203. package/src/features/automations/__tests__/set-variable.executor.test.ts +0 -383
  204. package/src/features/automations/__tests__/template-grammar.test.ts +0 -308
  205. package/src/features/automations/__tests__/webhook.executor.test.ts +0 -142
  206. package/src/features/automations/__tests__/when-evaluator.test.ts +0 -274
  207. package/src/features/automations/__tests__/when-pushdown.test.ts +0 -281
  208. package/src/features/automations/action-executors/create-entry.executor.ts +0 -27
  209. package/src/features/automations/action-executors/edit-field.executor.ts +0 -26
  210. package/src/features/automations/action-executors/index.ts +0 -37
  211. package/src/features/automations/action-executors/send-mail.executor.ts +0 -53
  212. package/src/features/automations/action-executors/set-variable.executor.ts +0 -159
  213. package/src/features/automations/action-executors/webhook.executor.ts +0 -67
  214. package/src/features/automations/automation-runner.ts +0 -85
  215. package/src/features/automations/automation-runner.utils.ts +0 -47
  216. package/src/features/automations/automations.handler.ts +0 -197
  217. package/src/features/automations/automations.schema.ts +0 -177
  218. package/src/features/automations/context-resolver.ts +0 -152
  219. package/src/features/automations/cron-runner.ts +0 -140
  220. package/src/features/automations/cron-runner.utils.ts +0 -44
  221. package/src/features/automations/filter-translation.ts +0 -46
  222. package/src/features/automations/index.ts +0 -16
  223. package/src/features/automations/template-grammar.ts +0 -245
  224. package/src/features/automations/var-access-resolver.ts +0 -140
  225. package/src/features/automations/when-evaluator.ts +0 -87
  226. package/src/features/automations/when-pushdown.ts +0 -57
  227. package/src/features/backrefs/__tests__/backrefs.handler.test.ts +0 -359
  228. package/src/features/backrefs/backrefs.handler.ts +0 -168
  229. package/src/features/backrefs/d1-backref.repository.ts +0 -84
  230. package/src/features/backrefs/index.ts +0 -5
  231. package/src/features/content/constants.ts +0 -16
  232. package/src/features/content/handlers/bulk.handler.ts +0 -185
  233. package/src/features/content/handlers/create.ts +0 -129
  234. package/src/features/content/handlers/delete.ts +0 -62
  235. package/src/features/content/handlers/facets.ts +0 -49
  236. package/src/features/content/handlers/get.ts +0 -120
  237. package/src/features/content/handlers/helpers.test.ts +0 -180
  238. package/src/features/content/handlers/helpers.ts +0 -93
  239. package/src/features/content/handlers/list.ts +0 -174
  240. package/src/features/content/handlers/update.ts +0 -174
  241. package/src/features/content/index.ts +0 -26
  242. package/src/features/draft/draft.handler.ts +0 -195
  243. package/src/features/draft/draft.middleware.ts +0 -66
  244. package/src/features/draft/index.ts +0 -5
  245. package/src/features/email/email.service.ts +0 -98
  246. package/src/features/email/email.types.ts +0 -119
  247. package/src/features/email/providers/resend.ts +0 -67
  248. package/src/features/email/providers/smtp.ts +0 -55
  249. package/src/features/email/templates/automation-mail.ts +0 -19
  250. package/src/features/email/templates/password-changed.ts +0 -63
  251. package/src/features/email/templates/password-reset.ts +0 -68
  252. package/src/features/email/templates/shell.ts +0 -96
  253. package/src/features/notifications/index.ts +0 -5
  254. package/src/features/notifications/notifications.handler.ts +0 -105
  255. package/src/features/password-reset/index.ts +0 -19
  256. package/src/features/password-reset/request.ts +0 -92
  257. package/src/features/password-reset/reset.ts +0 -102
  258. package/src/features/rotate-field/index.ts +0 -5
  259. package/src/features/rotate-field/rotate-field.handler.ts +0 -132
  260. package/src/features/rotate-field/rotate-field.schema.ts +0 -17
  261. package/src/features/schema/schema.handler.ts +0 -131
  262. package/src/features/seeds/index.ts +0 -5
  263. package/src/features/seeds/seeds.handler.test.ts +0 -632
  264. package/src/features/seeds/seeds.handler.ts +0 -693
  265. package/src/features/settings/__tests__/settings.handler.test.ts +0 -555
  266. package/src/features/settings/settings.handler.ts +0 -392
  267. package/src/features/setup/index.ts +0 -204
  268. package/src/features/stats/index.ts +0 -5
  269. package/src/features/stats/stats.handler.ts +0 -420
  270. package/src/features/webhooks/index.ts +0 -63
  271. package/src/index.ts +0 -65
  272. package/src/media-utils.ts +0 -82
  273. package/src/middleware/auth-providers.middleware.ts +0 -45
  274. package/src/middleware/observability.middleware.ts +0 -70
  275. package/src/middleware/rate-limit.middleware.ts +0 -45
  276. package/src/middleware/repository.middleware.ts +0 -114
  277. package/src/middleware/seed-registry.middleware.test.ts +0 -97
  278. package/src/middleware/seed-registry.middleware.ts +0 -21
  279. package/src/middleware/storage.middleware.ts +0 -25
  280. package/src/middleware.ts +0 -45
  281. package/src/public/access-policy.ts +0 -27
  282. package/src/public/api-key-middleware.ts +0 -57
  283. package/src/public/cache-utils.ts +0 -38
  284. package/src/public/entry-projection.ts +0 -46
  285. package/src/public/idempotency.ts +0 -23
  286. package/src/public/index.ts +0 -16
  287. package/src/public/problem-details.ts +0 -124
  288. package/src/public/public-add.ts +0 -114
  289. package/src/public/public-edit.ts +0 -163
  290. package/src/public/public-errors.ts +0 -19
  291. package/src/public/public-read.ts +0 -63
  292. package/src/public/public-routes.ts +0 -88
  293. package/src/public/query-builder.test.ts +0 -224
  294. package/src/public/query-builder.ts +0 -156
  295. package/src/public/rate-limit-middleware.ts +0 -34
  296. package/src/public/read-list.ts +0 -54
  297. package/src/public/read-single.ts +0 -48
  298. package/src/public/response-builder.ts +0 -30
  299. package/src/public/sanitize.ts +0 -69
  300. package/src/public/slug-utils.ts +0 -18
  301. package/src/rate-limit/cloudflare-rate-limiter.test.ts +0 -30
  302. package/src/rate-limit/cloudflare-rate-limiter.ts +0 -15
  303. package/src/rate-limit/in-memory-rate-limiter.test.ts +0 -37
  304. package/src/rate-limit/in-memory-rate-limiter.ts +0 -17
  305. package/src/rate-limit/no-op-rate-limiter.test.ts +0 -22
  306. package/src/rate-limit/no-op-rate-limiter.ts +0 -11
  307. package/src/search-utils.test.ts +0 -211
  308. package/src/search-utils.ts +0 -213
  309. package/src/search.ts +0 -65
  310. package/src/shared/apply-policies.test.ts +0 -81
  311. package/src/shared/apply-policies.ts +0 -67
  312. package/src/shared/automations.repository.d1.ts +0 -150
  313. package/src/shared/background-notification-service.test.ts +0 -62
  314. package/src/shared/background-notification-service.ts +0 -52
  315. package/src/shared/base.repository.d1.ts +0 -32
  316. package/src/shared/content-utils.test.ts +0 -165
  317. package/src/shared/content-utils.ts +0 -86
  318. package/src/shared/content.repository.d1.test.ts +0 -458
  319. package/src/shared/content.repository.d1.ts +0 -851
  320. package/src/shared/d1-activity-log.repository.test.ts +0 -140
  321. package/src/shared/d1-activity-log.repository.ts +0 -105
  322. package/src/shared/d1-activity-logger.test.ts +0 -86
  323. package/src/shared/d1-activity-logger.ts +0 -67
  324. package/src/shared/d1-analytics.repository.test.ts +0 -78
  325. package/src/shared/d1-analytics.repository.ts +0 -85
  326. package/src/shared/d1-content-scan.repository.test.ts +0 -80
  327. package/src/shared/d1-content-scan.repository.ts +0 -37
  328. package/src/shared/d1-notification.repository.test.ts +0 -128
  329. package/src/shared/d1-notification.repository.ts +0 -118
  330. package/src/shared/d1-password-reset-token.repository.test.ts +0 -81
  331. package/src/shared/d1-password-reset-token.repository.ts +0 -56
  332. package/src/shared/d1-search.repository.test.ts +0 -87
  333. package/src/shared/d1-search.repository.ts +0 -88
  334. package/src/shared/d1-session.repository.test.ts +0 -125
  335. package/src/shared/d1-session.repository.ts +0 -102
  336. package/src/shared/d1-setup-checklist.repository.ts +0 -36
  337. package/src/shared/d1-user.repository.test.ts +0 -151
  338. package/src/shared/d1-user.repository.ts +0 -119
  339. package/src/shared/d1-widget.repository.test.ts +0 -221
  340. package/src/shared/d1-widget.repository.ts +0 -341
  341. package/src/shared/demo-data-sql.ts +0 -54
  342. package/src/shared/demo-data.repository.d1.ts +0 -20
  343. package/src/shared/execution-context-scheduler.ts +0 -13
  344. package/src/shared/fixed-clock.ts +0 -25
  345. package/src/shared/fts-sync.ts +0 -8
  346. package/src/shared/idempotency.repository.d1.test.ts +0 -83
  347. package/src/shared/idempotency.repository.d1.ts +0 -60
  348. package/src/shared/in-memory-activity-logger.ts +0 -19
  349. package/src/shared/in-memory-notification-service.ts +0 -19
  350. package/src/shared/in-memory-seed.repository.ts +0 -51
  351. package/src/shared/media.repository.d1.test.ts +0 -107
  352. package/src/shared/media.repository.d1.ts +0 -68
  353. package/src/shared/qstash-notification-service.test.ts +0 -67
  354. package/src/shared/qstash-notification-service.ts +0 -55
  355. package/src/shared/query-utils.ts +0 -141
  356. package/src/shared/request-utils.ts +0 -26
  357. package/src/shared/schema-mutator.d1.ts +0 -64
  358. package/src/shared/seed-layout.repository.d1.test.ts +0 -114
  359. package/src/shared/seed-layout.repository.d1.ts +0 -62
  360. package/src/shared/seed-registry-cache.test.ts +0 -68
  361. package/src/shared/seed-registry-cache.ts +0 -49
  362. package/src/shared/seed.repository.d1.test.ts +0 -143
  363. package/src/shared/seed.repository.d1.ts +0 -98
  364. package/src/shared/sequential-id-generator.ts +0 -33
  365. package/src/shared/site-settings.repository.d1.ts +0 -53
  366. package/src/shared/storage/factory.ts +0 -41
  367. package/src/shared/storage/s3-bucket.ts +0 -195
  368. package/src/shared/storage-utils.ts +0 -40
  369. package/src/shared/system-stats.repository.d1.test.ts +0 -58
  370. package/src/shared/system-stats.repository.d1.ts +0 -48
  371. package/src/types.ts +0 -87
  372. package/src/upload.ts +0 -198
  373. package/src/widget.ts +0 -212
@@ -1,180 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { Context } from 'hono'
3
- import { EntryNotFoundError, SlugConflictError } from '@beechcms/core'
4
- import { normalizeBody, contentValidationProblem, logContentActivity, dispatchContentAutomation, handleContentDatabaseError } from './helpers'
5
- import { CONTENT_ERRORS } from '../constants'
6
-
7
- // Mock dependencies
8
- vi.mock('../../../public/problem-details', () => ({
9
- publicProblem: vi.fn((_ctx, details) => ({ mockProblem: true, ...details })),
10
- fkProblemOrNull: vi.fn((_ctx, err, method) => {
11
- if (err instanceof Error && err.message === 'FK_ERROR') return { mockFkProblem: true }
12
- return null
13
- }),
14
- }))
15
-
16
- describe('content handlers helpers', () => {
17
- describe('normalizeBody', () => {
18
- it('returns the object when input is an object', () => {
19
- const obj = { a: 1 }
20
- expect(normalizeBody(obj)).toBe(obj)
21
- })
22
-
23
- it('returns an empty object when input is null', () => {
24
- expect(normalizeBody(null)).toEqual({})
25
- })
26
-
27
- it('returns an empty object when input is a primitive', () => {
28
- expect(normalizeBody('string')).toEqual({})
29
- expect(normalizeBody(123)).toEqual({})
30
- expect(normalizeBody(true)).toEqual({})
31
- })
32
- })
33
-
34
- describe('contentValidationProblem', () => {
35
- it('calls publicProblem with correct parameters', () => {
36
- const ctx = {} as Context
37
- const errors = [{ field: 'title', expected: 'string', received: 'number', message: 'Wrong type' }]
38
- const result = contentValidationProblem(ctx, errors)
39
-
40
- expect(result).toEqual({
41
- mockProblem: true,
42
- type: 'content-validation-failed',
43
- title: 'Bad Request',
44
- status: 400,
45
- detail: 'Validation failed',
46
- errors,
47
- })
48
- })
49
- })
50
-
51
- describe('logContentActivity', () => {
52
- it('logs activity with correct payload', () => {
53
- const mockLog = vi.fn()
54
- const ctx = {
55
- get: vi.fn((key) => {
56
- if (key === 'jwtPayload') return { sub: 'user-1', email: 'test@test.com', name: 'John', surname: 'Doe' }
57
- if (key === 'activityLogger') return { log: mockLog }
58
- })
59
- } as unknown as Context<any>
60
-
61
- logContentActivity(ctx, 'create', 'entry-1', 'test-slug', 'Test Title')
62
-
63
- expect(mockLog).toHaveBeenCalledWith({
64
- action: 'create',
65
- entityType: 'content',
66
- entityId: 'entry-1',
67
- entitySlug: 'test-slug',
68
- details: { title: 'Test Title' },
69
- actor: {
70
- id: 'user-1',
71
- email: 'test@test.com',
72
- name: 'John Doe',
73
- },
74
- })
75
- })
76
-
77
- it('handles missing name and surname', () => {
78
- const mockLog = vi.fn()
79
- const ctx = {
80
- get: vi.fn((key) => {
81
- if (key === 'jwtPayload') return { sub: 'user-1' } // Missing name, surname, email
82
- if (key === 'activityLogger') return { log: mockLog }
83
- })
84
- } as unknown as Context<any>
85
-
86
- logContentActivity(ctx, 'update', 'entry-1', 'test-slug', 'Test Title')
87
-
88
- expect(mockLog).toHaveBeenCalledWith({
89
- action: 'update',
90
- entityType: 'content',
91
- entityId: 'entry-1',
92
- entitySlug: 'test-slug',
93
- details: { title: 'Test Title' },
94
- actor: {
95
- id: 'user-1',
96
- email: 'unknown',
97
- name: null,
98
- },
99
- })
100
- })
101
- })
102
-
103
- describe('dispatchContentAutomation', () => {
104
- it('schedules automation run', () => {
105
- const mockWaitUntil = vi.fn()
106
- const mockRun = vi.fn().mockReturnValue('mock-promise')
107
- const ctx = {
108
- get: vi.fn((key) => {
109
- if (key === 'scheduler') return { waitUntil: mockWaitUntil }
110
- if (key === 'automationRunner') return { run: mockRun }
111
- })
112
- } as unknown as Context<any>
113
-
114
- const entry = { id: 1 }
115
- dispatchContentAutomation(ctx, 'posts', 'create', entry)
116
-
117
- expect(mockRun).toHaveBeenCalledWith({
118
- seedSlug: 'posts',
119
- event: 'create',
120
- entry,
121
- })
122
- expect(mockWaitUntil).toHaveBeenCalledWith('mock-promise')
123
- })
124
- })
125
-
126
- describe('handleContentDatabaseError', () => {
127
- it('handles EntryNotFoundError', () => {
128
- const ctx = {} as Context<any>
129
- const error = new EntryNotFoundError('Not found')
130
- const result = handleContentDatabaseError(ctx, error)
131
-
132
- expect(result).toEqual({
133
- mockProblem: true,
134
- type: 'content-not-found',
135
- title: 'Not Found',
136
- status: 404,
137
- detail: CONTENT_ERRORS.NOT_FOUND,
138
- })
139
- })
140
-
141
- it('handles SlugConflictError', () => {
142
- const ctx = {} as Context<any>
143
- const error = new SlugConflictError('Conflict', 'slug')
144
- const result = handleContentDatabaseError(ctx, error)
145
-
146
- expect(result).toEqual({
147
- mockProblem: true,
148
- type: 'content-slug-conflict',
149
- title: 'Conflict',
150
- status: 409,
151
- detail: CONTENT_ERRORS.SLUG_CONFLICT,
152
- })
153
- })
154
-
155
- it('handles foreign key error', () => {
156
- const ctx = { req: { method: 'POST' } } as unknown as Context<any>
157
- const error = new Error('FK_ERROR')
158
- const result = handleContentDatabaseError(ctx, error)
159
-
160
- expect(result).toEqual({ mockFkProblem: true })
161
- })
162
-
163
- it('handles generic errors as 500', () => {
164
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
165
- const ctx = { req: { method: 'POST' } } as unknown as Context<any>
166
- const error = new Error('Some db error')
167
- const result = handleContentDatabaseError(ctx, error)
168
-
169
- expect(result).toEqual({
170
- mockProblem: true,
171
- type: 'content-database-error',
172
- title: 'Internal Server Error',
173
- status: 500,
174
- detail: CONTENT_ERRORS.DATABASE_ERROR,
175
- })
176
- expect(consoleSpy).toHaveBeenCalledWith('Content database error:', error)
177
- consoleSpy.mockRestore()
178
- })
179
- })
180
- })
@@ -1,93 +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 { Context } from 'hono'
6
- import { EntryNotFoundError, SlugConflictError } from '@beechcms/core'
7
- import { publicProblem, fkProblemOrNull } from '../../../public/problem-details'
8
- import { CONTENT_ERRORS } from '../constants'
9
- import { AppEnv } from '../../../types'
10
-
11
- export function normalizeBody(raw: unknown): Record<string, unknown> {
12
- return typeof raw === 'object' && raw !== null ? (raw as Record<string, unknown>) : {}
13
- }
14
-
15
- export function contentValidationProblem(
16
- context: Context,
17
- details: Array<{ field: string; expected: string; received: string; message: string }>
18
- ) {
19
- return publicProblem(context, {
20
- type: 'content-validation-failed',
21
- title: 'Bad Request',
22
- status: 400,
23
- detail: 'Validation failed',
24
- errors: details
25
- })
26
- }
27
-
28
- export function logContentActivity(
29
- context: Context<AppEnv>,
30
- action: 'create' | 'update' | 'delete',
31
- id: string,
32
- slug: string,
33
- title: string
34
- ) {
35
- const jwtPayload = context.get('jwtPayload')
36
- context.get('activityLogger').log({
37
- action,
38
- entityType: 'content',
39
- entityId: id,
40
- entitySlug: slug,
41
- details: { title },
42
- actor: {
43
- id: jwtPayload.sub,
44
- email: jwtPayload.email ?? 'unknown',
45
- name: [jwtPayload.name, jwtPayload.surname].filter(Boolean).join(' ') || null,
46
- },
47
- })
48
- }
49
-
50
- export function dispatchContentAutomation(
51
- context: Context<AppEnv>,
52
- seedSlug: string,
53
- event: 'create' | 'update' | 'delete',
54
- entry: Record<string, unknown>
55
- ) {
56
- context.get('scheduler').waitUntil(
57
- context.get('automationRunner').run({
58
- seedSlug,
59
- event,
60
- entry,
61
- }),
62
- )
63
- }
64
-
65
- export function handleContentDatabaseError(context: Context<AppEnv>, error: unknown) {
66
- if (error instanceof EntryNotFoundError) {
67
- return publicProblem(context, {
68
- type: 'content-not-found',
69
- title: 'Not Found',
70
- status: 404,
71
- detail: CONTENT_ERRORS.NOT_FOUND
72
- })
73
- }
74
- if (error instanceof SlugConflictError) {
75
- return publicProblem(context, {
76
- type: 'content-slug-conflict',
77
- title: 'Conflict',
78
- status: 409,
79
- detail: CONTENT_ERRORS.SLUG_CONFLICT,
80
- })
81
- }
82
-
83
- const fkResponse = fkProblemOrNull(context, error, context.req.method)
84
- if (fkResponse) return fkResponse
85
-
86
- console.error('Content database error:', error)
87
- return publicProblem(context, {
88
- type: 'content-database-error',
89
- title: 'Internal Server Error',
90
- status: 500,
91
- detail: CONTENT_ERRORS.DATABASE_ERROR,
92
- })
93
- }
@@ -1,174 +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 { Context } from 'hono'
6
- import { parsePositiveInt, parseQueryFilters, cleanStr, toEngineFilters } from '../../../shared/query-utils'
7
- import { applyVisibility } from '../../../shared/apply-policies'
8
- import { publicProblem } from '../../../public/problem-details'
9
- import { CONTENT_ERRORS } from '../constants'
10
- import { AppEnv } from '../../../types'
11
-
12
- /**
13
- * Builds a compact `relations` map for the list response.
14
- * For each relation branch in the seed, collects non-null referenced ids from
15
- * the page items, then fires ONE batched query per target seed to retrieve
16
- * only the label column. This is O(R) extra queries per page (R = # relation
17
- * branches) instead of O(N*R) per-row fetches.
18
- *
19
- * Shape: { [branchAlias]: { [targetId]: labelString } }
20
- */
21
- async function buildRelationsMap(
22
- context: Context<AppEnv>,
23
- seed: Parameters<typeof applyVisibility>[1],
24
- entries: Record<string, unknown>[]
25
- ): Promise<Record<string, Record<string, string>>> {
26
- const relationBranches = seed.branches.filter(
27
- (b: { type: string }) => b.type === 'relation'
28
- ) as Array<{ alias: string; targetSeed?: string }>
29
-
30
- if (relationBranches.length === 0) return {}
31
-
32
- const relations: Record<string, Record<string, string>> = {}
33
- const repository = context.get('repository')
34
- const seedRegistry = context.get('seedRegistry')
35
-
36
- for (const branch of relationBranches) {
37
- const targetSlug = branch.targetSeed
38
- if (!targetSlug) continue
39
-
40
- const targetSeedDef = seedRegistry.get(targetSlug)
41
- if (!targetSeedDef) continue
42
-
43
- const labelAlias = targetSeedDef.displayNameAlias ?? 'title'
44
-
45
- // Collect unique non-null ids referenced by this branch
46
- const ids = Array.from(
47
- new Set(
48
- entries
49
- .map((entry) => {
50
- const data = entry.data as Record<string, unknown>
51
- return typeof data[branch.alias] === 'string' && data[branch.alias]
52
- ? (data[branch.alias] as string)
53
- : null
54
- })
55
- .filter((id): id is string => id !== null)
56
- )
57
- )
58
-
59
- if (ids.length === 0) continue
60
-
61
- try {
62
- const { items } = await repository.findMany(targetSeedDef, {
63
- filters: [
64
- {
65
- column: 'id',
66
- type: 'system' as const,
67
- conditions: [{ op: 'in' as const, value: ids }],
68
- },
69
- ],
70
- fields: ['id', labelAlias],
71
- pagination: { limit: ids.length, offset: 0 },
72
- })
73
-
74
- const map: Record<string, string> = {}
75
- for (const item of items) {
76
- const id = (item as Record<string, unknown>).id as string
77
- const data = (item as Record<string, unknown>).data as Record<string, unknown>
78
- const label = data[labelAlias]
79
- map[id] = label != null && label !== '' ? String(label) : id
80
- }
81
-
82
- relations[branch.alias] = map
83
- } catch {
84
- // Non-fatal: if the target seed table doesn't exist yet, skip
85
- }
86
- }
87
-
88
- return relations
89
- }
90
-
91
- export async function listHandler(context: Context<AppEnv>) {
92
- const slug = context.req.param('slug')
93
- if (!slug) {
94
- return publicProblem(context, {
95
- type: 'content-invalid-slug',
96
- title: 'Bad Request',
97
- status: 400,
98
- detail: CONTENT_ERRORS.INVALID_SLUG
99
- })
100
- }
101
-
102
- const seed = context.get('getSeed')(slug)
103
- if (!seed) {
104
- return publicProblem(context, {
105
- type: 'content-seed-not-found',
106
- title: 'Not Found',
107
- status: 404,
108
- detail: CONTENT_ERRORS.SEED_NOT_FOUND
109
- })
110
- }
111
-
112
- try {
113
- const query = context.req.query()
114
- const search = cleanStr(query.search) ?? ''
115
- const sortBy = cleanStr(query.sortBy) ?? ''
116
- const sortDirRaw = cleanStr(query.sortDir)?.toLowerCase() ?? 'asc'
117
- const rawFilters = parseQueryFilters(query.filters)
118
- const engineFilters = toEngineFilters(rawFilters)
119
-
120
- // Note: repository doesn't yet support has_pending_draft filter/column natively
121
- // in findMany without SQL manipulation. We'll stick to basic findMany for now
122
- // and might need to enhance the repository if this feature is critical for v1 of this refactor.
123
- // The legacy code was doing a lot of SQL injection here.
124
-
125
- const page = parsePositiveInt(query.page, 1)
126
- const limit = Math.min(parsePositiveInt(query.limit, 25), 100)
127
- const offset = (page - 1) * limit
128
-
129
- const orderBy = sortBy
130
- ? { column: sortBy, dir: (sortDirRaw === 'desc' ? 'DESC' : 'ASC') as 'ASC' | 'DESC' }
131
- : undefined
132
-
133
- const repository = context.get('repository')
134
- const { items, total } = await repository.findMany(seed, {
135
- filters: engineFilters,
136
- orderBy,
137
- search: search || undefined,
138
- pagination: { limit, offset },
139
- })
140
-
141
- const entries = await Promise.all(items.map(async (item) => {
142
- // Check for pending draft if allowed
143
- let hasPendingDraft = false
144
- if (seed.allowDrafts) {
145
- hasPendingDraft = await repository.hasDraft(seed, item.id)
146
- }
147
-
148
- return {
149
- ...item,
150
- has_pending_draft: hasPendingDraft,
151
- data: applyVisibility(item, seed) // Repository returns "pure" data including system fields
152
- }
153
- }))
154
-
155
- // If no query params (except slug), return array directly (legacy compatibility)
156
- const hasQueryParams = Boolean(search) || Boolean(sortBy) || Boolean(query.filters) || query.page !== undefined || query.limit !== undefined
157
- if (!hasQueryParams) {
158
- return context.json(entries)
159
- }
160
-
161
- // Build compact relation labels map for N+1 mitigation
162
- const relations = await buildRelationsMap(context, seed, entries)
163
-
164
- return context.json({ items: entries, total, page, limit, relations })
165
- } catch (error) {
166
- console.error('Content list error:', error)
167
- return publicProblem(context, {
168
- type: 'content-database-error',
169
- title: 'Internal Server Error',
170
- status: 500,
171
- detail: CONTENT_ERRORS.DATABASE_ERROR
172
- })
173
- }
174
- }
@@ -1,174 +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 { Context } from 'hono'
6
- import {
7
- slugify,
8
- isValidContentStatus,
9
- validateAndSanitizeSeedPayload,
10
- resolvePolicies
11
- } from '@beechcms/core'
12
- import { applyPrivacy, PrivacyPolicyError } from '../../../shared/apply-policies'
13
- import { publicProblem } from '../../../public/problem-details'
14
- import {
15
- normalizeBody,
16
- contentValidationProblem,
17
- logContentActivity,
18
- dispatchContentAutomation,
19
- handleContentDatabaseError
20
- } from './helpers'
21
- import { CONTENT_ERRORS } from '../constants'
22
- import { cleanStr } from '../../../shared/query-utils'
23
- import { AppEnv } from '../../../types'
24
-
25
-
26
-
27
- export async function updateHandler(context: Context<AppEnv>) {
28
- const slug = context.req.param('slug')
29
- const id = context.req.param('id')
30
- if (!slug || !id) {
31
- return publicProblem(context, {
32
- type: 'content-invalid-slug-or-id',
33
- title: 'Bad Request',
34
- status: 400,
35
- detail: CONTENT_ERRORS.INVALID_SLUG_OR_ID
36
- })
37
- }
38
-
39
- const seed = context.get('getSeed')(slug)
40
- if (!seed) {
41
- return publicProblem(context, {
42
- type: 'content-seed-not-found',
43
- title: 'Not Found',
44
- status: 404,
45
- detail: CONTENT_ERRORS.SEED_NOT_FOUND
46
- })
47
- }
48
-
49
- let body: Record<string, unknown>
50
- try {
51
- body = normalizeBody(await context.req.json<unknown>())
52
- } catch {
53
- return publicProblem(context, {
54
- type: 'content-invalid-json',
55
- title: 'Bad Request',
56
- status: 400,
57
- detail: CONTENT_ERRORS.INVALID_JSON_BODY
58
- })
59
- }
60
-
61
- const bodyForData = { ...body }
62
- delete bodyForData.slug
63
- delete bodyForData.status
64
-
65
- try {
66
- const repository = context.get('repository')
67
- // We need current data to handle slug and status if not provided,
68
- // and to verify existence.
69
- const current = await repository.findById(seed, id)
70
-
71
- const newSlug = body.slug !== undefined ? slugify(String(body.slug)) : (current.slug as string)
72
- const newStatus = body.status !== undefined ? (cleanStr(body.status) ?? current.status as string) : current.status as string
73
-
74
- if (!isValidContentStatus(newStatus)) {
75
- return publicProblem(context, {
76
- type: 'content-invalid-status',
77
- title: 'Bad Request',
78
- status: 400,
79
- detail: 'Invalid status. Allowed values are: draft, review, published'
80
- })
81
- }
82
-
83
- if (!newSlug) {
84
- return publicProblem(context, {
85
- type: 'content-missing-slug',
86
- title: 'Bad Request',
87
- status: 400,
88
- detail: 'Missing required field: slug'
89
- })
90
- }
91
-
92
- let mergedData: Record<string, unknown> = {}
93
-
94
- if (Object.keys(bodyForData).length > 0) {
95
- const sensitiveAliases = Object.keys(bodyForData).filter((alias) => {
96
- const branch = seed.branches.find((b) => b.alias === alias)
97
- return branch != null && resolvePolicies(branch).privacy !== 'plain'
98
- })
99
-
100
- if (sensitiveAliases.length > 0) {
101
- return publicProblem(context, {
102
- type: 'content-sensitive-field-edit',
103
- title: 'Unprocessable Entity',
104
- status: 422,
105
- detail: `${CONTENT_ERRORS.SENSITIVE_FIELD_EDIT}: ${sensitiveAliases.join(', ')}`
106
- })
107
- }
108
-
109
- const validation = validateAndSanitizeSeedPayload(seed, bodyForData, {
110
- operation: 'update',
111
- allowNull: true,
112
- requireAtLeastOneValidField: true,
113
- enforceRequiredFields: true,
114
- idGenerator: context.get('idGenerator'),
115
- })
116
-
117
- if (validation.dangerousFields.length > 0) {
118
- return publicProblem(context, {
119
- type: 'content-dangerous-content',
120
- title: 'Unprocessable Entity',
121
- status: 422,
122
- detail: `Content rejected: dangerous markup detected in field '${validation.dangerousFields[0]}'`
123
- })
124
- }
125
-
126
- if (validation.details.length > 0) return contentValidationProblem(context, validation.details)
127
-
128
- let privacyPatch: Record<string, unknown>
129
- try {
130
- privacyPatch = await applyPrivacy(validation.data, seed)
131
- } catch (error) {
132
- if (error instanceof PrivacyPolicyError) {
133
- return publicProblem(context, {
134
- type: 'content-policy-not-implemented',
135
- title: 'Not Implemented',
136
- status: 501,
137
- detail: error.message
138
- })
139
- }
140
- throw error
141
- }
142
-
143
- // Remove null values from patch (patch semantics: null = leave unchanged)
144
- for (const [k, v] of Object.entries(privacyPatch)) {
145
- if (v !== null) mergedData[k] = v
146
- }
147
- }
148
-
149
- if (newSlug !== current.slug) {
150
- if (await repository.existsSlug(seed, newSlug, id)) {
151
- return publicProblem(context, {
152
- type: 'content-slug-conflict',
153
- title: 'Conflict',
154
- status: 409,
155
- detail: CONTENT_ERRORS.SLUG_CONFLICT
156
- })
157
- }
158
- // Add slug to mergedData if changed
159
- mergedData.slug = newSlug
160
- }
161
-
162
- await repository.update(seed, id, mergedData, newStatus)
163
-
164
- const jwtPayload = context.get('jwtPayload')
165
- const title = mergedData.title || mergedData.name || newSlug
166
-
167
- logContentActivity(context, 'update', id, slug, String(title))
168
- dispatchContentAutomation(context, slug, 'update', { ...current, ...mergedData, id, status: newStatus })
169
-
170
- return context.json({ success: true })
171
- } catch (error) {
172
- return handleContentDatabaseError(context, error)
173
- }
174
- }
@@ -1,26 +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 { Hono } from 'hono'
6
- import { AppEnv } from '../../types'
7
- import { listHandler } from './handlers/list'
8
- import { getByIdHandler, getBySlugHandler } from './handlers/get'
9
- import { createHandler } from './handlers/create'
10
- import { updateHandler } from './handlers/update'
11
- import { deleteHandler } from './handlers/delete'
12
- import { facetsHandler } from './handlers/facets'
13
- import { bulkHandler } from './handlers/bulk.handler'
14
-
15
- const content = new Hono<AppEnv>()
16
-
17
- content.get('/:slug', listHandler)
18
- content.get('/:slug/facets', facetsHandler)
19
- content.get('/:schema_slug/by-slug/:entry_slug', getBySlugHandler)
20
- content.get('/:slug/:id', getByIdHandler)
21
- content.post('/:slug', createHandler)
22
- content.patch('/:slug/bulk', bulkHandler)
23
- content.put('/:slug/:id', updateHandler)
24
- content.delete('/:slug/:id', deleteHandler)
25
-
26
- export default content