@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,558 +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 { Branch, Seed } from '@beechcms/core'
8
- import {
9
- nextBranchId,
10
- validateSeedDefinitions,
11
- planCreateSeed,
12
- planExtendSeed,
13
- planFtsRebuild,
14
- generateDropTable,
15
- generateDropColumn,
16
- generateRenameColumn,
17
- generateRetypeColumn,
18
- BRANCH_ALIAS_RE,
19
- } from '@beechcms/core'
20
- import { publicProblem, internalErrorDetail } from '../../public/problem-details'
21
- import { deleteR2Objects } from '../../upload'
22
- import { extractMediaKeysFromData } from '../../media-utils'
23
- import type { Env, Variables } from '../../types'
24
-
25
- const SLUG_RE = /^[a-z0-9_]+$/
26
-
27
- function requireAdmin(context: any) {
28
- const role = context.get('jwtPayload')?.role
29
- if (role !== 'admin') {
30
- return publicProblem(context, {
31
- type: 'forbidden',
32
- title: 'Forbidden',
33
- status: 403,
34
- detail: 'Seed management requires admin role.',
35
- })
36
- }
37
- return null
38
- }
39
-
40
- function actorFromContext(context: any) {
41
- const jwt = context.get('jwtPayload')
42
- return {
43
- id: jwt?.sub ?? 'unknown',
44
- email: jwt?.email ?? 'unknown',
45
- name: [jwt?.name, jwt?.surname].filter(Boolean).join(' ') || null,
46
- }
47
- }
48
-
49
- async function parseJsonBody(context: any): Promise<unknown> {
50
- try { return await context.req.json() } catch {
51
- return publicProblem(context, { type: 'invalid-json', title: 'Invalid JSON', status: 400, detail: 'Body must be valid JSON.' })
52
- }
53
- }
54
-
55
- async function getActiveSeed(context: any, slug: string) {
56
- const repo = context.get('seedRepository')
57
- const existing = await repo.get(slug)
58
- if (!existing || existing.status === 'deleted') {
59
- return publicProblem(context, { type: 'seed-not-found', title: 'Seed not found', status: 404, detail: `No active seed with slug '${slug}'.` })
60
- }
61
- return existing
62
- }
63
-
64
- async function validateAndApplySeedDef(context: any, slug: string, candidate: Seed, action: 'create' | 'update', logDetails: any) {
65
- const repo = context.get('seedRepository')
66
- const activeSeeds = await repo.listActive()
67
- const candidateSet = [...activeSeeds.filter((s: any) => s.slug !== slug), candidate]
68
- const issues = validateSeedDefinitions(candidateSet)
69
- const fatalIssues = issues.filter(i => i.fatal && i.slug === slug)
70
- if (fatalIssues.length > 0) {
71
- return publicProblem(context, {
72
- type: 'validation-failed',
73
- title: 'Validation failed',
74
- status: 422,
75
- detail: fatalIssues.flatMap(i => i.messages).join('; '),
76
- })
77
- }
78
-
79
- const schemaMutator = context.get('schemaMutator')
80
- const tableName = `content_${slug}`
81
- const existingCols = await schemaMutator.getColumns(tableName)
82
-
83
- try {
84
- const stmts = existingCols === null
85
- ? planCreateSeed(candidate)
86
- : planExtendSeed(candidate, existingCols).statements
87
- await schemaMutator.execDdl(stmts)
88
- } catch (err) {
89
- return publicProblem(context, {
90
- type: 'ddl-failed',
91
- title: 'DDL execution failed',
92
- status: 422,
93
- detail: internalErrorDetail(context.env, err),
94
- })
95
- }
96
-
97
- await repo.upsert(slug, candidate, 'runtime')
98
- await repo.bumpRegistryVersion()
99
-
100
- const actor = actorFromContext(context)
101
- context.get('activityLogger').log({ action, entityType: 'seed', entityId: slug, details: logDetails, actor })
102
-
103
- return null
104
- }
105
-
106
- async function applyDestructiveSeedDef(context: any, slug: string, updatedDef: Seed, stmts: string[], logDetails: any) {
107
- const repo = context.get('seedRepository')
108
- const schemaMutator = context.get('schemaMutator')
109
-
110
- try {
111
- await schemaMutator.execDestructive(stmts)
112
- } catch (err) {
113
- return publicProblem(context, { type: 'ddl-failed', title: 'DDL failed', status: 422, detail: internalErrorDetail(context.env, err) })
114
- }
115
-
116
- await repo.upsert(slug, updatedDef, 'runtime')
117
- await repo.bumpRegistryVersion()
118
-
119
- const actor = actorFromContext(context)
120
- context.get('activityLogger').log({ action: 'update', entityType: 'seed', entityId: slug, details: logDetails, actor })
121
-
122
- return null
123
- }
124
-
125
- /** Typed confirm guard. Returns a 400 response on mismatch, null on success. */
126
- function requireConfirm(context: any, expected: string, body: unknown) {
127
- const confirm = (body as Record<string, unknown>)?.confirm
128
- if (typeof confirm !== 'string' || confirm !== expected) {
129
- return publicProblem(context, {
130
- type: 'confirmation-required',
131
- title: 'Confirmation required',
132
- status: 400,
133
- detail: `Destructive operation requires body field \`confirm\` equal to "${expected}".`,
134
- })
135
- }
136
- return null
137
- }
138
-
139
- function validateIncomingBranches(incomingBranches: Branch[], storedBranches: Branch[], slug: string, context: any) {
140
- const storedById = new Map(storedBranches.map((b: Branch) => [b.id, b]))
141
-
142
- for (const branch of incomingBranches) {
143
- const stored = branch.id ? storedById.get(branch.id) : undefined
144
- if (stored) {
145
- if (branch.alias !== stored.alias) {
146
- return publicProblem(context, {
147
- type: 'alias-rename-not-supported',
148
- title: 'Alias rename not supported',
149
- status: 422,
150
- detail: `Branch '${branch.id}' alias rename from '${stored.alias}' to '${branch.alias}' is irreversible. Use PATCH /api/seeds/${slug}/branches/${branch.id}/rename with a typed confirmation.`,
151
- })
152
- }
153
- if (branch.type !== stored.type) {
154
- return publicProblem(context, {
155
- type: 'branch-type-change-not-supported',
156
- title: 'Branch type change not supported',
157
- status: 422,
158
- detail: `Branch '${branch.id}' type change from '${stored.type}' to '${branch.type}' is irreversible. Use PATCH /api/seeds/${slug}/branches/${branch.id}/retype with a typed confirmation.`,
159
- })
160
- }
161
- } else if (!branch.id) {
162
- const accSeed = { branches: incomingBranches.filter(b => b.id) }
163
- branch.id = nextBranchId(accSeed)
164
- }
165
- }
166
- return null
167
- }
168
-
169
- async function deleteSeedMediaObjects(context: any, slug: string, seed: Seed, schemaMutator: any) {
170
- const fileBranches = seed.branches.filter((b: Branch) => b.type === 'file')
171
- if (fileBranches.length === 0) return
172
-
173
- try {
174
- const dbCols = await schemaMutator.getColumns(`content_${slug}`)
175
- if (!dbCols) return
176
-
177
- const colList = fileBranches.map((b: Branch) => b.alias).filter((a: string) => dbCols.has(a)).join(', ')
178
- if (!colList) return
179
-
180
- const rs = await context.env.DB.prepare(`SELECT ${colList} FROM content_${slug}`).all()
181
- const rows = (rs.results as Record<string, unknown>[]) ?? []
182
- const r2Keys: string[] = []
183
-
184
- for (const row of rows) {
185
- for (const b of fileBranches) {
186
- const val = row[b.alias]
187
- if (!val) continue
188
- const keys = extractMediaKeysFromData(seed, { [b.alias]: val })
189
- r2Keys.push(...keys)
190
- }
191
- }
192
-
193
- if (r2Keys.length > 0) {
194
- await deleteR2Objects(context, r2Keys).catch(() => { /* non-fatal */ })
195
- }
196
- } catch { /* non-fatal: drop proceeds */ }
197
- }
198
-
199
- export const seedsApp = new Hono<{ Bindings: Env; Variables: Variables }>()
200
-
201
- seedsApp.use('*', async (context, next) => {
202
- const denied = requireAdmin(context)
203
- if (denied) return denied
204
- await next()
205
- })
206
-
207
- /** GET /api/seeds — list all seed records (active + deleted). Admin-only. */
208
- seedsApp.get('/', async (context) => {
209
- const records = await context.get('seedRepository').listAll()
210
- return context.json(records)
211
- })
212
-
213
- /** GET /api/seeds/:slug — single record by slug. Admin-only. */
214
- seedsApp.get('/:slug', async (context) => {
215
- const slug = context.req.param('slug')
216
- const record = await context.get('seedRepository').get(slug)
217
- if (!record) {
218
- return publicProblem(context, {
219
- type: 'seed-not-found',
220
- title: 'Seed not found',
221
- status: 404,
222
- detail: `No seed with slug '${slug}'.`,
223
- })
224
- }
225
- return context.json(record)
226
- })
227
-
228
- /** POST /api/seeds — create a new content type. */
229
- seedsApp.post('/', async (context) => {
230
- const body = await parseJsonBody(context)
231
- if (body instanceof Response) return body
232
-
233
- const candidate = body as Seed
234
- const slug = candidate?.slug
235
-
236
- if (!slug || !SLUG_RE.test(slug)) {
237
- return publicProblem(context, { type: 'invalid-json', title: 'Bad Request', status: 400, detail: `slug must match ${SLUG_RE.source}.` })
238
- }
239
-
240
- const repo = context.get('seedRepository')
241
- const existing = await repo.get(slug)
242
-
243
- if (existing?.status === 'active') {
244
- return publicProblem(context, {
245
- type: 'slug-conflict',
246
- title: 'Slug conflict',
247
- status: 409,
248
- detail: `An active seed with slug '${slug}' already exists.`,
249
- })
250
- }
251
-
252
- // Assign ids to branches that are missing one
253
- const accSeed: Pick<Seed, 'branches'> = { branches: [] }
254
- const branches: Branch[] = Array.isArray(candidate.branches) ? candidate.branches : []
255
- for (const branch of branches) {
256
- if (!branch.id) {
257
- branch.id = nextBranchId(accSeed)
258
- }
259
- accSeed.branches.push({ ...branch })
260
- }
261
-
262
- // Default displayNameAlias to first text branch if not provided
263
- if (!candidate.displayNameAlias) {
264
- const firstText = branches.find(b => b.type === 'text')
265
- if (!firstText) {
266
- return publicProblem(context, { type: 'invalid-json', title: 'Bad Request', status: 400, detail: 'displayNameAlias is required (or include at least one text branch so it can be inferred).' })
267
- }
268
- candidate.displayNameAlias = firstText.alias
269
- }
270
- candidate.branches = branches
271
-
272
- const error = await validateAndApplySeedDef(context, slug, candidate, 'create', { slug })
273
- if (error) return error
274
-
275
- return context.json({ slug }, 201)
276
- })
277
-
278
- /** PUT /api/seeds/:slug — replace definition (additive-only). */
279
- seedsApp.put('/:slug', async (context) => {
280
- const slug = context.req.param('slug')
281
- const body = await parseJsonBody(context)
282
- if (body instanceof Response) return body
283
-
284
- const existing = await getActiveSeed(context, slug)
285
- if (existing instanceof Response) return existing
286
-
287
- const incoming = body as Seed
288
- const storedBranches = existing.definition.branches
289
- const incomingBranches: Branch[] = Array.isArray(incoming.branches) ? incoming.branches : []
290
-
291
- const validationError = validateIncomingBranches(incomingBranches, storedBranches, slug, context)
292
- if (validationError) return validationError
293
-
294
- const candidate: Seed = { ...incoming, slug, branches: incomingBranches }
295
-
296
- const error = await validateAndApplySeedDef(context, slug, candidate, 'update', { slug })
297
- if (error) return error
298
-
299
- return context.json({ slug })
300
- })
301
-
302
- /** POST /api/seeds/:slug/branches — add a single branch. */
303
- seedsApp.post('/:slug/branches', async (context) => {
304
- const slug = context.req.param('slug')
305
- const body = await parseJsonBody(context)
306
- if (body instanceof Response) return body
307
-
308
- const existing = await getActiveSeed(context, slug)
309
- if (existing instanceof Response) return existing
310
-
311
- const newBranch = body as Branch
312
- newBranch.id = nextBranchId(existing.definition)
313
-
314
- const candidate: Seed = {
315
- ...existing.definition,
316
- branches: [...existing.definition.branches, newBranch],
317
- }
318
-
319
- const error = await validateAndApplySeedDef(context, slug, candidate, 'update', { addedBranch: newBranch.id })
320
- if (error) return error
321
-
322
- return context.json({ id: newBranch.id })
323
- })
324
-
325
- /** DELETE /api/seeds/:slug — soft-delete a content type. */
326
- seedsApp.delete('/:slug', async (context) => {
327
- const slug = context.req.param('slug')
328
- const repo = context.get('seedRepository')
329
-
330
- const existing = await getActiveSeed(context, slug)
331
- if (existing instanceof Response) return existing
332
-
333
- const backrefMap = context.get('backrefMap')
334
- const inbound = backrefMap.get(slug)
335
- if (inbound && inbound.length > 0) {
336
- const referencers = [...new Set(inbound.map((r: any) => r.sourceSlug))]
337
- return publicProblem(context, {
338
- type: 'seed-referenced',
339
- title: 'Seed referenced',
340
- status: 409,
341
- detail: `Seed '${slug}' is referenced by: ${referencers.join(', ')}. Remove those relations first.`,
342
- })
343
- }
344
-
345
- await repo.softDelete(slug)
346
- await repo.bumpRegistryVersion()
347
-
348
- const actor = actorFromContext(context)
349
- context.get('activityLogger').log({ action: 'delete', entityType: 'seed', entityId: slug, details: { slug }, actor })
350
-
351
- return context.json({ success: true })
352
- })
353
-
354
- /** GET /api/seeds/:slug/orphans — columns in DB but absent from the definition. */
355
- seedsApp.get('/:slug/orphans', async (context) => {
356
- const slug = context.req.param('slug')
357
- const existing = await getActiveSeed(context, slug)
358
- if (existing instanceof Response) return existing
359
-
360
- const schemaMutator = context.get('schemaMutator')
361
- const dbCols = await schemaMutator.getColumns(`content_${slug}`)
362
- if (!dbCols) return context.json({ orphans: [] })
363
-
364
- const knownAliases = new Set([
365
- 'id', 'slug', 'status', 'created_at', 'updated_at',
366
- ...existing.definition.branches
367
- .filter((b: Branch) => !(b.type === 'relation' && b.multiple === true))
368
- .map((b: Branch) => b.alias),
369
- ])
370
- const orphans = [...dbCols].filter((col: string) => !knownAliases.has(col))
371
- return context.json({ orphans })
372
- })
373
-
374
- /** POST /api/seeds/:slug/fts/rebuild — rebuild FTS table + triggers. */
375
- seedsApp.post('/:slug/fts/rebuild', async (context) => {
376
- const slug = context.req.param('slug')
377
- const existing = await getActiveSeed(context, slug)
378
- if (existing instanceof Response) return existing
379
-
380
- const stmts = planFtsRebuild(existing.definition)
381
- if (stmts.length > 0) {
382
- await context.get('schemaMutator').execDestructive(stmts)
383
- }
384
-
385
- const actor = actorFromContext(context)
386
- context.get('activityLogger').log({ action: 'update', entityType: 'seed', entityId: slug, details: { op: 'fts-rebuild' }, actor })
387
-
388
- return context.json({ success: true })
389
- })
390
-
391
- /** DELETE /api/seeds/:slug/hard — hard delete: drops tables + deletes row. */
392
- seedsApp.delete('/:slug/hard', async (context) => {
393
- const slug = context.req.param('slug')
394
- const body = await parseJsonBody(context)
395
- if (body instanceof Response) return body
396
-
397
- const confirmErr = requireConfirm(context, slug, body)
398
- if (confirmErr) return confirmErr
399
-
400
- const existing = await getActiveSeed(context, slug)
401
- if (existing instanceof Response) return existing
402
-
403
- const backrefMap = context.get('backrefMap')
404
- const inbound = backrefMap.get(slug)
405
- if (inbound && inbound.length > 0) {
406
- const referencers = [...new Set(inbound.map((r: any) => r.sourceSlug))]
407
- return publicProblem(context, {
408
- type: 'seed-referenced',
409
- title: 'Seed referenced',
410
- status: 409,
411
- detail: `Seed '${slug}' is referenced by: ${referencers.join(', ')}. Remove those relations first.`,
412
- })
413
- }
414
-
415
- const repo = context.get('seedRepository')
416
- const schemaMutator = context.get('schemaMutator')
417
- const seed = existing.definition
418
-
419
- await deleteSeedMediaObjects(context, slug, seed, schemaMutator)
420
-
421
- await schemaMutator.execDestructive(generateDropTable(seed))
422
- await repo.hardDelete(slug)
423
- await repo.bumpRegistryVersion()
424
-
425
- const actor = actorFromContext(context)
426
- context.get('activityLogger').log({ action: 'delete', entityType: 'seed', entityId: slug, details: { op: 'hard-delete', slug }, actor })
427
-
428
- return context.json({ success: true })
429
- })
430
-
431
- /** DELETE /api/seeds/:slug/branches/:branchId — drop a single field column. */
432
- seedsApp.delete('/:slug/branches/:branchId', async (context) => {
433
- const slug = context.req.param('slug')
434
- const branchId = context.req.param('branchId')
435
- const body = await parseJsonBody(context)
436
- if (body instanceof Response) return body
437
-
438
- const existing = await getActiveSeed(context, slug)
439
- if (existing instanceof Response) return existing
440
-
441
- const branch = existing.definition.branches.find((b: Branch) => b.id === branchId)
442
- if (!branch) {
443
- return publicProblem(context, { type: 'branch-not-found', title: 'Branch not found', status: 404, detail: `No branch with id '${branchId}' in seed '${slug}'.` })
444
- }
445
-
446
- const confirmErr = requireConfirm(context, `${slug}.${branch.alias}`, body)
447
- if (confirmErr) return confirmErr
448
-
449
- const updatedDef: Seed = {
450
- ...existing.definition,
451
- branches: existing.definition.branches.filter((b: Branch) => b.id !== branchId),
452
- }
453
-
454
- const stmts = generateDropColumn(existing.definition, branch.alias)
455
- const error = await applyDestructiveSeedDef(context, slug, updatedDef, stmts, { op: 'drop-branch', branchId, alias: branch.alias })
456
- if (error) return error
457
-
458
- return context.json({ success: true })
459
- })
460
-
461
- /** PATCH /api/seeds/:slug/branches/:branchId/rename — rename a field alias. */
462
- seedsApp.patch('/:slug/branches/:branchId/rename', async (context) => {
463
- const slug = context.req.param('slug')
464
- const branchId = context.req.param('branchId')
465
- const body = await parseJsonBody(context)
466
- if (body instanceof Response) return body
467
-
468
- const newAlias = (body as Record<string, unknown>)?.newAlias
469
- if (typeof newAlias !== 'string' || !BRANCH_ALIAS_RE.test(newAlias)) {
470
- return publicProblem(context, { type: 'invalid-json', title: 'Bad Request', status: 400, detail: `newAlias must match ${BRANCH_ALIAS_RE.source} (lowercase letter followed by alphanumeric characters or underscores).` })
471
- }
472
-
473
- const existing = await getActiveSeed(context, slug)
474
- if (existing instanceof Response) return existing
475
-
476
- const branch = existing.definition.branches.find((b: Branch) => b.id === branchId)
477
- if (!branch) {
478
- return publicProblem(context, { type: 'branch-not-found', title: 'Branch not found', status: 404, detail: `No branch with id '${branchId}' in seed '${slug}'.` })
479
- }
480
-
481
- const confirmErr = requireConfirm(context, `${slug}.${branch.alias}`, body)
482
- if (confirmErr) return confirmErr
483
-
484
- const renamedDef: Seed = {
485
- ...existing.definition,
486
- branches: existing.definition.branches.map((b: Branch) =>
487
- b.id === branchId ? { ...b, alias: newAlias } : b
488
- ),
489
- }
490
-
491
- const renameStmts = generateRenameColumn(existing.definition, branch.alias, newAlias)
492
- const ftsStmts = planFtsRebuild(renamedDef)
493
-
494
- const error = await applyDestructiveSeedDef(context, slug, renamedDef, [...renameStmts, ...ftsStmts], { op: 'rename-branch', branchId, from: branch.alias, to: newAlias })
495
- if (error) return error
496
-
497
- let affectedAutomations: string[] = []
498
- try {
499
- const automationRepo = context.get('automationRepository')
500
- if (automationRepo) {
501
- const automations = await automationRepo.list(slug)
502
- const oldAlias = branch.alias
503
- affectedAutomations = automations
504
- .filter((a: any) => JSON.stringify(a).includes(oldAlias))
505
- .map((a: any) => a.id)
506
- }
507
- } catch { /* non-fatal */ }
508
-
509
- return context.json({ success: true, affectedAutomations })
510
- })
511
-
512
- /** PATCH /api/seeds/:slug/branches/:branchId/retype — change field SQL type. */
513
- seedsApp.patch('/:slug/branches/:branchId/retype', async (context) => {
514
- const slug = context.req.param('slug')
515
- const branchId = context.req.param('branchId')
516
- const body = await parseJsonBody(context)
517
- if (body instanceof Response) return body
518
-
519
- const newType = (body as Record<string, unknown>)?.newType
520
- const VALID_TYPES = new Set(['text','number','boolean','date','json','richtext','file','tags','relation','repeater'])
521
- if (typeof newType !== 'string' || !VALID_TYPES.has(newType)) {
522
- return publicProblem(context, { type: 'invalid-json', title: 'Bad Request', status: 400, detail: `newType must be one of: ${[...VALID_TYPES].join(', ')}.` })
523
- }
524
-
525
- const existing = await getActiveSeed(context, slug)
526
- if (existing instanceof Response) return existing
527
-
528
- const branch = existing.definition.branches.find((b: Branch) => b.id === branchId)
529
- if (!branch) {
530
- return publicProblem(context, { type: 'branch-not-found', title: 'Branch not found', status: 404, detail: `No branch with id '${branchId}' in seed '${slug}'.` })
531
- }
532
-
533
- if (branch.type === 'repeater' || newType === 'repeater') {
534
- return publicProblem(context, {
535
- type: 'retype-not-supported',
536
- title: 'Retype not supported',
537
- status: 422,
538
- detail: "Retyping to or from 'repeater' is not supported in v1.",
539
- })
540
- }
541
-
542
- const confirmErr = requireConfirm(context, `${slug}.${branch.alias}`, body)
543
- if (confirmErr) return confirmErr
544
-
545
- const retypedBranch: Branch = { ...branch, type: newType as Branch['type'] }
546
- const retypedDef: Seed = {
547
- ...existing.definition,
548
- branches: existing.definition.branches.map((b: Branch) => b.id === branchId ? retypedBranch : b),
549
- }
550
-
551
- const retypeStmts = generateRetypeColumn(existing.definition, retypedBranch)
552
- const ftsStmts = planFtsRebuild(retypedDef)
553
-
554
- const error = await applyDestructiveSeedDef(context, slug, retypedDef, [...retypeStmts, ...ftsStmts], { op: 'retype-branch', branchId, from: branch.type, to: newType })
555
- if (error) return error
556
-
557
- return context.json({ success: true })
558
- })