dineway 0.2.39 → 0.2.41

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 (460) hide show
  1. package/dist/{activity-LXZdjKwI.mjs → activity-BuhkMdv8.mjs} +2 -2
  2. package/dist/{activity-events-DoqeOM8x.mjs → activity-events-DkHsy7Y0.mjs} +1 -1
  3. package/dist/{allowed-origins-DiVrMLxh.mjs → allowed-origins-Clitkhiv.mjs} +1 -1
  4. package/dist/api/route-utils.d.mts +15 -12
  5. package/dist/api/route-utils.mjs +27 -20
  6. package/dist/api/schemas/index.d.mts +1 -1
  7. package/dist/api/schemas/index.mjs +10 -5
  8. package/dist/{api-COSxvdOi.mjs → api-CMbsIQ46.mjs} +41 -13
  9. package/dist/{api-tokens-CNHnKO57.mjs → api-tokens-ciHNTdN2.mjs} +1 -1
  10. package/dist/{apply-D4rZHDyg.mjs → apply-B5qoX19G.mjs} +62 -18
  11. package/dist/astro/index.d.mts +16 -13
  12. package/dist/astro/index.mjs +31 -5
  13. package/dist/astro/middleware/auth.d.mts +14 -11
  14. package/dist/astro/middleware/auth.mjs +8 -8
  15. package/dist/astro/middleware/redirect.mjs +10 -6
  16. package/dist/astro/middleware/request-context.mjs +5 -5
  17. package/dist/astro/middleware/seed.d.mts +1 -1
  18. package/dist/astro/middleware/seed.mjs +2 -2
  19. package/dist/astro/middleware/setup.mjs +1 -1
  20. package/dist/astro/middleware.d.mts +2 -2
  21. package/dist/astro/middleware.mjs +266 -176
  22. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +12 -7
  23. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +12 -7
  24. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  25. package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
  26. package/dist/astro/routes/api/admin/briefing.mjs +41 -22
  27. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  28. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +14 -10
  29. package/dist/astro/routes/api/admin/byline-fields/index.mjs +14 -10
  30. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +14 -10
  31. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +25 -19
  32. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +25 -19
  33. package/dist/astro/routes/api/admin/bylines/index.mjs +25 -19
  34. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +20 -16
  35. package/dist/astro/routes/api/admin/comments/_id_.mjs +10 -7
  36. package/dist/astro/routes/api/admin/comments/bulk.mjs +18 -13
  37. package/dist/astro/routes/api/admin/comments/counts.mjs +10 -7
  38. package/dist/astro/routes/api/admin/comments/index.mjs +18 -13
  39. package/dist/astro/routes/api/admin/context/_id_/history.mjs +51 -39
  40. package/dist/astro/routes/api/admin/context/_id_/index.mjs +51 -39
  41. package/dist/astro/routes/api/admin/context/_id_/review.mjs +57 -44
  42. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +57 -44
  43. package/dist/astro/routes/api/admin/context/diff.mjs +56 -43
  44. package/dist/astro/routes/api/admin/context/index.mjs +57 -44
  45. package/dist/astro/routes/api/admin/context/stale.mjs +56 -43
  46. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +51 -39
  47. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +56 -43
  48. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +56 -43
  49. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +52 -40
  50. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  51. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +7 -7
  52. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +7 -7
  53. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +78 -68
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +78 -68
  55. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +71 -60
  56. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +78 -67
  57. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +78 -67
  58. package/dist/astro/routes/api/admin/plugins/index.mjs +71 -60
  59. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  60. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -60
  61. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +78 -67
  62. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -60
  63. package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -60
  64. package/dist/astro/routes/api/admin/review-requests/_id_/image.mjs +38 -23
  65. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +46 -36
  66. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +63 -52
  67. package/dist/astro/routes/api/admin/review-requests/_id_/revoke.mjs +9 -9
  68. package/dist/astro/routes/api/admin/review-requests/index.mjs +61 -50
  69. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -60
  70. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  71. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -60
  72. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
  73. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  74. package/dist/astro/routes/api/admin/users/_id_/index.mjs +11 -7
  75. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  76. package/dist/astro/routes/api/admin/users/index.mjs +12 -7
  77. package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
  78. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  79. package/dist/astro/routes/api/auth/invite/complete.mjs +17 -12
  80. package/dist/astro/routes/api/auth/invite/index.mjs +14 -9
  81. package/dist/astro/routes/api/auth/invite/register-options.mjs +16 -11
  82. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  83. package/dist/astro/routes/api/auth/magic-link/send.mjs +17 -12
  84. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  85. package/dist/astro/routes/api/auth/me.mjs +14 -11
  86. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  87. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  88. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +3 -3
  89. package/dist/astro/routes/api/auth/passkey/_id_.mjs +12 -7
  90. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  91. package/dist/astro/routes/api/auth/passkey/options.mjs +19 -14
  92. package/dist/astro/routes/api/auth/passkey/register/options.mjs +16 -11
  93. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +17 -12
  94. package/dist/astro/routes/api/auth/passkey/verify.mjs +17 -12
  95. package/dist/astro/routes/api/auth/setup-token/index.mjs +6 -6
  96. package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
  97. package/dist/astro/routes/api/auth/signup/complete.mjs +17 -12
  98. package/dist/astro/routes/api/auth/signup/request.mjs +17 -12
  99. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  100. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts +14 -11
  101. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +23 -19
  102. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +23 -18
  103. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  104. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +8 -8
  105. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +8 -8
  106. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +8 -8
  107. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +25 -20
  108. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +41 -31
  109. package/dist/astro/routes/api/content/_collection_/_id_/release-readiness.mjs +14 -9
  110. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +8 -8
  111. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  112. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +41 -31
  113. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +30 -20
  114. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  115. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +8 -8
  116. package/dist/astro/routes/api/content/_collection_/_id_.mjs +25 -14
  117. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  118. package/dist/astro/routes/api/content/_collection_/index.mjs +25 -14
  119. package/dist/astro/routes/api/content/_collection_/trash.mjs +13 -8
  120. package/dist/astro/routes/api/dashboard.mjs +21 -13
  121. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  122. package/dist/astro/routes/api/health.mjs +1 -1
  123. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  124. package/dist/astro/routes/api/import/probe.mjs +30 -23
  125. package/dist/astro/routes/api/import/wordpress/analyze.mjs +13 -10
  126. package/dist/astro/routes/api/import/wordpress/execute.d.mts +14 -11
  127. package/dist/astro/routes/api/import/wordpress/execute.mjs +58 -47
  128. package/dist/astro/routes/api/import/wordpress/media.d.mts +14 -11
  129. package/dist/astro/routes/api/import/wordpress/media.mjs +17 -14
  130. package/dist/astro/routes/api/import/wordpress/prepare.mjs +61 -48
  131. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +15 -12
  132. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +58 -45
  133. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  134. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +32 -26
  135. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  136. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +14 -11
  137. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +63 -52
  138. package/dist/astro/routes/api/integration/artifact.mjs +9 -9
  139. package/dist/astro/routes/api/integration/dispatch.mjs +14 -14
  140. package/dist/astro/routes/api/integrations/_provider_.mjs +9 -9
  141. package/dist/astro/routes/api/integrations/index.mjs +8 -8
  142. package/dist/astro/routes/api/manifest.mjs +5 -5
  143. package/dist/astro/routes/api/mcp.mjs +141 -93
  144. package/dist/astro/routes/api/media/_id_/confirm.mjs +15 -12
  145. package/dist/astro/routes/api/media/_id_.mjs +14 -9
  146. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  147. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  148. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  149. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  150. package/dist/astro/routes/api/media/upload-url.mjs +16 -13
  151. package/dist/astro/routes/api/media.mjs +19 -16
  152. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +57 -44
  153. package/dist/astro/routes/api/menus/_name_/items.mjs +57 -44
  154. package/dist/astro/routes/api/menus/_name_/reorder.mjs +57 -44
  155. package/dist/astro/routes/api/menus/_name_/translations.mjs +57 -44
  156. package/dist/astro/routes/api/menus/_name_.mjs +57 -44
  157. package/dist/astro/routes/api/menus/index.mjs +57 -44
  158. package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
  159. package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
  160. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  161. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  162. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  163. package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
  164. package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
  165. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  166. package/dist/astro/routes/api/openapi.json.mjs +10 -5
  167. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  168. package/dist/astro/routes/api/redirects/404s/index.mjs +15 -13
  169. package/dist/astro/routes/api/redirects/404s/summary.mjs +15 -13
  170. package/dist/astro/routes/api/redirects/_id_.mjs +57 -44
  171. package/dist/astro/routes/api/redirects/index.mjs +57 -44
  172. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  173. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  174. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -62
  175. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +73 -62
  176. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +73 -62
  177. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +73 -62
  178. package/dist/astro/routes/api/schema/collections/index.mjs +73 -62
  179. package/dist/astro/routes/api/schema/index.mjs +13 -10
  180. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -60
  181. package/dist/astro/routes/api/schema/orphans/index.mjs +71 -60
  182. package/dist/astro/routes/api/search/enable.mjs +20 -13
  183. package/dist/astro/routes/api/search/index.mjs +19 -12
  184. package/dist/astro/routes/api/search/rebuild.mjs +20 -13
  185. package/dist/astro/routes/api/search/stats.mjs +12 -7
  186. package/dist/astro/routes/api/search/suggest.mjs +19 -12
  187. package/dist/astro/routes/api/sections/_slug_.mjs +57 -44
  188. package/dist/astro/routes/api/sections/index.mjs +57 -44
  189. package/dist/astro/routes/api/settings/email.mjs +5 -5
  190. package/dist/astro/routes/api/settings/reviews.mjs +11 -11
  191. package/dist/astro/routes/api/settings.mjs +57 -44
  192. package/dist/astro/routes/api/setup/admin-verify.mjs +19 -14
  193. package/dist/astro/routes/api/setup/admin.mjs +17 -12
  194. package/dist/astro/routes/api/setup/dev-bypass.mjs +44 -32
  195. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  196. package/dist/astro/routes/api/setup/index.mjs +47 -34
  197. package/dist/astro/routes/api/setup/status.mjs +3 -3
  198. package/dist/astro/routes/api/snapshot.mjs +9 -9
  199. package/dist/astro/routes/api/system/heartbeat.mjs +2 -2
  200. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +60 -47
  201. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +60 -47
  202. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +60 -47
  203. package/dist/astro/routes/api/taxonomies/index.mjs +60 -47
  204. package/dist/astro/routes/api/themes/preview.mjs +7 -7
  205. package/dist/astro/routes/api/typegen.mjs +4 -4
  206. package/dist/astro/routes/api/well-known/auth.mjs +3 -3
  207. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  208. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  209. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +56 -43
  210. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +57 -44
  211. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +57 -44
  212. package/dist/astro/routes/api/widget-areas/_name_.mjs +53 -41
  213. package/dist/astro/routes/api/widget-areas/index.mjs +57 -44
  214. package/dist/astro/routes/api/widget-components.mjs +2 -2
  215. package/dist/astro/routes/robots.txt.mjs +14 -9
  216. package/dist/astro/routes/sitemap-_collection_.xml.mjs +20 -16
  217. package/dist/astro/routes/sitemap.xml.mjs +19 -15
  218. package/dist/astro/session-driver.d.mts +1 -1
  219. package/dist/astro/session-driver.mjs +8 -3
  220. package/dist/astro/types.d.mts +21 -14
  221. package/dist/{atomic-authority-CnBQJ14T.mjs → atomic-authority-Bf5QZboB.mjs} +2 -2
  222. package/dist/{audit-Cl495Ze3.mjs → audit-hXJBTPY0.mjs} +1 -1
  223. package/dist/auth/providers/github.d.mts +1 -1
  224. package/dist/auth/providers/google.d.mts +1 -1
  225. package/dist/{auth-control-guard-DbjgJdlo.mjs → auth-control-guard-DpUP6Fs_.mjs} +1 -1
  226. package/dist/{authorize-DDmgmnW-.mjs → authorize-DWNOqMKq.mjs} +1 -1
  227. package/dist/{briefing-DsD-Ouwc.mjs → briefing-BzvBeIJh.mjs} +1 -1
  228. package/dist/{briefing-COw-WcYz.mjs → briefing-DYiV93rg.mjs} +995 -7
  229. package/dist/{bundle-bhiszAui.mjs → bundle-DWn5eFKz.mjs} +2 -2
  230. package/dist/{byline-TYk2kad6.mjs → byline-3qjp1-oa.mjs} +65 -14
  231. package/dist/{byline-fields-CKhPED5o.d.mts → byline-fields-Bne2v0ti.d.mts} +42 -38
  232. package/dist/{byline-fields-BKj5f3Ub.mjs → byline-fields-DRMCc0V_.mjs} +1 -1
  233. package/dist/{byline-fields-DZ46DF10.mjs → byline-fields-wWu2Cb3l.mjs} +3 -3
  234. package/dist/{byline-registry-CJihchD1.mjs → byline-registry-Caj0_gbU.mjs} +1 -1
  235. package/dist/{bylines-6T9iVC9j.mjs → bylines-BSn9O1Wx.mjs} +3 -3
  236. package/dist/{bylines-CvTSCAw9.mjs → bylines-CGuJi-zu.mjs} +5 -5
  237. package/dist/{patterns-Ay-4KImK.mjs → cache-DsEbwFVE.mjs} +51 -1
  238. package/dist/{chunks-C8vSD_5L.mjs → chunks-Bb56aCtB.mjs} +1 -1
  239. package/dist/cli/index.mjs +488 -58
  240. package/dist/cli/plugin-kit.d.mts +14 -11
  241. package/dist/cli/plugin-kit.mjs +2 -2
  242. package/dist/client/external-auth-headers.d.mts +1 -1
  243. package/dist/client/index.d.mts +16 -13
  244. package/dist/client/index.mjs +2 -2
  245. package/dist/{client-factory-C1ZQCMog.mjs → client-factory-BLbm250o.mjs} +1 -1
  246. package/dist/{comment-DAQfUjqt.mjs → comment-BWDG1nQm.mjs} +2 -2
  247. package/dist/{comment-reaction-Dp3G7UZc.mjs → comment-reaction-B7pLTlQ7.mjs} +1 -1
  248. package/dist/{comments-BrvIaRAx.mjs → comments-xkten8nV.mjs} +1 -1
  249. package/dist/config-6R0bchVE.mjs +125 -0
  250. package/dist/{content-CIKsrvU9.mjs → content-BigS8BAv.mjs} +302 -45
  251. package/dist/content-Dr22fzA_.mjs +390 -0
  252. package/dist/{content-refresh-BilzqcLt.mjs → content-refresh-DJuFIqQ4.mjs} +14 -8
  253. package/dist/content-storage/index.d.mts +180 -0
  254. package/dist/content-storage/index.mjs +29 -0
  255. package/dist/content-storage/store.d.mts +3 -0
  256. package/dist/content-storage/store.mjs +5 -0
  257. package/dist/{review-payload-Bap86e75.mjs → content-write-DAZCNKWl.mjs} +838 -131
  258. package/dist/{context-DAs_MZjJ.mjs → context-0806nV9h.mjs} +292 -23
  259. package/dist/{context-DVTvucNb.mjs → context-CCsI5nTK.mjs} +2 -2
  260. package/dist/{context-route-helpers-BP-UJ4u8.mjs → context-route-helpers-TP3EqxRQ.mjs} +2 -2
  261. package/dist/{dashboard-BAjWCGCP.mjs → dashboard-CSrnhBO6.mjs} +4 -4
  262. package/dist/database/batch.d.mts +1 -1
  263. package/dist/database/batch.mjs +1 -1
  264. package/dist/database/d1/index.d.mts +14 -11
  265. package/dist/database/d1/index.mjs +4 -4
  266. package/dist/database/instrumentation.mjs +3 -2
  267. package/dist/db/index.d.mts +3 -3
  268. package/dist/db/index.mjs +1 -1
  269. package/dist/db/libsql.d.mts +1 -1
  270. package/dist/db/postgres.d.mts +1 -1
  271. package/dist/db/sqlite.d.mts +1 -1
  272. package/dist/{device-flow-Dh0rNlh1.mjs → device-flow-SoZh-HvN.mjs} +3 -3
  273. package/dist/{discovery-V0e0Gg8j.mjs → discovery-49qXmdwv.mjs} +4 -4
  274. package/dist/{enrich-B7PIJ8Iy.mjs → enrich-CAMsD1aT.mjs} +1 -1
  275. package/dist/{error-B5a45Tfb.mjs → error-sL4aemcW.mjs} +2 -0
  276. package/dist/{evidence-Vnp_fQbC.mjs → evidence-B3O9_VKm.mjs} +7 -7
  277. package/dist/{field-defs-cache-aXUeXJdC.mjs → field-defs-cache-dn5Tw79A.mjs} +4 -4
  278. package/dist/{fts-manager-BrPpYtK0.mjs → fts-manager-Zu5ITic0.mjs} +1 -1
  279. package/dist/{hitl-requests-BxMMON3s.mjs → hitl-requests-B5vOPseK.mjs} +2 -2
  280. package/dist/{hitl-route-helpers-sdnjpx2k.mjs → hitl-route-helpers-C3icmGdj.mjs} +5 -5
  281. package/dist/hook-events-BQw73jc7.d.mts +32 -0
  282. package/dist/{import-C2-v4FCs.mjs → import-CKnKQj3f.mjs} +9 -9
  283. package/dist/{index-BVGe04wF.d.mts → index-CLj17kW9.d.mts} +12 -5
  284. package/dist/index.d.mts +19 -16
  285. package/dist/index.mjs +107 -98
  286. package/dist/{integration-credentials-DMEXZU2J.mjs → integration-credentials-DpuRw1kx.mjs} +2 -2
  287. package/dist/{jsonld-XWmmAoVo.d.mts → jsonld-CN91qtDw.d.mts} +2 -2
  288. package/dist/{load-DvCVppOF.mjs → load-CiRTddkJ.mjs} +1 -1
  289. package/dist/{loader-Dp6zLmQm.mjs → loader-CCwWFQSh.mjs} +16 -5
  290. package/dist/{manifest-schema-CCvogfrP.mjs → manifest-schema-DaQpgyTB.mjs} +1 -1
  291. package/dist/{mcp-reviewed-executor-B8Gbin3T.mjs → mcp-reviewed-executor-DA6Q9sDc.mjs} +6 -6
  292. package/dist/media/image-endpoint.mjs +1 -1
  293. package/dist/media/index.d.mts +1 -1
  294. package/dist/media/index.mjs +2 -2
  295. package/dist/media/local-runtime.d.mts +16 -13
  296. package/dist/media/local-runtime.mjs +3 -3
  297. package/dist/{media-C5ba8fvI.mjs → media-BjH5OD-A.mjs} +1 -1
  298. package/dist/{media-allowlist-DQvscVkS.mjs → media-allowlist-C8HJ2O61.mjs} +1 -1
  299. package/dist/{menus-CyNpBQrX.mjs → menus-CbBi7Ad7.mjs} +2 -2
  300. package/dist/{menus-w5xwT-f5.mjs → menus-D0c8CeVg.mjs} +7 -7
  301. package/dist/migration-DJuj7ZwN.mjs +526 -0
  302. package/dist/{migrations-CLlX25HO.mjs → migrations-BAjF60cl.mjs} +1 -1
  303. package/dist/{oauth-authorization-CdqJZUMf.mjs → oauth-authorization-CSSRMOKn.mjs} +4 -4
  304. package/dist/{oauth-clients-CHNb9MAZ.mjs → oauth-clients-DX5HIJJv.mjs} +2 -2
  305. package/dist/object-cache/memory.d.mts +1 -1
  306. package/dist/{object-cache-mxCW-Rpt.mjs → object-cache-DyI1SOBK.mjs} +3 -1
  307. package/dist/owned-metadata-BPmUjZqI.mjs +69 -0
  308. package/dist/page/index.d.mts +15 -12
  309. package/dist/page/index.mjs +1 -1
  310. package/dist/{parse-THHCpJLB.mjs → parse-C6kCR1OT.mjs} +1 -1
  311. package/dist/plugin-utils.d.mts +14 -11
  312. package/dist/plugins/adapt-sandbox-entry.d.mts +14 -11
  313. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  314. package/dist/{plugins-pfraURNp.mjs → plugins-V0W65r3v.mjs} +16 -962
  315. package/dist/{policy-B6mVa7ib.mjs → policy-DbceGc4P.mjs} +2 -2
  316. package/dist/{preview-Bh7D7F27.mjs → preview-CWiIjMDi.mjs} +2 -2
  317. package/dist/{provider-loader-DT7vQ5FI.d.mts → provider-loader-oLKm1AU8.d.mts} +1 -1
  318. package/dist/{public-url-Ccv0Xmue.d.mts → public-url-CEC1vj02.d.mts} +2 -2
  319. package/dist/{public-url-BvnTaacI.d.mts → public-url-CKrUov8D.d.mts} +1 -1
  320. package/dist/{publication-authorization-B_HJSnzR.mjs → publication-authorization-wMR-tEQ_.mjs} +43 -17
  321. package/dist/{query-xspvw7Ui.mjs → query-DDi367tF.mjs} +14 -14
  322. package/dist/{query-DLeahg3x.mjs → query-DLnnpEuf.mjs} +4 -4
  323. package/dist/{rate-limit-BsBr_U9g.mjs → rate-limit-DeVLLe4z.mjs} +2 -2
  324. package/dist/{redirect-BQFa1THe.mjs → redirect-CJ-FAbNK.mjs} +2 -2
  325. package/dist/{redirects-DJcsgz_X.mjs → redirects-BKi6mek4.mjs} +4 -5
  326. package/dist/{redirects-CVfxefrz.mjs → redirects-I78-ZYLV.mjs} +5 -386
  327. package/dist/{registry-Dclv9iHv.mjs → registry-zXXZezu-.mjs} +7 -7
  328. package/dist/{release-B3Q-9B7N.mjs → release-Cpi0-Bzq.mjs} +173 -22
  329. package/dist/request-context.d.mts +30 -0
  330. package/dist/{request-meta-CjORiJQ_.mjs → request-meta-DZYuLXx_.mjs} +1 -1
  331. package/dist/review-payload-Bhi52CbI.mjs +112 -0
  332. package/dist/{review-requests-CcSUTm_l.mjs → review-requests-C-ScxD9n.mjs} +2 -2
  333. package/dist/{review-requests-CUVn0RBl.mjs → review-requests-DZYM51yI.mjs} +2 -2
  334. package/dist/{review-route-helpers-CKBfGKCi.mjs → review-route-helpers-DXNDyx_q.mjs} +2 -2
  335. package/dist/{revision-W6FDfDqx.mjs → revision-B_HYO2AE.mjs} +42 -7
  336. package/dist/revisions-CQ7rMP5d.mjs +55 -0
  337. package/dist/{revocation-C_ZQvGRT.mjs → revocation-4we8kfBg.mjs} +2 -2
  338. package/dist/{runner-CRU7BXjr.mjs → runner-CuG8o1uW.mjs} +558 -487
  339. package/dist/{runner-SoP1rphP.d.mts → runner-DXQkyPeX.d.mts} +1 -1
  340. package/dist/{runs-BtaAiLTw.mjs → runs-BjgLfqCn.mjs} +5 -5
  341. package/dist/runtime-Bs2JMbb2.d.mts +45 -0
  342. package/dist/runtime-Ch5G-tnG.mjs +400 -0
  343. package/dist/runtime.d.mts +15 -12
  344. package/dist/runtime.mjs +9 -4
  345. package/dist/schema-BA05k0TN.mjs +8 -0
  346. package/dist/{search-BI9uKr7U.mjs → search-DMrzhfx_.mjs} +4 -98
  347. package/dist/{secrets-D_pergcD.mjs → secrets-CIYcw9T9.mjs} +4 -4
  348. package/dist/{sections-BqqYq9RW.mjs → sections-BTrSEhqB.mjs} +2 -2
  349. package/dist/seed/index.d.mts +2 -2
  350. package/dist/seed/index.mjs +38 -26
  351. package/dist/seo/index.d.mts +3 -3
  352. package/dist/seo/index.mjs +12 -9
  353. package/dist/{seo-Bs_DUxJf.mjs → seo-Cv7ud_m2.mjs} +44 -5
  354. package/dist/{seo-B-5PsaJO.mjs → seo-DkjtBh-y.mjs} +1 -1
  355. package/dist/{service-W2xuGLgw.mjs → service-BBJM08uD.mjs} +2 -2
  356. package/dist/{service-B65aJsN7.mjs → service-CkMuD5AE.mjs} +3 -3
  357. package/dist/{settings-DsBzKeUQ.mjs → settings-BUONaNnG.mjs} +7 -7
  358. package/dist/{settings-CyJ2-MKx.mjs → settings-CI-NtWEc.mjs} +2 -2
  359. package/dist/{setup-complete-DeivSVJi.mjs → setup-complete-DoVbVrHx.mjs} +1 -1
  360. package/dist/{site-activity-DU0UPDji.mjs → site-activity-hpfJkmxQ.mjs} +1 -1
  361. package/dist/{site-context-Dic2jHuw.mjs → site-context-BW3GRCJH.mjs} +15 -15
  362. package/dist/{site-url-Tw6CfBB2.mjs → site-url-CYatfe3q.mjs} +1 -1
  363. package/dist/{state-DM7blWfT.mjs → state-CKkqoA6i.mjs} +1 -1
  364. package/dist/storage/local.d.mts +1 -1
  365. package/dist/storage/local.mjs +1 -1
  366. package/dist/storage/s3.d.mts +1 -1
  367. package/dist/storage/s3.mjs +2 -2
  368. package/dist/{store-32e6dfD-.mjs → store-BzaAtszy.mjs} +3 -3
  369. package/dist/submission-DLgjQ_Ew.mjs +205 -0
  370. package/dist/{taxonomies-BFsUR7kc.mjs → taxonomies-C02-Vuh3.mjs} +3 -3
  371. package/dist/{taxonomies-lWGNLKgn.mjs → taxonomies-D5wO9zmB.mjs} +7 -7
  372. package/dist/{taxonomy-DN6i1upz.mjs → taxonomy-BK7JmHlo.mjs} +53 -3
  373. package/dist/terms-EskuqbKE.mjs +104 -0
  374. package/dist/text-extraction-CdqMGYQK.mjs +96 -0
  375. package/dist/{tokens-D-StaTAQ.mjs → tokens-D8HEH277.mjs} +1 -1
  376. package/dist/{trusted-proxy-hYufGFPK.mjs → trusted-proxy-Dg3U9Lrv.mjs} +1 -1
  377. package/dist/{types-RFzE_V1M.mjs → types-BI3ULB3A.mjs} +2 -2
  378. package/dist/{types-CJynaYg1.d.mts → types-C3jUu4Bc.d.mts} +90 -34
  379. package/dist/{types-B--VyN3n.d.mts → types-Dpv_MvwZ.d.mts} +1 -1
  380. package/dist/{types-CgcOeaiQ.d.mts → types-ex-UrNlz.d.mts} +1 -1
  381. package/dist/types-qOEot0UQ.d.mts +83 -0
  382. package/dist/ui/server-runtime.d.mts +18 -15
  383. package/dist/ui/server-runtime.mjs +29 -25
  384. package/dist/{user-Btai9rl3.mjs → user-Bl2_8rhJ.mjs} +2 -2
  385. package/dist/{utils-CYxGuO_P.mjs → utils-CklSLz9F.mjs} +2 -2
  386. package/dist/{validate-C05z0m7M.mjs → validate-C-yk7mmX.mjs} +3 -3
  387. package/dist/{validate-kmN2lS8H.d.mts → validate-DUscf6VG.d.mts} +3 -3
  388. package/dist/version-BlE1LEPb.mjs +6 -0
  389. package/dist/version-store-BXv2D0de.mjs +208 -0
  390. package/dist/version-store-B_THJCc0.d.mts +98 -0
  391. package/dist/{widgets-BOrDZdQ3.mjs → widgets-9xHBhL_L.mjs} +3 -3
  392. package/dist/{wordpress-slugs-ROzITIBK.mjs → wordpress-slugs-yaeD7cxn.mjs} +1 -1
  393. package/dist/{worker-Bg35R37I.mjs → worker-CC_Rt1pB.mjs} +10 -10
  394. package/dist/write-intent-DuHVqks9.mjs +108 -0
  395. package/dist/{zod-generator-DkrWuID7.mjs → zod-generator-B5Pt8fv0.mjs} +2 -2
  396. package/package.json +16 -4
  397. package/dist/cache-B5NSHhxG.mjs +0 -52
  398. package/dist/cron-C7HCJPPl.mjs +0 -271
  399. package/dist/schema-CosVhHJt.mjs +0 -8
  400. package/dist/submission-DJmRejGR.mjs +0 -411
  401. package/dist/version-BnLdwIT1.mjs +0 -6
  402. /package/dist/{actor-DxUAJgQX.mjs → actor-D0AW80ld.mjs} +0 -0
  403. /package/dist/{adapter-symbols-Bq3JsWGM.d.mts → adapter-symbols-B9mi-BUh.d.mts} +0 -0
  404. /package/dist/{adapters-C8nRpUuj.d.mts → adapters-lDnJjNDz.d.mts} +0 -0
  405. /package/dist/{api-tokens-0N3nafqZ.mjs → api-tokens-CdfsE9PL.mjs} +0 -0
  406. /package/dist/{base64-Cz-aU0X1.mjs → base64-qvSs0Gxy.mjs} +0 -0
  407. /package/dist/{challenge-store-BPn3goP9.mjs → challenge-store-7IZ_NqWg.mjs} +0 -0
  408. /package/dist/{components-rFN8NH3N.mjs → components-JA6tFHmE.mjs} +0 -0
  409. /package/dist/{context-types-CPWAJRs5.mjs → context-types-DDIJhGLs.mjs} +0 -0
  410. /package/dist/{default-BS6VQRkB.mjs → default-C2azCFSB.mjs} +0 -0
  411. /package/dist/{email-console-GqK6hgMJ.mjs → email-console-BYQp_5Qr.mjs} +0 -0
  412. /package/dist/{escape-CE7xOWzJ.mjs → escape-4_NNa6GR.mjs} +0 -0
  413. /package/dist/{experimental-workflows-BbxpWwBy.mjs → experimental-workflows-CPNiI2EL.mjs} +0 -0
  414. /package/dist/{forgeway-account-DcTxh3Gw.mjs → forgeway-account-YzraapbX.mjs} +0 -0
  415. /package/dist/{hash-D2Rqd2J2.mjs → hash-qSYPMJ8w.mjs} +0 -0
  416. /package/dist/{media-url-D9kdpoLS.mjs → media-url-D5E1a47B.mjs} +0 -0
  417. /package/dist/{mime-BnVhH671.mjs → mime-FkfazULS.mjs} +0 -0
  418. /package/dist/{mode-D0gePRtf.mjs → mode-C3RI5Z5t.mjs} +0 -0
  419. /package/dist/{normalize-aTwryvvi.mjs → normalize-DrmlLn40.mjs} +0 -0
  420. /package/dist/{oauth-authority-P5YMSk2z.mjs → oauth-authority-DVlLFhsZ.mjs} +0 -0
  421. /package/dist/{oauth-state-store-CMqLdo4I.mjs → oauth-state-store-nf-78RbK.mjs} +0 -0
  422. /package/dist/{options-JiLWB6Bt.mjs → options-yFkLUuTw.mjs} +0 -0
  423. /package/dist/{output-7HDrYTSQ.mjs → output-ljHaxIHX.mjs} +0 -0
  424. /package/dist/{parser-kettsjWc.mjs → parser-CTlxybRo.mjs} +0 -0
  425. /package/dist/{passkey-config-DVzQ3dv3.mjs → passkey-config-BLon3ct9.mjs} +0 -0
  426. /package/dist/{placeholder-DJLP_HY7.d.mts → placeholder-DdZV3I8x.d.mts} +0 -0
  427. /package/dist/{portable-text-tQhvPLf1.mjs → portable-text-CSbRjM-T.mjs} +0 -0
  428. /package/dist/{portable-text-BE7nszX6.d.mts → portable-text-HNmwL-7L.d.mts} +0 -0
  429. /package/dist/{process-cache-C19OA3am.mjs → process-cache-CMy5M80h.mjs} +0 -0
  430. /package/dist/{provider-loader-DERzBMUz.mjs → provider-loader-DlaT1usE.mjs} +0 -0
  431. /package/dist/{public-discovery-BGyhuD5U.mjs → public-discovery-BnqYofSK.mjs} +0 -0
  432. /package/dist/{public-url-DFXUU6Wp.mjs → public-url-BHjYWuaN.mjs} +0 -0
  433. /package/dist/{public-url-sR8SVmTt.mjs → public-url-GQygrYmg.mjs} +0 -0
  434. /package/dist/{redirect-BxacnBYL.mjs → redirect-CokmLN5o.mjs} +0 -0
  435. /package/dist/{request-cache-8_ifFzVw.mjs → request-cache-CizvDoxV.mjs} +0 -0
  436. /package/dist/{resolve-DEKC4qVa.mjs → resolve-BxFGSKYu.mjs} +0 -0
  437. /package/dist/{runtime-env-CPTzh0mZ.mjs → runtime-env-DpYGy4pT.mjs} +0 -0
  438. /package/dist/{scheduled-publish-BxdShRGs.d.mts → scheduled-publish-eCNGpvNm.d.mts} +0 -0
  439. /package/dist/{seo-contributions-LEFs1d7w.mjs → seo-contributions-ZKqrqsdT.mjs} +0 -0
  440. /package/dist/{service-kQ5ljRzX.mjs → service-DeX1PRNt.mjs} +0 -0
  441. /package/dist/{session-user-eweCNKzW.mjs → session-user-D36BRaZY.mjs} +0 -0
  442. /package/dist/{setup-nonce-B6A5Y1ea.mjs → setup-nonce-B9IO7PbK.mjs} +0 -0
  443. /package/dist/{sidecar-client-BwPhhz-F.mjs → sidecar-client-2hx5G46s.mjs} +0 -0
  444. /package/dist/{slugify-kD31VIv2.mjs → slugify-DvoaEPtL.mjs} +0 -0
  445. /package/dist/{ssrf-C9dyjU8O.mjs → ssrf-DcD8vn3E.mjs} +0 -0
  446. /package/dist/{stable-hash-B9Tbb2f_.mjs → stable-hash-9RDJgfif.mjs} +0 -0
  447. /package/dist/{status-Bjf_uSrW.mjs → status-B2xUokyJ.mjs} +0 -0
  448. /package/dist/{transport-BrU1aDY5.mjs → transport-BHYE4pox.mjs} +0 -0
  449. /package/dist/{transport-CZbtxgKZ.d.mts → transport-CVU5rp7W.d.mts} +0 -0
  450. /package/dist/{types-DNBL-4Sn.mjs → types-B3Uq7Czg.mjs} +0 -0
  451. /package/dist/{types-DsJTXStN.d.mts → types-BJztoTbF.d.mts} +0 -0
  452. /package/dist/{types-COvyXIp7.mjs → types-BgUxCuwu.mjs} +0 -0
  453. /package/dist/{types-KFzuijKE.d.mts → types-C0heD9oI.d.mts} +0 -0
  454. /package/dist/{types-B03h5jt_.d.mts → types-DheoByey.d.mts} +0 -0
  455. /package/dist/{types-SlLXjRpg.d.mts → types-I5LHzk_M.d.mts} +0 -0
  456. /package/dist/{types-PLJ9hlhh.mjs → types-Nm0cMxEh.mjs} +0 -0
  457. /package/dist/{types-CtGSEKEJ.d.mts → types-PxxPTFSl.d.mts} +0 -0
  458. /package/dist/{url-DGG3hw_h.mjs → url-Coamqvs4.mjs} +0 -0
  459. /package/dist/{url-DUz3LbCs.mjs → url-dn4mFfCI.mjs} +0 -0
  460. /package/dist/{workers-build-5UQ4j69Q.mjs → workers-build-4926MPc0.mjs} +0 -0
@@ -1,23 +1,304 @@
1
- import { AtomicWriteConflict, atomicBatch, rowUnchanged } from "./database/batch.mjs";
1
+ import { c as __exportAll } from "./runner-CuG8o1uW.mjs";
2
+ import { getRequestContext } from "./request-context.mjs";
3
+ import { AtomicWriteConflict, atomicBatch, prepareAtomicChecks, rowUnchanged } from "./database/batch.mjs";
2
4
  import { t as validateIdentifier } from "./validate-Co3j6T_K.mjs";
3
5
  import { r as isI18nEnabled } from "./config-XW5tMrH8.mjs";
4
- import { r as encodeBase64, t as decodeBase64 } from "./base64-Cz-aU0X1.mjs";
5
- import { n as ScheduledNotDueError, t as DinewayValidationError } from "./types-RFzE_V1M.mjs";
6
- import { t as contentWriteChecks } from "./atomic-authority-CnBQJ14T.mjs";
7
- import { o as invalidateCollectionCache, s as invalidateCommentObjectCache } from "./object-cache-mxCW-Rpt.mjs";
8
- import { t as RevisionRepository } from "./revision-W6FDfDqx.mjs";
9
- import { t as ContentRepository } from "./content-CIKsrvU9.mjs";
10
- import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-C8vSD_5L.mjs";
11
- import { t as UserRepository } from "./user-Btai9rl3.mjs";
12
- import { n as stableStringify, t as buildStableHash } from "./stable-hash-B9Tbb2f_.mjs";
13
- import { t as RedirectRepository } from "./redirect-BQFa1THe.mjs";
14
- import { r as requestCached } from "./request-cache-8_ifFzVw.mjs";
15
- import { t as BylineRepository } from "./byline-TYk2kad6.mjs";
16
- import { r as parseAllowedMimeTypes, t as matchesMimeAllowlist } from "./mime-BnVhH671.mjs";
17
- import { i as invalidateRedirectCache } from "./cache-B5NSHhxG.mjs";
18
- import { t as SeoRepository } from "./seo-Bs_DUxJf.mjs";
6
+ import { i as resolveContentPartition, n as contentDigest, o as ContentStorageError, s as ContentStorageReplay } from "./config-6R0bchVE.mjs";
7
+ import { d as contentPartitionWritable, p as readContentPartitionRoute, r as getContentStorage } from "./runtime-Ch5G-tnG.mjs";
8
+ import { n as readRevisionDataBatch, r as storedRevisionIndex, t as readRevisionData } from "./revisions-CQ7rMP5d.mjs";
9
+ import { r as encodeBase64, t as decodeBase64 } from "./base64-qvSs0Gxy.mjs";
10
+ import { n as ScheduledNotDueError, t as DinewayValidationError } from "./types-BI3ULB3A.mjs";
11
+ import { t as contentWriteChecks } from "./atomic-authority-Bf5QZboB.mjs";
12
+ import { a as prepareContentHookEvents, s as contentStorageHookSnapshotSchema, t as ContentRepository } from "./content-BigS8BAv.mjs";
13
+ import { r as requestCached } from "./request-cache-CizvDoxV.mjs";
14
+ import { o as invalidateCollectionCache, s as invalidateCommentObjectCache } from "./object-cache-DyI1SOBK.mjs";
15
+ import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-Bb56aCtB.mjs";
16
+ import { t as BylineRepository } from "./byline-3qjp1-oa.mjs";
17
+ import { i as storedContentSeo, r as snapshotOwnedContentMetadata, t as contentEventBylines } from "./owned-metadata-BPmUjZqI.mjs";
18
+ import { t as RevisionRepository } from "./revision-B_HYO2AE.mjs";
19
+ import { t as UserRepository } from "./user-Bl2_8rhJ.mjs";
20
+ import { i as snapshotPartitionTerms, n as prepareContentTerms, r as snapshotContentTermChanges } from "./terms-EskuqbKE.mjs";
21
+ import { t as RedirectRepository } from "./redirect-CJ-FAbNK.mjs";
22
+ import { i as invalidateRedirectCache } from "./cache-DsEbwFVE.mjs";
23
+ import { r as parseAllowedMimeTypes, t as matchesMimeAllowlist } from "./mime-FkfazULS.mjs";
24
+ import { n as extractSearchableFields } from "./text-extraction-CdqMGYQK.mjs";
25
+ import { a as contentVersionSchema } from "./version-store-BXv2D0de.mjs";
26
+ import { r as markContentWriteReplay, t as beginContentWriteIntent } from "./write-intent-DuHVqks9.mjs";
27
+ import { t as SeoRepository } from "./seo-Cv7ud_m2.mjs";
19
28
  import { sql } from "kysely";
29
+ import { ulid } from "ulidx";
30
+ import { z } from "zod";
20
31
 
32
+ //#region src/content-storage/partition-snapshot.ts
33
+ /** Resolver code sees only declared snapshots; their primary rows are fenced at activation. */
34
+ async function snapshotPartitionDependencies(db, collection, item, rule, changes) {
35
+ const checks = [];
36
+ const dependencies = {
37
+ taxonomies: {},
38
+ references: {}
39
+ };
40
+ if ("field" in rule.partitionBy) return {
41
+ dependencies,
42
+ checks
43
+ };
44
+ const taxonomies = {};
45
+ for (const name of rule.partitionBy.taxonomies ?? []) {
46
+ const snapshot = await snapshotPartitionTerms(db, collection, item.id, name, item.locale ?? "en", changes?.[name]);
47
+ taxonomies[name] = snapshot.terms;
48
+ checks.push(...snapshot.checks);
49
+ }
50
+ const references = {};
51
+ for (const [field, definition] of Object.entries(rule.partitionBy.references ?? {})) {
52
+ const value = item.data[field];
53
+ if (value == null || value === "") {
54
+ references[field] = null;
55
+ continue;
56
+ }
57
+ const id = typeof value === "string" ? value : z.object({
58
+ id: z.string(),
59
+ collection: z.literal(definition.collection).optional()
60
+ }).parse(value).id;
61
+ const snapshot = await new ContentRepository(db).snapshot(definition.collection, id);
62
+ if (!snapshot) throw new ContentStorageError("INVALID_PARTITION", `Partition reference ${field} does not exist.`);
63
+ checks.push(snapshot.check);
64
+ const relatedTerms = {};
65
+ for (const name of definition.taxonomies ?? []) {
66
+ const terms = await snapshotPartitionTerms(db, definition.collection, id, name, snapshot.item.locale ?? "en");
67
+ relatedTerms[name] = terms.terms;
68
+ checks.push(...terms.checks);
69
+ }
70
+ references[field] = {
71
+ collection: definition.collection,
72
+ id,
73
+ data: z.record(z.string(), z.json()).parse(snapshot.item.data),
74
+ taxonomies: relatedTerms
75
+ };
76
+ }
77
+ dependencies.taxonomies = taxonomies;
78
+ dependencies.references = references;
79
+ return {
80
+ dependencies,
81
+ checks
82
+ };
83
+ }
84
+
85
+ //#endregion
86
+ //#region src/content-storage/projection.ts
87
+ /** A central list/search projection; full bodies are loaded through the directory. */
88
+ function contentProjectionValues(item, fields, full = false) {
89
+ const values = {
90
+ id: item.id,
91
+ slug: item.slug,
92
+ status: item.status,
93
+ author_id: item.authorId,
94
+ primary_byline_id: item.primaryBylineId,
95
+ created_at: item.createdAt,
96
+ updated_at: item.updatedAt,
97
+ published_at: item.publishedAt,
98
+ scheduled_at: item.scheduledAt,
99
+ version: item.version,
100
+ live_revision_id: item.liveRevisionId,
101
+ draft_revision_id: item.draftRevisionId,
102
+ locale: item.locale ?? "en",
103
+ translation_group: item.translationGroup
104
+ };
105
+ for (const field of fields) {
106
+ if (!full && field.type === "portableText" && field.searchable === 1 && field.unique !== 1) {
107
+ values[field.slug] = extractSearchableFields(item.data, [field.slug])[field.slug] ?? "";
108
+ continue;
109
+ }
110
+ const value = full || field.column_type !== "JSON" || field.unique === 1 || field.searchable === 1 ? item.data[field.slug] : void 0;
111
+ values[field.slug] = value == null ? field.required ? "null" : null : typeof value === "object" ? JSON.stringify(value) : value;
112
+ }
113
+ return values;
114
+ }
115
+ function prepareContentProjection(db, collection, item, fields, create, full = false) {
116
+ const values = contentProjectionValues(item, fields, full);
117
+ const columns = Object.keys(values);
118
+ return create ? sql`INSERT INTO ${sql.table(`ec_${collection}`)} (${sql.join(columns.map((column) => sql.ref(column)))}) VALUES (${sql.join(columns.map((column) => values[column] === null ? sql`NULL` : sql`${values[column]}`))})`.compile(db) : sql`UPDATE ${sql.table(`ec_${collection}`)} SET ${sql.join(columns.filter((column) => column !== "id").map((column) => sql`${sql.ref(column)} = ${values[column] === null ? sql`NULL` : sql`${values[column]}`} `))} WHERE id = ${item.id}`.compile(db);
119
+ }
120
+
121
+ //#endregion
122
+ //#region src/content-storage/prepare-write.ts
123
+ async function prepareRoutedContentWrite(options) {
124
+ const { db, collection, item } = options;
125
+ const storage = getContentStorage(db, collection);
126
+ if (!storage) return void 0;
127
+ const location = await storage.coordinator.locate(collection, item.id);
128
+ const rootVersion = options.rootVersion ?? ulid();
129
+ const operationId = options.operationId ?? rootVersion;
130
+ const principalId = getRequestContext()?.writePrincipal?.id ?? "system";
131
+ const partitionSnapshot = await snapshotPartitionDependencies(db, collection, item, storage.runtime.config.rules[collection], options.terms);
132
+ const resolved = await resolveContentPartition(storage.runtime.config, {
133
+ collection,
134
+ id: item.id,
135
+ data: contentVersionSchema.shape.data.parse(item.data),
136
+ dependencies: partitionSnapshot.dependencies
137
+ }, storage.runtime.resolvers);
138
+ if (!resolved) throw new Error("Content storage rule is unavailable.");
139
+ const partition = await readContentPartitionRoute(db, collection, resolved.partition);
140
+ if (partition.route.state === "frozen") throw new ContentStorageError("FROZEN", "Content in this partition is temporarily read-only during migration. Please retry shortly.");
141
+ if (partition.route.target_store !== resolved.store) throw new Error("The partition mapping requires an explicit storage migration.");
142
+ const destination = {
143
+ partition: resolved.partition,
144
+ store: partition.route.store
145
+ };
146
+ if (partition.route.store === "primary") {
147
+ const data = contentVersionSchema.shape.data.parse(item.data);
148
+ const command = {
149
+ collection,
150
+ entryId: item.id,
151
+ store: "primary",
152
+ partition: destination.partition,
153
+ partitionEpoch: partition.route.epoch,
154
+ routingVersion: storage.runtime.config.version,
155
+ version: rootVersion,
156
+ digest: await contentDigest(data),
157
+ operationId,
158
+ principalId,
159
+ expectedVersion: location?.version ?? null
160
+ };
161
+ const history = location && location.store !== "primary" ? await db.selectFrom("revisions").selectAll().where("collection", "=", collection).where("entry_id", "=", item.id).execute() : [];
162
+ const snapshots = await readRevisionDataBatch(db, history);
163
+ const effects = options.effects ? await prepareContentHookEvents(db, command, options.effects.snapshot, options.effects.targets) : { statements: [] };
164
+ return {
165
+ checks: [
166
+ ...options.checks,
167
+ ...partitionSnapshot.checks,
168
+ partition.check,
169
+ ...history.map((row) => rowUnchanged("revisions", row))
170
+ ],
171
+ statements: [
172
+ ...history.map((row, index) => db.updateTable("revisions").set({ data: JSON.stringify(snapshots[index]) }).where("id", "=", row.id).compile()),
173
+ ...options.primaryStatements,
174
+ ...effects.statements,
175
+ sql`INSERT INTO _dineway_content_locations (collection, entry_id, store, partition, routing_version, version, digest) VALUES (${collection}, ${item.id}, 'primary', ${destination.partition}, ${storage.runtime.config.version}, ${rootVersion}, ${command.digest}) ON CONFLICT (collection, entry_id) DO UPDATE SET store=excluded.store, partition=excluded.partition, routing_version=excluded.routing_version, version=excluded.version, digest=excluded.digest`.compile(db),
176
+ sql`INSERT INTO _dineway_content_operations (id, collection, entry_id, command, state, created_at, updated_at) VALUES (${operationId}, ${collection}, ${item.id}, ${JSON.stringify(command)}, 'committed', ${item.updatedAt}, ${item.updatedAt})`.compile(db)
177
+ ]
178
+ };
179
+ }
180
+ const metadata = {
181
+ slug: item.slug,
182
+ status: item.status,
183
+ authorId: item.authorId,
184
+ primaryBylineId: item.primaryBylineId,
185
+ createdAt: item.createdAt,
186
+ updatedAt: item.updatedAt,
187
+ publishedAt: item.publishedAt,
188
+ scheduledAt: item.scheduledAt,
189
+ liveRevisionId: item.liveRevisionId,
190
+ draftRevisionId: item.draftRevisionId,
191
+ version: item.version,
192
+ locale: item.locale,
193
+ translationGroup: item.translationGroup
194
+ };
195
+ const moving = !!location && location.store !== destination.store;
196
+ const existingRevisions = moving ? await db.selectFrom("revisions").selectAll().where("collection", "=", collection).where("entry_id", "=", item.id).execute() : [];
197
+ const history = [];
198
+ const retainedRevisions = existingRevisions.filter((revision) => !options.revisions.some((next) => next.id === revision.id));
199
+ const retainedData = await readRevisionDataBatch(db, retainedRevisions);
200
+ for (const [index, revision] of retainedRevisions.entries()) history.push({
201
+ id: revision.id,
202
+ data: retainedData[index],
203
+ authorId: revision.author_id ?? void 0
204
+ });
205
+ const historicalIds = new Set(history.map((revision) => revision.id));
206
+ const revisions = await Promise.all([...history, ...options.revisions].map(async (revision) => {
207
+ const data = contentVersionSchema.shape.data.parse(revision.data);
208
+ const version = historicalIds.has(revision.id) || revision.replace ? await contentDigest({
209
+ rootVersion,
210
+ revisionId: revision.id
211
+ }) : revision.id;
212
+ return {
213
+ revision,
214
+ data,
215
+ reference: {
216
+ collection,
217
+ entryId: item.id,
218
+ store: destination.store,
219
+ partition: destination.partition,
220
+ routingVersion: storage.runtime.config.version,
221
+ version,
222
+ digest: await contentDigest(data)
223
+ }
224
+ };
225
+ }));
226
+ const payload = contentVersionSchema.shape.data.parse({
227
+ ...item.data,
228
+ _dineway: {
229
+ ...metadata,
230
+ ...options.owned ? { owned: options.owned } : {},
231
+ partitionDependencies: partitionSnapshot.dependencies,
232
+ revisions: revisions.map((revision) => ({
233
+ id: revision.revision.id,
234
+ ...revision.reference
235
+ }))
236
+ }
237
+ });
238
+ const command = {
239
+ partitionEpoch: partition.route.epoch,
240
+ collection,
241
+ entryId: item.id,
242
+ ...destination,
243
+ routingVersion: storage.runtime.config.version,
244
+ version: rootVersion,
245
+ digest: await contentDigest(payload),
246
+ operationId,
247
+ principalId,
248
+ expectedVersion: location?.version ?? null
249
+ };
250
+ const projection = prepareContentProjection(db, collection, item, options.fields, options.create);
251
+ const effects = options.effects ? await prepareContentHookEvents(db, command, options.effects.snapshot, options.effects.targets) : { statements: [] };
252
+ return storage.coordinator.prepareCommit({
253
+ command,
254
+ data: payload
255
+ }, {
256
+ authorize: async () => options.create ? [] : contentWriteChecks(collection, item.id, "edit"),
257
+ prepare: async () => {
258
+ const statements = [];
259
+ const store = storage.stores[destination.store];
260
+ for (const revision of revisions) {
261
+ await store.prepare({
262
+ command: {
263
+ ...revision.reference,
264
+ kind: "revision",
265
+ operationId: await contentDigest({
266
+ operationId,
267
+ revisionId: revision.revision.id
268
+ }),
269
+ principalId,
270
+ expectedVersion: null
271
+ },
272
+ data: revision.data
273
+ });
274
+ statements.push(historicalIds.has(revision.revision.id) || revision.revision.replace ? db.updateTable("revisions").set({ data: storedRevisionIndex(revision.reference) }).where("id", "=", revision.revision.id).compile() : db.insertInto("revisions").values({
275
+ id: revision.revision.id,
276
+ collection,
277
+ entry_id: item.id,
278
+ data: storedRevisionIndex(revision.reference),
279
+ author_id: revision.revision.authorId ?? null,
280
+ created_at: item.updatedAt
281
+ }).compile());
282
+ }
283
+ statements.push(projection);
284
+ return {
285
+ checks: [
286
+ ...options.checks,
287
+ ...partitionSnapshot.checks,
288
+ ...existingRevisions.map((revision) => rowUnchanged("revisions", revision)),
289
+ ...moving ? [sql`(SELECT COUNT(*) FROM revisions WHERE collection = ${collection} AND entry_id = ${item.id}) = ${existingRevisions.length}`] : []
290
+ ],
291
+ statements: [
292
+ ...statements,
293
+ ...options.globalStatements,
294
+ ...effects.statements
295
+ ]
296
+ };
297
+ }
298
+ });
299
+ }
300
+
301
+ //#endregion
21
302
  //#region src/api/rev.ts
22
303
  /**
23
304
  * Generate a _rev token from a content item's version and updatedAt.
@@ -135,6 +416,38 @@ async function validateMediaFields(db, collectionSlug, data) {
135
416
 
136
417
  //#endregion
137
418
  //#region src/api/handlers/content.ts
419
+ function contentStorageFailure(error) {
420
+ if (!(error instanceof ContentStorageError)) return void 0;
421
+ return {
422
+ success: false,
423
+ error: {
424
+ code: error.code === "INVALID_PARTITION" ? "VALIDATION_ERROR" : error.code === "CONFLICT" || error.code === "ROUTE_CHANGED" ? "CONFLICT" : "CONTENT_STORAGE_UNAVAILABLE",
425
+ message: {
426
+ FROZEN: "This content is temporarily read-only. Please retry shortly.",
427
+ UNAVAILABLE: "Content is temporarily unavailable. Please retry shortly.",
428
+ INVALID_CONFIG: "Content storage is temporarily unavailable. Please retry shortly.",
429
+ INVALID_PARTITION: "The fields used to organize this content are missing or inconsistent. Check them and try again.",
430
+ ROUTE_CHANGED: "Content routing changed. Reload and try again.",
431
+ CONFLICT: "Content changed during this operation. Reload and try again."
432
+ }[error.code]
433
+ }
434
+ };
435
+ }
436
+ async function commitRoutedContent(db, collection, input, metadata = {}) {
437
+ try {
438
+ const prepared = await prepareContentWrite(db, collection, {
439
+ ...input,
440
+ bylines: metadata.bylines,
441
+ seo: metadata.hasSeo ? metadata.seo : void 0
442
+ });
443
+ await atomicBatch(db, prepared.batch);
444
+ prepared.afterCommit();
445
+ return handleContentGet(db, collection, prepared.id);
446
+ } catch (error) {
447
+ if (error instanceof ContentStorageReplay) return markContentWriteReplay(await handleContentGet(db, collection, error.location.entryId));
448
+ throw error;
449
+ }
450
+ }
138
451
  /**
139
452
  * Extract a slug source (title or name) from content data.
140
453
  * Returns null if no suitable string field is found.
@@ -400,6 +713,8 @@ async function handleContentList(db, collection, params) {
400
713
  }
401
714
  };
402
715
  } catch (error) {
716
+ const storageError = contentStorageFailure(error);
717
+ if (storageError) return storageError;
403
718
  console.error("Content list error:", error);
404
719
  return {
405
720
  success: false,
@@ -427,6 +742,8 @@ async function handleContentAuthors(db, collection) {
427
742
  })).toSorted((a, b) => (a.name ?? a.email).localeCompare(b.name ?? b.email)) }
428
743
  };
429
744
  } catch (error) {
745
+ const storageError = contentStorageFailure(error);
746
+ if (storageError) return storageError;
430
747
  console.error("Content authors error:", error);
431
748
  return {
432
749
  success: false,
@@ -460,6 +777,8 @@ async function handleContentGet(db, collection, id, locale) {
460
777
  }
461
778
  };
462
779
  } catch (error) {
780
+ const storageError = contentStorageFailure(error);
781
+ if (storageError) return storageError;
463
782
  console.error("Content get error:", error);
464
783
  return {
465
784
  success: false,
@@ -494,6 +813,8 @@ async function handleContentGetIncludingTrashed(db, collection, id, locale) {
494
813
  }
495
814
  };
496
815
  } catch (error) {
816
+ const storageError = contentStorageFailure(error);
817
+ if (storageError) return storageError;
497
818
  console.error("Content get error:", error);
498
819
  return {
499
820
  success: false,
@@ -527,6 +848,25 @@ async function handleContentCreate(db, collection, body) {
527
848
  if (fieldCheck) return fieldCheck;
528
849
  const mimeCheck = await validateMediaFields(db, collection, body.data);
529
850
  if (!mimeCheck.success) return mimeCheck;
851
+ if (getContentStorage(db, collection)) {
852
+ if (body.status && body.status !== "draft" && body.status !== "published") throw new DinewayValidationError("Content must be created as a draft or published item.");
853
+ return await commitRoutedContent(db, collection, {
854
+ operationId: body.operationId,
855
+ data: body.data,
856
+ terms: body.terms,
857
+ slug: body.slug,
858
+ authorId: body.authorId,
859
+ locale: body.locale,
860
+ translationOf: body.translationOf,
861
+ createdAt: body.createdAt,
862
+ publishedAt: body.publishedAt,
863
+ publish: body.status === "published"
864
+ }, {
865
+ bylines: body.bylines,
866
+ seo: body.seo,
867
+ hasSeo
868
+ });
869
+ }
530
870
  const repo = new ContentRepository(db);
531
871
  let slug = body.slug;
532
872
  if (!slug) {
@@ -546,6 +886,11 @@ async function handleContentCreate(db, collection, body) {
546
886
  });
547
887
  const checks = [...prepared.batch.checks ?? [], ...configuration.checks];
548
888
  const statements = [...prepared.batch.statements];
889
+ if (body.terms) {
890
+ const terms = await prepareContentTerms(db, collection, prepared.id, body.terms, body.locale ?? "en");
891
+ checks.push(...terms.checks ?? []);
892
+ statements.push(...terms.statements);
893
+ }
549
894
  if (usesDraftRevisions && (!body.status || body.status === "draft")) {
550
895
  const draft = await repo.prepareDraftSnapshot(collection, prepared.id, body.authorId);
551
896
  checks.push(...draft.checks ?? []);
@@ -577,6 +922,8 @@ async function handleContentCreate(db, collection, body) {
577
922
  }
578
923
  };
579
924
  } catch (error) {
925
+ const storageError = contentStorageFailure(error);
926
+ if (storageError) return storageError;
580
927
  console.error("Content create error:", error);
581
928
  return {
582
929
  success: false,
@@ -613,6 +960,30 @@ async function handleContentUpdate(db, collection, id, body, options = {}) {
613
960
  }
614
961
  const repo = new ContentRepository(db);
615
962
  const resolvedId = await resolveId(repo, collection, id, body.locale) ?? id;
963
+ if (getContentStorage(db, collection)) {
964
+ const existing = await repo.findById(collection, resolvedId);
965
+ if (!existing) throw new ContentUpdateApiError("NOT_FOUND", `Content item not found: ${id}`);
966
+ if (body.status && body.status !== "draft" && body.status !== "published") throw new DinewayValidationError("Use the scheduling endpoint to change scheduled content.");
967
+ return await commitRoutedContent(db, collection, {
968
+ operationId: body.operationId,
969
+ id: resolvedId,
970
+ data: body.data,
971
+ terms: body.terms,
972
+ slug: body.slug,
973
+ authorId: body.authorId,
974
+ expectedRev: body._rev,
975
+ publishedAt: body.publishedAt,
976
+ stageDraft: !!options.stageDraft && !!body.data,
977
+ reuseDraftRevision: options.skipRevision,
978
+ publish: body.status === "published",
979
+ unpublish: existing.status === "published" && body.status === "draft",
980
+ status: body.status === "draft" ? "draft" : void 0
981
+ }, {
982
+ bylines: body.bylines,
983
+ seo: body.seo,
984
+ hasSeo
985
+ });
986
+ }
616
987
  const snapshot = await repo.snapshot(collection, resolvedId);
617
988
  if (!snapshot) throw new ContentUpdateApiError("NOT_FOUND", `Content item not found: ${id}`);
618
989
  const existing = snapshot.item;
@@ -624,6 +995,11 @@ async function handleContentUpdate(db, collection, id, body, options = {}) {
624
995
  ...contentWriteChecks(collection, resolvedId, "edit")
625
996
  ];
626
997
  const statements = [];
998
+ if (body.terms) {
999
+ const terms = await prepareContentTerms(db, collection, resolvedId, body.terms, existing.locale ?? "en");
1000
+ checks.push(...terms.checks ?? []);
1001
+ statements.push(...terms.statements);
1002
+ }
627
1003
  const stageDraft = options.stageDraft && body.data && await collectionSupportsRevisions(db, collection);
628
1004
  if (stageDraft) {
629
1005
  const revisions = new RevisionRepository(db);
@@ -686,6 +1062,8 @@ async function handleContentUpdate(db, collection, id, body, options = {}) {
686
1062
  }
687
1063
  };
688
1064
  } catch (error) {
1065
+ const storageError = contentStorageFailure(error);
1066
+ if (storageError) return storageError;
689
1067
  if (error instanceof AtomicWriteConflict) return {
690
1068
  success: false,
691
1069
  error: {
@@ -722,6 +1100,43 @@ async function handleContentDuplicate(db, collection, id, authorId) {
722
1100
  const hasSeo = configuration.row?.has_seo === 1;
723
1101
  const repo = new ContentRepository(db);
724
1102
  const resolvedId = await resolveId(repo, collection, id) ?? id;
1103
+ if (getContentStorage(db, collection)) {
1104
+ const snapshot = await repo.snapshot(collection, resolvedId);
1105
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
1106
+ const data = { ...snapshot.item.data };
1107
+ if (typeof data.title === "string") data.title += " (Copy)";
1108
+ else if (typeof data.name === "string") data.name += " (Copy)";
1109
+ const terms = await snapshotContentTermChanges(db, collection, resolvedId);
1110
+ const metadata = await snapshotOwnedContentMetadata(db, collection, resolvedId);
1111
+ const bylines = await new BylineRepository(db).getContentBylines(collection, resolvedId, { locale: snapshot.item.locale ?? void 0 });
1112
+ const seo = hasSeo ? await new SeoRepository(db).get(collection, resolvedId) : void 0;
1113
+ const prepared = await prepareContentWrite(db, collection, {
1114
+ data,
1115
+ terms: terms.changes,
1116
+ bylines: bylines.map((credit) => ({
1117
+ bylineId: credit.byline.id,
1118
+ roleLabel: credit.roleLabel
1119
+ })),
1120
+ seo: seo ? {
1121
+ ...seo,
1122
+ canonical: null
1123
+ } : void 0,
1124
+ authorId: authorId ?? snapshot.item.authorId,
1125
+ locale: snapshot.item.locale ?? void 0
1126
+ });
1127
+ await atomicBatch(db, {
1128
+ checks: [
1129
+ ...prepared.batch.checks ?? [],
1130
+ ...metadata.checks,
1131
+ ...terms.checks,
1132
+ snapshot.check,
1133
+ ...contentWriteChecks(collection, resolvedId, "edit")
1134
+ ],
1135
+ statements: prepared.batch.statements
1136
+ });
1137
+ prepared.afterCommit();
1138
+ return await handleContentGet(db, collection, prepared.id);
1139
+ }
725
1140
  const prepared = await repo.prepareDuplicate(collection, resolvedId, authorId);
726
1141
  const bylines = await new BylineRepository(db).prepareCopyContentBylines(collection, resolvedId, prepared.id);
727
1142
  const checks = [
@@ -750,6 +1165,8 @@ async function handleContentDuplicate(db, collection, id, authorId) {
750
1165
  data: { item: duplicate }
751
1166
  };
752
1167
  } catch (err) {
1168
+ const storageError = contentStorageFailure(err);
1169
+ if (storageError) return storageError;
753
1170
  if (err instanceof DinewayValidationError) return {
754
1171
  success: false,
755
1172
  error: {
@@ -793,6 +1210,8 @@ async function handleContentDelete(db, collection, id) {
793
1210
  }
794
1211
  };
795
1212
  } catch (error) {
1213
+ const storageError = contentStorageFailure(error);
1214
+ if (storageError) return storageError;
796
1215
  console.error("Content delete error:", error);
797
1216
  return {
798
1217
  success: false,
@@ -826,6 +1245,8 @@ async function handleContentRestore(db, collection, id) {
826
1245
  }
827
1246
  };
828
1247
  } catch (error) {
1248
+ const storageError = contentStorageFailure(error);
1249
+ if (storageError) return storageError;
829
1250
  console.error("Content restore error:", error);
830
1251
  return {
831
1252
  success: false,
@@ -844,22 +1265,8 @@ async function handleContentPermanentDelete(db, collection, id) {
844
1265
  try {
845
1266
  const repo = new ContentRepository(db);
846
1267
  const resolvedId = await resolveIdIncludingTrashed(repo, collection, id) ?? id;
847
- const snapshot = await repo.snapshot(collection, resolvedId, true);
848
- const deleted = !!snapshot?.deleted;
849
- if (snapshot && deleted) {
850
- await atomicBatch(db, {
851
- checks: [snapshot.check, ...contentWriteChecks(collection, resolvedId, "permanent")],
852
- statements: [
853
- sql`DELETE FROM ${sql.table(`ec_${collection}`)} WHERE id = ${resolvedId} AND deleted_at IS NOT NULL`.compile(db),
854
- db.deleteFrom("_dineway_seo").where("collection", "=", collection).where("content_id", "=", resolvedId).compile(),
855
- db.deleteFrom("_dineway_comments").where("collection", "=", collection).where("content_id", "=", resolvedId).compile(),
856
- db.deleteFrom("revisions").where("collection", "=", collection).where("entry_id", "=", resolvedId).compile(),
857
- db.deleteFrom("_dineway_content_bylines").where("collection_slug", "=", collection).where("content_id", "=", resolvedId).compile()
858
- ]
859
- });
860
- invalidateCollectionCache(collection);
861
- invalidateCommentObjectCache();
862
- }
1268
+ const deleted = await repo.permanentDelete(collection, resolvedId);
1269
+ if (deleted) invalidateCommentObjectCache();
863
1270
  if (!deleted) return {
864
1271
  success: false,
865
1272
  error: {
@@ -875,6 +1282,8 @@ async function handleContentPermanentDelete(db, collection, id) {
875
1282
  }
876
1283
  };
877
1284
  } catch (error) {
1285
+ const storageError = contentStorageFailure(error);
1286
+ if (storageError) return storageError;
878
1287
  console.error("Content permanent delete error:", error);
879
1288
  return {
880
1289
  success: false,
@@ -913,6 +1322,8 @@ async function handleContentListTrashed(db, collection, options = {}) {
913
1322
  }
914
1323
  };
915
1324
  } catch (error) {
1325
+ const storageError = contentStorageFailure(error);
1326
+ if (storageError) return storageError;
916
1327
  console.error("Content list trashed error:", error);
917
1328
  return {
918
1329
  success: false,
@@ -933,6 +1344,8 @@ async function handleContentCountTrashed(db, collection) {
933
1344
  data: { count: await new ContentRepository(db).countTrashed(collection) }
934
1345
  };
935
1346
  } catch (error) {
1347
+ const storageError = contentStorageFailure(error);
1348
+ if (storageError) return storageError;
936
1349
  console.error("Content count trashed error:", error);
937
1350
  return {
938
1351
  success: false,
@@ -957,6 +1370,8 @@ async function handleContentSchedule(db, collection, id, scheduledAt) {
957
1370
  data: { item }
958
1371
  };
959
1372
  } catch (error) {
1373
+ const storageError = contentStorageFailure(error);
1374
+ if (storageError) return storageError;
960
1375
  if (error instanceof DinewayValidationError) return {
961
1376
  success: false,
962
1377
  error: {
@@ -988,6 +1403,8 @@ async function handleContentUnschedule(db, collection, id) {
988
1403
  data: { item }
989
1404
  };
990
1405
  } catch (error) {
1406
+ const storageError = contentStorageFailure(error);
1407
+ if (storageError) return storageError;
991
1408
  if (error instanceof DinewayValidationError) return {
992
1409
  success: false,
993
1410
  error: {
@@ -1016,6 +1433,26 @@ async function prepareContentPublication(db, collection, id, options = {}) {
1016
1433
  const configuration = await contentWriteConfiguration(db, collection);
1017
1434
  const repo = new ContentRepository(db);
1018
1435
  const resolvedId = await resolveId(repo, collection, id) ?? id;
1436
+ if (getContentStorage(db, collection)) {
1437
+ const snapshot = await repo.snapshot(collection, resolvedId);
1438
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
1439
+ if (options.requireScheduledDue && (!snapshot.item.scheduledAt || snapshot.item.scheduledAt > (/* @__PURE__ */ new Date()).toISOString())) throw new ScheduledNotDueError();
1440
+ const prepared = await prepareContentWrite(db, collection, {
1441
+ id: resolvedId,
1442
+ publish: true,
1443
+ publishedAt: options.publishedAt,
1444
+ expectedRev: encodeRev(snapshot.item)
1445
+ });
1446
+ return {
1447
+ resolvedId,
1448
+ previous: snapshot.item,
1449
+ slugChanged: !!snapshot.item.slug && snapshot.item.slug !== prepared.item.slug,
1450
+ batch: {
1451
+ checks: [...prepared.batch.checks ?? [], snapshot.check],
1452
+ statements: [...prepared.batch.statements]
1453
+ }
1454
+ };
1455
+ }
1019
1456
  const prepared = await repo.preparePublish(collection, resolvedId, options.publishedAt, options.requireScheduledDue);
1020
1457
  const statements = [...prepared.batch.statements];
1021
1458
  const existing = prepared.previous;
@@ -1047,6 +1484,8 @@ async function handleContentPublish(db, collection, id, options = {}) {
1047
1484
  data: { item }
1048
1485
  };
1049
1486
  } catch (error) {
1487
+ const storageError = contentStorageFailure(error);
1488
+ if (storageError) return storageError;
1050
1489
  if (error instanceof DinewayValidationError) return {
1051
1490
  success: false,
1052
1491
  error: {
@@ -1081,6 +1520,10 @@ async function handleContentUnpublish(db, collection, id) {
1081
1520
  try {
1082
1521
  const repo = new ContentRepository(db);
1083
1522
  const resolvedId = await resolveId(repo, collection, id) ?? id;
1523
+ if (getContentStorage(db, collection)) return await commitRoutedContent(db, collection, {
1524
+ id: resolvedId,
1525
+ unpublish: true
1526
+ });
1084
1527
  const item = await repo.unpublish(collection, resolvedId);
1085
1528
  await hydrateSeo(db, collection, item, await collectionHasSeo(db, collection));
1086
1529
  return {
@@ -1088,6 +1531,8 @@ async function handleContentUnpublish(db, collection, id) {
1088
1531
  data: { item }
1089
1532
  };
1090
1533
  } catch (error) {
1534
+ const storageError = contentStorageFailure(error);
1535
+ if (storageError) return storageError;
1091
1536
  if (error instanceof DinewayValidationError) return {
1092
1537
  success: false,
1093
1538
  error: {
@@ -1115,6 +1560,8 @@ async function handleContentCountScheduled(db, collection) {
1115
1560
  data: { count: await new ContentRepository(db).countScheduled(collection) }
1116
1561
  };
1117
1562
  } catch (error) {
1563
+ const storageError = contentStorageFailure(error);
1564
+ if (storageError) return storageError;
1118
1565
  console.error("Content count scheduled error:", error);
1119
1566
  return {
1120
1567
  success: false,
@@ -1139,6 +1586,8 @@ async function handleContentDiscardDraft(db, collection, id) {
1139
1586
  data: { item }
1140
1587
  };
1141
1588
  } catch (error) {
1589
+ const storageError = contentStorageFailure(error);
1590
+ if (storageError) return storageError;
1142
1591
  if (error instanceof DinewayValidationError) return {
1143
1592
  success: false,
1144
1593
  error: {
@@ -1181,6 +1630,8 @@ async function handleContentCompare(db, collection, id) {
1181
1630
  }
1182
1631
  };
1183
1632
  } catch (error) {
1633
+ const storageError = contentStorageFailure(error);
1634
+ if (storageError) return storageError;
1184
1635
  console.error("Content compare error:", error);
1185
1636
  return {
1186
1637
  success: false,
@@ -1234,6 +1685,8 @@ async function handleContentTranslations(db, collection, id) {
1234
1685
  }
1235
1686
  };
1236
1687
  } catch (error) {
1688
+ const storageError = contentStorageFailure(error);
1689
+ if (storageError) return storageError;
1237
1690
  if (error instanceof Error) console.error("Content translations error:", error);
1238
1691
  return {
1239
1692
  success: false,
@@ -1274,113 +1727,367 @@ function prepareNonTranslatableFields(db, collectionSlug, updatedItemId, transla
1274
1727
  }
1275
1728
 
1276
1729
  //#endregion
1277
- //#region src/site-context/action-hash.ts
1278
- async function buildStableActionHash(value) {
1279
- return buildStableHash(value);
1730
+ //#region src/api/handlers/content-write.ts
1731
+ var content_write_exports = /* @__PURE__ */ __exportAll({
1732
+ prepareContentWrite: () => prepareContentWrite,
1733
+ preparedContentReview: () => preparedContentReview
1734
+ });
1735
+ const fieldData = (data) => Object.fromEntries(Object.entries(data).filter(([key]) => !key.startsWith("_")));
1736
+ const reviews = /* @__PURE__ */ new WeakMap();
1737
+ function preparedContentReview(write) {
1738
+ const stored = reviews.get(write);
1739
+ if (!stored) throw new DinewayValidationError("Review requires an unmodified prepared content write.");
1740
+ return structuredClone(stored);
1280
1741
  }
1281
-
1282
- //#endregion
1283
- //#region src/site-context/review-payload.ts
1284
- var ReviewPayloadBuilder = class {
1285
- constructor(handlers) {
1286
- this.handlers = handlers;
1742
+ /** Prepare a draft or direct backing-row edit without committing site-owned writes separately. */
1743
+ async function prepareContentWrite(db, collection, input) {
1744
+ return prepareContentWriteInternal(db, collection, input, true);
1745
+ }
1746
+ async function prepareContentWriteInternal(db, collection, input, syncTranslations) {
1747
+ const configuration = await contentWriteConfiguration(db, collection);
1748
+ const supports = JSON.parse(configuration.row?.supports ?? "[]");
1749
+ const usesRevisions = Array.isArray(supports) && supports.includes("revisions");
1750
+ if (input.seo && configuration.row?.has_seo !== 1) throw new DinewayValidationError("SEO is not enabled for this content type.");
1751
+ if (input.status !== void 0 && input.status !== "draft") throw new DinewayValidationError("Prepared status changes must use publish or unpublish.");
1752
+ if (input.publish && input.unpublish) throw new DinewayValidationError("Publish and unpublish cannot be combined.");
1753
+ const validateData = async (data) => {
1754
+ const fields = await validateContentDataFields(db, collection, fieldData(data));
1755
+ if (fields && !fields.success) throw new DinewayValidationError(fields.error.message);
1756
+ const media = await validateMediaFields(db, collection, fieldData(data));
1757
+ if (!media.success) throw new DinewayValidationError(media.error.message);
1758
+ };
1759
+ if (input.data) await validateData(input.data);
1760
+ const intent = getContentStorage(db, collection) ? await beginContentWriteIntent(db, collection, input, JSON.parse(JSON.stringify(input))) : void 0;
1761
+ const revisionIdentity = intent ? {
1762
+ id: intent.revisionId,
1763
+ createdAt: intent.now
1764
+ } : void 0;
1765
+ const repo = new ContentRepository(db, { prepareIndexWrites: true });
1766
+ const checks = [...configuration.checks];
1767
+ const statements = [];
1768
+ const globalStatements = [];
1769
+ const storageRevisions = [];
1770
+ const translatedWrites = [];
1771
+ let termChanges = input.terms;
1772
+ if (!input.id && input.translationOf && getContentStorage(db, collection)) {
1773
+ const sourceTerms = await snapshotContentTermChanges(db, collection, input.translationOf);
1774
+ checks.push(...sourceTerms.checks);
1775
+ termChanges = {
1776
+ ...sourceTerms.changes,
1777
+ ...termChanges
1778
+ };
1287
1779
  }
1288
- async buildContentReviewPayload(input) {
1289
- const actionType = input.actionType ?? "content.publish";
1290
- const content = await this.loadContent(input.collection, input.id);
1291
- const compare = await this.loadCompare(input.collection, content.entryId);
1292
- const live = asRecord(compare.live);
1293
- const draft = asRecord(compare.draft) ?? content.data;
1294
- const displayTitle = stringOrNull(draft.title) ?? content.displayTitle;
1295
- const hasChanges = typeof compare.hasChanges === "boolean" ? compare.hasChanges : stableStringify(live) !== stableStringify(draft);
1296
- const actionHash = await buildStableActionHash({
1297
- actionType,
1298
- collection: input.collection,
1299
- entryId: content.entryId,
1300
- liveRevisionId: content.liveRevisionId,
1301
- draftRevisionId: content.draftRevisionId,
1302
- reviewedRev: content.reviewedRev,
1303
- live,
1304
- draft
1780
+ const appendGlobal = (...items) => {
1781
+ statements.push(...items);
1782
+ globalStatements.push(...items);
1783
+ };
1784
+ let item;
1785
+ let previousItem;
1786
+ let previousSlug = null;
1787
+ let wasPublished = false;
1788
+ let live = null;
1789
+ let draft = null;
1790
+ let now = intent?.now ?? (/* @__PURE__ */ new Date()).toISOString();
1791
+ if (input.id) {
1792
+ const snapshot = await repo.snapshot(collection, input.id);
1793
+ if (!snapshot) throw new DinewayValidationError("Content item not found.");
1794
+ previousItem = snapshot.item;
1795
+ if (input.expectedRev !== void 0 && encodeRev(snapshot.item) !== input.expectedRev) throw new AtomicWriteConflict();
1796
+ previousSlug = snapshot.item.slug;
1797
+ wasPublished = snapshot.item.status === "published";
1798
+ item = {
1799
+ ...snapshot.item,
1800
+ updatedAt: now,
1801
+ version: snapshot.item.version + 1,
1802
+ publishedAt: input.publishedAt === void 0 ? snapshot.item.publishedAt : input.publishedAt
1803
+ };
1804
+ checks.push(snapshot.check, ...contentWriteChecks(collection, item.id, "edit"));
1805
+ if (getContentStorage(db, collection)) checks.push(contentPartitionWritable(collection, item.id));
1806
+ for (const [kind, id] of [["live", item.liveRevisionId], ["draft", item.draftRevisionId]]) {
1807
+ if (!id) continue;
1808
+ const revision = await db.selectFrom("revisions").selectAll().where("id", "=", id).executeTakeFirst();
1809
+ if (!revision || revision.collection !== collection || revision.entry_id !== item.id) throw new DinewayValidationError("Content revision is missing or belongs to another entry.");
1810
+ checks.push(rowUnchanged("revisions", revision));
1811
+ if (kind === "live") live = await readRevisionData(db, revision);
1812
+ else draft = await readRevisionData(db, revision);
1813
+ }
1814
+ const stage = input.stageDraft !== false && usesRevisions;
1815
+ const changedDraft = stage && (Object.keys(input.data ?? {}).length > 0 || input.slug !== void 0);
1816
+ if (changedDraft) draft = {
1817
+ ...draft ?? item.data,
1818
+ ...input.data,
1819
+ ...input.slug === void 0 ? {} : { _slug: input.slug }
1820
+ };
1821
+ if (input.draftData) {
1822
+ const previous = draft ?? live ?? item.data;
1823
+ await validateData(Object.fromEntries(Object.entries(input.draftData).filter(([key, value]) => JSON.stringify(previous[key]) !== JSON.stringify(value))));
1824
+ draft = structuredClone(input.draftData);
1825
+ }
1826
+ if (!stage) {
1827
+ item.data = {
1828
+ ...item.data,
1829
+ ...await repo.normalizePreparedData(collection, fieldData(input.data ?? {}))
1830
+ };
1831
+ for (const [key, value] of Object.entries(item.data)) if (typeof value === "boolean") item.data[key] = Number(value);
1832
+ for (const [key, value] of Object.entries(item.data)) if (value === null || value === void 0) delete item.data[key];
1833
+ if (input.slug !== void 0) item.slug = input.slug;
1834
+ }
1835
+ if (!stage && input.slug && previousSlug && input.slug !== previousSlug) appendGlobal(...new RedirectRepository(db).prepareAutoRedirect(collection, previousSlug, input.slug, item.id, configuration.row?.url_pattern ?? null).statements);
1836
+ if (syncTranslations && !stage && isI18nEnabled() && input.data && item.translationGroup) {
1837
+ const sync = prepareNonTranslatableFields(db, collection, item.id, item.translationGroup, fieldData(input.data), configuration.fields.filter((field) => field.translatable === 0).map((field) => field.slug));
1838
+ if (sync) if (getContentStorage(db, collection)) {
1839
+ const sharedSlugs = new Set(configuration.fields.filter((field) => field.translatable === 0).map((field) => field.slug));
1840
+ const shared = Object.fromEntries(Object.entries(fieldData(input.data)).filter(([field]) => sharedSlugs.has(field)));
1841
+ const siblings = await sql`SELECT id FROM ${sql.table(`ec_${collection}`)} WHERE translation_group = ${item.translationGroup} AND id <> ${item.id} ORDER BY id`.execute(db);
1842
+ checks.push(sql`(SELECT COUNT(*) FROM ${sql.table(`ec_${collection}`)} WHERE translation_group = ${item.translationGroup} AND id <> ${item.id}) = ${siblings.rows.length}`);
1843
+ for (const sibling of siblings.rows) translatedWrites.push(await prepareContentWriteInternal(db, collection, {
1844
+ id: sibling.id,
1845
+ data: shared,
1846
+ stageDraft: false,
1847
+ operationId: intent ? `${intent.operationId}:${sibling.id}` : void 0
1848
+ }, false));
1849
+ } else appendGlobal(sync);
1850
+ }
1851
+ if (input.status !== void 0) item.status = input.status;
1852
+ if (input.authorId !== void 0) item.authorId = input.authorId;
1853
+ statements.push(repo.prepareUpdate(collection, item.id, {
1854
+ data: stage ? void 0 : input.data && fieldData(input.data),
1855
+ slug: stage ? void 0 : input.slug,
1856
+ status: input.status,
1857
+ authorId: input.authorId,
1858
+ publishedAt: input.publishedAt
1859
+ }, now));
1860
+ if (changedDraft || input.draftData || input.unpublish && !draft && live) {
1861
+ draft ??= live;
1862
+ if (draft) {
1863
+ const replace = !!input.reuseDraftRevision && !!item.draftRevisionId && item.draftRevisionId !== item.liveRevisionId;
1864
+ const revision = replace ? {
1865
+ id: item.draftRevisionId,
1866
+ statement: db.updateTable("revisions").set({ data: JSON.stringify(draft) }).where("id", "=", item.draftRevisionId).compile()
1867
+ } : new RevisionRepository(db, { prepareIndexWrites: true }).prepareCreateSnapshot({
1868
+ collection,
1869
+ entryId: item.id,
1870
+ data: sql`${JSON.stringify(draft)}`,
1871
+ authorId: input.authorId ?? void 0
1872
+ }, revisionIdentity);
1873
+ storageRevisions.push({
1874
+ id: revision.id,
1875
+ data: draft,
1876
+ authorId: input.authorId ?? void 0,
1877
+ replace
1878
+ });
1879
+ item.draftRevisionId = revision.id;
1880
+ statements.push(revision.statement, sql`UPDATE ${sql.table(`ec_${collection}`)} SET draft_revision_id=${revision.id} WHERE id=${item.id}`.compile(db));
1881
+ }
1882
+ }
1883
+ } else {
1884
+ if (input.expectedRev !== void 0 || input.unpublish) throw new DinewayValidationError("A new draft cannot reference an existing revision.");
1885
+ const data = fieldData(input.data ?? {});
1886
+ if (input.draftData) await validateData(input.draftData);
1887
+ const slugSource = [data.title, data.name].find((value) => typeof value === "string" && value.length > 0);
1888
+ const slug = input.slug ?? (slugSource ? await repo.generateUniqueSlug(collection, slugSource, input.locale) : void 0);
1889
+ if (slug) checks.push(sql`NOT EXISTS(SELECT 1 FROM ${sql.table(`ec_${collection}`)} WHERE slug=${slug} ${input.locale ? sql`AND locale=${input.locale}` : sql``})`);
1890
+ const created = await repo.prepareCreate({
1891
+ type: collection,
1892
+ data,
1893
+ slug,
1894
+ status: "draft",
1895
+ authorId: input.authorId ?? void 0,
1896
+ locale: input.locale,
1897
+ translationOf: input.translationOf,
1898
+ createdAt: input.createdAt,
1899
+ publishedAt: input.publishedAt
1900
+ }, {
1901
+ captureDefaults: true,
1902
+ id: intent?.entryId,
1903
+ now: intent?.now
1305
1904
  });
1306
- const scope = `content:${input.collection}:${content.entryId}`;
1307
- const summary = input.summary ?? `Review ${actionType} for ${input.collection}/${displayTitle ?? content.entryId}`;
1308
- return {
1309
- collection: input.collection,
1310
- entryId: content.entryId,
1311
- scope,
1312
- liveRevisionId: content.liveRevisionId,
1313
- draftRevisionId: content.draftRevisionId,
1314
- reviewedRev: content.reviewedRev,
1315
- actionType,
1316
- actionHash,
1317
- reviewPayload: {
1318
- kind: "content_review",
1319
- actionType,
1320
- summary,
1321
- target: {
1322
- collection: input.collection,
1323
- entryId: content.entryId,
1324
- scope,
1325
- liveRevisionId: content.liveRevisionId,
1326
- draftRevisionId: content.draftRevisionId,
1327
- reviewedRev: content.reviewedRev,
1328
- actionHash
1329
- },
1330
- content: {
1331
- id: content.entryId,
1332
- slug: content.slug,
1333
- status: content.status,
1334
- title: displayTitle,
1335
- updatedAt: content.updatedAt
1336
- },
1337
- diff: {
1338
- hasChanges,
1339
- live,
1340
- draft
1341
- }
1905
+ item = created.item;
1906
+ now = item.updatedAt;
1907
+ checks.push(...created.batch.checks ?? []);
1908
+ statements.push(...created.batch.statements);
1909
+ if (usesRevisions || input.draftData) {
1910
+ draft = structuredClone(input.draftData ?? {
1911
+ ...item.data,
1912
+ ...Object.fromEntries(Object.entries(input.data ?? {}).filter(([key]) => key.startsWith("_")))
1913
+ });
1914
+ const revision = new RevisionRepository(db, { prepareIndexWrites: true }).prepareCreateSnapshot({
1915
+ collection,
1916
+ entryId: item.id,
1917
+ data: sql`${JSON.stringify(draft)}`,
1918
+ authorId: input.authorId ?? void 0
1919
+ }, revisionIdentity);
1920
+ storageRevisions.push({
1921
+ id: revision.id,
1922
+ data: draft,
1923
+ authorId: input.authorId ?? void 0
1924
+ });
1925
+ item.draftRevisionId = revision.id;
1926
+ statements.push(revision.statement, sql`UPDATE ${sql.table(`ec_${collection}`)} SET draft_revision_id=${revision.id} WHERE id=${item.id}`.compile(db));
1927
+ }
1928
+ }
1929
+ if (input.publish) {
1930
+ const authority = contentWriteChecks(collection, item.id, "publish");
1931
+ if (input.id) checks.push(...authority);
1932
+ else appendGlobal(...prepareAtomicChecks(db, authority));
1933
+ const data = draft ?? live ?? item.data;
1934
+ let revisionId = item.draftRevisionId ?? item.liveRevisionId;
1935
+ if (!revisionId) {
1936
+ const revision = new RevisionRepository(db, { prepareIndexWrites: true }).prepareCreateSnapshot({
1937
+ collection,
1938
+ entryId: item.id,
1939
+ data: sql`${JSON.stringify(data)}`,
1940
+ authorId: input.authorId ?? void 0
1941
+ }, revisionIdentity);
1942
+ revisionId = revision.id;
1943
+ storageRevisions.push({
1944
+ id: revision.id,
1945
+ data,
1946
+ authorId: input.authorId ?? void 0
1947
+ });
1948
+ statements.push(revision.statement);
1949
+ }
1950
+ const sync = repo.prepareSyncDataColumns(collection, item.id, data);
1951
+ if (sync) statements.push(sync);
1952
+ const slug = typeof data._slug === "string" ? data._slug : item.slug;
1953
+ if (wasPublished && previousSlug && slug && previousSlug !== slug) appendGlobal(...new RedirectRepository(db).prepareAutoRedirect(collection, previousSlug, slug, item.id, configuration.row?.url_pattern ?? null).statements);
1954
+ item = {
1955
+ ...item,
1956
+ slug,
1957
+ status: "published",
1958
+ liveRevisionId: revisionId,
1959
+ draftRevisionId: null,
1960
+ scheduledAt: null,
1961
+ publishedAt: item.publishedAt ?? now,
1962
+ updatedAt: now,
1963
+ data: {
1964
+ ...item.data,
1965
+ ...await repo.normalizePreparedData(collection, fieldData(data))
1342
1966
  }
1343
1967
  };
1968
+ for (const [key, value] of Object.entries(item.data)) {
1969
+ if (typeof value === "boolean") item.data[key] = Number(value);
1970
+ if (value === null || value === void 0) delete item.data[key];
1971
+ }
1972
+ statements.push(sql`UPDATE ${sql.table(`ec_${collection}`)} SET slug=${slug},status='published',live_revision_id=${revisionId},draft_revision_id=NULL,scheduled_at=NULL,published_at=${item.publishedAt},updated_at=${now} WHERE id=${item.id}`.compile(db));
1973
+ live = data;
1974
+ draft = null;
1344
1975
  }
1345
- async loadContent(collection, id) {
1346
- const result = await this.handlers.handleContentGet(collection, id);
1347
- if (!result.success) throw new Error(result.error?.message ?? `Content item not found: ${collection}/${id}`);
1348
- const payload = asRecord(result.data);
1349
- const item = asRecord(payload?.item);
1350
- if (!payload || !item) throw new Error("Content get response did not include an item");
1351
- const entryId = stringOrNull(item.id);
1352
- const reviewedRev = stringOrNull(payload._rev);
1353
- if (!entryId) throw new Error("Content item is missing id");
1354
- if (!reviewedRev) throw new Error("Content item is missing _rev for review binding");
1355
- const data = asRecord(item.data) ?? {};
1356
- const title = stringOrNull(data.title) ?? stringOrNull(item.title) ?? stringOrNull(item.slug);
1357
- return {
1358
- entryId,
1359
- reviewedRev,
1360
- liveRevisionId: stringOrNull(item.liveRevisionId),
1361
- draftRevisionId: stringOrNull(item.draftRevisionId),
1362
- slug: stringOrNull(item.slug),
1363
- status: stringOrNull(item.status),
1364
- updatedAt: stringOrNull(item.updatedAt),
1365
- displayTitle: title,
1366
- data
1367
- };
1976
+ if (input.unpublish) {
1977
+ checks.push(...contentWriteChecks(collection, item.id, "publish"));
1978
+ item.liveRevisionId = null;
1979
+ item.status = "draft";
1980
+ live = null;
1981
+ statements.push(sql`UPDATE ${sql.table(`ec_${collection}`)} SET live_revision_id=NULL,status='draft' WHERE id=${item.id}`.compile(db));
1368
1982
  }
1369
- async loadCompare(collection, id) {
1370
- const result = await this.handlers.handleContentCompare(collection, id);
1371
- if (!result.success) throw new Error(result.error?.message ?? `Failed to compare content: ${collection}/${id}`);
1372
- return asRecord(result.data) ?? {};
1983
+ const metadata = getContentStorage(db, collection) ? await snapshotOwnedContentMetadata(db, collection, item.id) : void 0;
1984
+ if (metadata) checks.push(...metadata.checks);
1985
+ const previousBylines = metadata?.owned.bylines;
1986
+ const previousSeo = metadata && configuration.row?.has_seo === 1 ? storedContentSeo(metadata.owned.seo) : void 0;
1987
+ if (termChanges) {
1988
+ const terms = await prepareContentTerms(db, collection, item.id, termChanges, item.locale ?? "en");
1989
+ checks.push(...terms.checks ?? []);
1990
+ appendGlobal(...terms.statements);
1991
+ if (metadata) metadata.owned.terms = [...metadata.owned.terms.filter((row) => !terms.replaced.includes(row.taxonomy_id)), ...terms.assignments.map((taxonomy_id) => ({
1992
+ collection,
1993
+ entry_id: item.id,
1994
+ taxonomy_id
1995
+ }))].toSorted((a, b) => a.taxonomy_id.localeCompare(b.taxonomy_id));
1373
1996
  }
1374
- };
1375
- function asRecord(value) {
1376
- return isRecord(value) ? value : null;
1377
- }
1378
- function isRecord(value) {
1379
- return typeof value === "object" && value !== null && !Array.isArray(value);
1380
- }
1381
- function stringOrNull(value) {
1382
- return typeof value === "string" && value.length > 0 ? value : null;
1997
+ if (input.bylines !== void 0) {
1998
+ const bylines = await new BylineRepository(db).prepareContentBylines(collection, item.id, input.bylines, {
1999
+ prefix: intent?.rootVersion,
2000
+ now,
2001
+ primaryIndex: true
2002
+ });
2003
+ checks.push(...bylines.checks ?? []);
2004
+ appendGlobal(...bylines.statements);
2005
+ item.primaryBylineId = bylines.rows[0]?.byline_id ?? null;
2006
+ if (metadata) metadata.owned.bylines = bylines.rows;
2007
+ }
2008
+ if (input.seo) {
2009
+ const seo = new SeoRepository(db, { prepareIndexWrites: true }).prepareUpsert(collection, item.id, input.seo, now);
2010
+ if (seo) {
2011
+ appendGlobal(seo);
2012
+ if (metadata) {
2013
+ const previous = metadata.owned.seo[0];
2014
+ metadata.owned.seo = [{
2015
+ collection,
2016
+ content_id: item.id,
2017
+ seo_title: input.seo.title === void 0 ? previous?.seo_title ?? null : input.seo.title,
2018
+ seo_description: input.seo.description === void 0 ? previous?.seo_description ?? null : input.seo.description,
2019
+ seo_image: input.seo.image === void 0 ? previous?.seo_image ?? null : input.seo.image,
2020
+ seo_canonical: input.seo.canonical === void 0 ? previous?.seo_canonical ?? null : input.seo.canonical,
2021
+ seo_no_index: input.seo.noIndex === void 0 ? previous?.seo_no_index ?? 0 : Number(input.seo.noIndex),
2022
+ created_at: previous?.created_at ?? now,
2023
+ updated_at: now
2024
+ }];
2025
+ }
2026
+ }
2027
+ }
2028
+ const effectContext = syncTranslations ? getRequestContext()?.contentWriteEffects : void 0;
2029
+ const effectTargets = syncTranslations ? effectContext?.targets ?? getContentStorage(db, collection)?.runtime.hookTargets?.([input.publish ? "content:afterPublish" : input.unpublish ? "content:afterUnpublish" : "content:afterSave"]) : void 0;
2030
+ const eventContent = {
2031
+ ...item,
2032
+ ...effectTargets?.length && metadata ? await contentEventBylines(db, item, metadata.owned.bylines) : {},
2033
+ ...metadata && configuration.row?.has_seo === 1 ? { seo: storedContentSeo(metadata.owned.seo) } : {}
2034
+ };
2035
+ const priorEventContent = effectContext?.previousContent ?? (previousItem ? {
2036
+ ...previousItem,
2037
+ ...effectTargets?.length && previousBylines ? await contentEventBylines(db, previousItem, previousBylines) : {},
2038
+ ...previousSeo ? { seo: previousSeo } : {}
2039
+ } : void 0);
2040
+ const ownBatch = await prepareRoutedContentWrite({
2041
+ db,
2042
+ collection,
2043
+ item,
2044
+ create: !input.id,
2045
+ operationId: intent?.operationId,
2046
+ rootVersion: intent?.rootVersion,
2047
+ owned: metadata?.owned,
2048
+ effects: effectTargets?.length ? {
2049
+ targets: effectTargets,
2050
+ snapshot: contentStorageHookSnapshotSchema.parse(JSON.parse(JSON.stringify({
2051
+ collection,
2052
+ id: item.id,
2053
+ isNew: !input.id,
2054
+ permanent: false,
2055
+ content: eventContent,
2056
+ previousContent: priorEventContent
2057
+ })))
2058
+ } : void 0,
2059
+ terms: termChanges,
2060
+ checks,
2061
+ globalStatements,
2062
+ primaryStatements: statements,
2063
+ revisions: storageRevisions,
2064
+ fields: configuration.fields
2065
+ }) ?? {
2066
+ checks,
2067
+ statements
2068
+ };
2069
+ const prepared = {
2070
+ id: item.id,
2071
+ item,
2072
+ rev: encodeRev(item),
2073
+ draftData: draft,
2074
+ batch: {
2075
+ checks: [...ownBatch.checks ?? [], ...translatedWrites.flatMap((write) => write.batch.checks ?? [])],
2076
+ statements: [...ownBatch.statements, ...translatedWrites.flatMap((write) => write.batch.statements)]
2077
+ },
2078
+ afterCommit: () => {
2079
+ invalidateCollectionCache(collection);
2080
+ if (previousSlug !== item.slug) invalidateRedirectCache();
2081
+ for (const write of translatedWrites) write.afterCommit();
2082
+ }
2083
+ };
2084
+ reviews.set(prepared, structuredClone({
2085
+ item,
2086
+ live,
2087
+ draft
2088
+ }));
2089
+ return prepared;
1383
2090
  }
1384
2091
 
1385
2092
  //#endregion
1386
- export { validateRev as A, handleContentUpdate as C, validateMediaFields as D, validateContentDataFields as E, decodeRev as O, handleContentUnschedule as S, prepareNonTranslatableFields as T, handleContentPublish as _, handleContentCompare as a, handleContentTranslations as b, handleContentCreate as c, handleContentDuplicate as d, handleContentGet as f, handleContentPermanentDelete as g, handleContentListTrashed as h, handleContentAuthors as i, encodeRev as k, handleContentDelete as l, handleContentList as m, buildStableActionHash as n, handleContentCountScheduled as o, handleContentGetIncludingTrashed as p, contentWriteConfiguration as r, handleContentCountTrashed as s, ReviewPayloadBuilder as t, handleContentDiscardDraft as u, handleContentRestore as v, prepareContentPublication as w, handleContentUnpublish as x, handleContentSchedule as y };
2093
+ export { prepareContentProjection as A, handleContentUnschedule as C, encodeRev as D, decodeRev as E, validateRev as O, handleContentUnpublish as S, prepareContentPublication as T, handleContentPermanentDelete as _, handleContentAuthors as a, handleContentSchedule as b, handleContentCountTrashed as c, handleContentDiscardDraft as d, handleContentDuplicate as f, handleContentListTrashed as g, handleContentList as h, contentWriteConfiguration as i, snapshotPartitionDependencies as j, contentProjectionValues as k, handleContentCreate as l, handleContentGetIncludingTrashed as m, prepareContentWrite as n, handleContentCompare as o, handleContentGet as p, preparedContentReview as r, handleContentCountScheduled as s, content_write_exports as t, handleContentDelete as u, handleContentPublish as v, handleContentUpdate as w, handleContentTranslations as x, handleContentRestore as y };