dineway 0.2.33 → 0.2.35

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 (458) hide show
  1. package/dist/{activity-CfryM8jO.mjs → activity-BbtYp_4V.mjs} +2 -2
  2. package/dist/{activity-events-BVo9rMUz.mjs → activity-events-CiFN61xq.mjs} +1 -1
  3. package/dist/{actor-DrJJsvy6.mjs → actor-DxUAJgQX.mjs} +20 -6
  4. package/dist/{adapters-DHt3f2lu.d.mts → adapters-Rol-inz6.d.mts} +5 -7
  5. package/dist/after-BVaUn7bK.mjs +24 -0
  6. package/dist/{allowed-origins-DGSyhRCz.mjs → allowed-origins-Cp7BI3L9.mjs} +1 -1
  7. package/dist/api/route-utils.d.mts +10 -10
  8. package/dist/api/route-utils.mjs +23 -19
  9. package/dist/api/schemas/index.d.mts +1 -1
  10. package/dist/api/schemas/index.mjs +5 -5
  11. package/dist/{api-CTf1SLmg.mjs → api-CwhrR7H5.mjs} +55 -1215
  12. package/dist/api-tokens-DA18zxza.mjs +3 -0
  13. package/dist/{api-tokens-CSomx-l3.mjs → api-tokens-OAgvq4xg.mjs} +1 -1
  14. package/dist/{apply-Bs2jXsms.mjs → apply-BTfAReIv.mjs} +109 -93
  15. package/dist/astro/index.d.mts +16 -12
  16. package/dist/astro/index.mjs +50 -9
  17. package/dist/astro/middleware/auth.d.mts +9 -9
  18. package/dist/astro/middleware/auth.mjs +29 -8
  19. package/dist/astro/middleware/redirect.mjs +8 -7
  20. package/dist/astro/middleware/request-context.mjs +17 -10
  21. package/dist/astro/middleware/seed.d.mts +1 -1
  22. package/dist/astro/middleware/seed.mjs +93 -71
  23. package/dist/astro/middleware/setup.mjs +1 -1
  24. package/dist/astro/middleware/workers.d.mts +6 -0
  25. package/dist/astro/middleware/workers.mjs +8 -0
  26. package/dist/astro/middleware.mjs +287 -159
  27. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -7
  28. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -7
  29. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  30. package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
  31. package/dist/astro/routes/api/admin/briefing.mjs +25 -23
  32. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +5 -4
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +11 -10
  34. package/dist/astro/routes/api/admin/byline-fields/index.mjs +11 -10
  35. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +11 -10
  36. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +22 -20
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +22 -20
  38. package/dist/astro/routes/api/admin/bylines/index.mjs +22 -20
  39. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +18 -16
  40. package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -7
  41. package/dist/astro/routes/api/admin/comments/bulk.mjs +14 -13
  42. package/dist/astro/routes/api/admin/comments/counts.mjs +8 -7
  43. package/dist/astro/routes/api/admin/comments/index.mjs +14 -13
  44. package/dist/astro/routes/api/admin/context/_id_/history.mjs +42 -31
  45. package/dist/astro/routes/api/admin/context/_id_/index.mjs +42 -31
  46. package/dist/astro/routes/api/admin/context/_id_/review.mjs +47 -36
  47. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +47 -36
  48. package/dist/astro/routes/api/admin/context/diff.mjs +46 -35
  49. package/dist/astro/routes/api/admin/context/index.mjs +47 -36
  50. package/dist/astro/routes/api/admin/context/stale.mjs +46 -35
  51. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +42 -31
  52. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +46 -35
  53. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +46 -35
  54. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +43 -32
  55. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  56. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +7 -7
  57. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +7 -7
  58. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +71 -66
  59. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +71 -66
  60. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +63 -58
  61. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +70 -65
  62. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +70 -65
  63. package/dist/astro/routes/api/admin/plugins/index.mjs +63 -58
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +63 -58
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +70 -65
  67. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +63 -58
  68. package/dist/astro/routes/api/admin/plugins/updates.mjs +63 -58
  69. package/dist/astro/routes/api/admin/review-requests/_id_/image.mjs +26 -23
  70. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +39 -25
  71. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +55 -43
  72. package/dist/astro/routes/api/admin/review-requests/_id_/revoke.mjs +10 -9
  73. package/dist/astro/routes/api/admin/review-requests/index.mjs +53 -41
  74. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +63 -58
  75. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  76. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +63 -58
  77. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +20 -12
  78. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  79. package/dist/astro/routes/api/admin/users/_id_/index.mjs +40 -32
  80. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  81. package/dist/astro/routes/api/admin/users/index.mjs +7 -7
  82. package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -5
  83. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  84. package/dist/astro/routes/api/auth/invite/complete.mjs +12 -12
  85. package/dist/astro/routes/api/auth/invite/index.mjs +9 -9
  86. package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -11
  87. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  88. package/dist/astro/routes/api/auth/magic-link/send.mjs +12 -11
  89. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  90. package/dist/astro/routes/api/auth/me.mjs +11 -11
  91. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  92. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +5 -4
  93. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +5 -4
  94. package/dist/astro/routes/api/auth/passkey/_id_.mjs +7 -7
  95. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  96. package/dist/astro/routes/api/auth/passkey/options.mjs +14 -13
  97. package/dist/astro/routes/api/auth/passkey/register/options.mjs +11 -11
  98. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +12 -12
  99. package/dist/astro/routes/api/auth/passkey/verify.mjs +12 -12
  100. package/dist/astro/routes/api/auth/setup-token/index.mjs +32 -23
  101. package/dist/astro/routes/api/auth/setup-token/verify.mjs +32 -26
  102. package/dist/astro/routes/api/auth/signup/complete.mjs +12 -12
  103. package/dist/astro/routes/api/auth/signup/request.mjs +12 -11
  104. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  105. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts +73 -2
  106. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +91 -49
  107. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +19 -16
  108. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  109. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +8 -7
  110. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +8 -7
  111. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +8 -7
  112. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +24 -21
  113. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +34 -22
  114. package/dist/astro/routes/api/content/_collection_/_id_/release-readiness.mjs +9 -9
  115. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +8 -7
  116. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  117. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +34 -22
  118. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +23 -19
  119. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  120. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +8 -7
  121. package/dist/astro/routes/api/content/_collection_/_id_.mjs +14 -13
  122. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  123. package/dist/astro/routes/api/content/_collection_/index.mjs +14 -13
  124. package/dist/astro/routes/api/content/_collection_/trash.mjs +8 -8
  125. package/dist/astro/routes/api/dashboard.mjs +16 -11
  126. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  127. package/dist/astro/routes/api/health.mjs +1 -1
  128. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  129. package/dist/astro/routes/api/import/probe.mjs +25 -24
  130. package/dist/astro/routes/api/import/wordpress/analyze.mjs +12 -11
  131. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  132. package/dist/astro/routes/api/import/wordpress/execute.mjs +50 -42
  133. package/dist/astro/routes/api/import/wordpress/media.d.mts +9 -9
  134. package/dist/astro/routes/api/import/wordpress/media.mjs +14 -14
  135. package/dist/astro/routes/api/import/wordpress/prepare.mjs +51 -40
  136. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +10 -10
  137. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +49 -38
  138. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  139. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +29 -27
  140. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  141. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +9 -9
  142. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +55 -47
  143. package/dist/astro/routes/api/integration/artifact.mjs +11 -8
  144. package/dist/astro/routes/api/integration/dispatch.mjs +17 -14
  145. package/dist/astro/routes/api/integrations/_provider_.mjs +11 -8
  146. package/dist/astro/routes/api/integrations/index.mjs +10 -7
  147. package/dist/astro/routes/api/manifest.mjs +5 -5
  148. package/dist/astro/routes/api/mcp.mjs +97 -88
  149. package/dist/astro/routes/api/media/_id_/confirm.mjs +12 -12
  150. package/dist/astro/routes/api/media/_id_.mjs +9 -9
  151. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  152. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  153. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  154. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  155. package/dist/astro/routes/api/media/upload-url.mjs +13 -13
  156. package/dist/astro/routes/api/media.mjs +16 -16
  157. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +47 -36
  158. package/dist/astro/routes/api/menus/_name_/items.mjs +47 -36
  159. package/dist/astro/routes/api/menus/_name_/reorder.mjs +47 -36
  160. package/dist/astro/routes/api/menus/_name_/translations.mjs +47 -36
  161. package/dist/astro/routes/api/menus/_name_.mjs +47 -36
  162. package/dist/astro/routes/api/menus/index.mjs +47 -36
  163. package/dist/astro/routes/api/oauth/authorize.mjs +9 -7
  164. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -6
  165. package/dist/astro/routes/api/oauth/device/code.mjs +11 -9
  166. package/dist/astro/routes/api/oauth/device/token.mjs +10 -8
  167. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  168. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -6
  169. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -6
  170. package/dist/astro/routes/api/oauth/token.mjs +8 -6
  171. package/dist/astro/routes/api/openapi.json.mjs +5 -5
  172. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  173. package/dist/astro/routes/api/redirects/404s/index.mjs +15 -14
  174. package/dist/astro/routes/api/redirects/404s/summary.mjs +15 -14
  175. package/dist/astro/routes/api/redirects/_id_.mjs +47 -37
  176. package/dist/astro/routes/api/redirects/index.mjs +47 -37
  177. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  178. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  179. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +65 -60
  180. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +65 -60
  181. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +65 -60
  182. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +65 -60
  183. package/dist/astro/routes/api/schema/collections/index.mjs +65 -60
  184. package/dist/astro/routes/api/schema/index.mjs +12 -11
  185. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +63 -58
  186. package/dist/astro/routes/api/schema/orphans/index.mjs +63 -58
  187. package/dist/astro/routes/api/search/enable.mjs +15 -14
  188. package/dist/astro/routes/api/search/index.mjs +14 -13
  189. package/dist/astro/routes/api/search/rebuild.mjs +15 -14
  190. package/dist/astro/routes/api/search/stats.mjs +9 -8
  191. package/dist/astro/routes/api/search/suggest.mjs +14 -13
  192. package/dist/astro/routes/api/sections/_slug_.mjs +47 -36
  193. package/dist/astro/routes/api/sections/index.mjs +47 -36
  194. package/dist/astro/routes/api/settings/email.mjs +5 -5
  195. package/dist/astro/routes/api/settings/reviews.mjs +11 -10
  196. package/dist/astro/routes/api/settings.mjs +47 -36
  197. package/dist/astro/routes/api/setup/admin-verify.mjs +14 -14
  198. package/dist/astro/routes/api/setup/admin.mjs +12 -12
  199. package/dist/astro/routes/api/setup/dev-bypass.mjs +35 -31
  200. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  201. package/dist/astro/routes/api/setup/index.mjs +37 -33
  202. package/dist/astro/routes/api/setup/status.mjs +3 -3
  203. package/dist/astro/routes/api/snapshot.mjs +11 -9
  204. package/dist/astro/routes/api/system/heartbeat.mjs +2 -2
  205. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +50 -39
  206. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +50 -39
  207. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +50 -39
  208. package/dist/astro/routes/api/taxonomies/index.mjs +50 -39
  209. package/dist/astro/routes/api/themes/preview.mjs +8 -6
  210. package/dist/astro/routes/api/typegen.mjs +4 -4
  211. package/dist/astro/routes/api/well-known/auth.mjs +3 -3
  212. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  213. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  214. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +46 -35
  215. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +47 -36
  216. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +47 -36
  217. package/dist/astro/routes/api/widget-areas/_name_.mjs +44 -33
  218. package/dist/astro/routes/api/widget-areas/index.mjs +47 -36
  219. package/dist/astro/routes/api/widget-components.mjs +2 -2
  220. package/dist/astro/routes/robots.txt.mjs +11 -10
  221. package/dist/astro/routes/sitemap-_collection_.xml.mjs +20 -18
  222. package/dist/astro/routes/sitemap.xml.mjs +19 -17
  223. package/dist/astro/session-driver.d.mts +1 -1
  224. package/dist/astro/session-driver.mjs +4 -4
  225. package/dist/astro/types.d.mts +13 -13
  226. package/dist/atomic-authority-CnBQJ14T.mjs +33 -0
  227. package/dist/{audit-CYjfxG9i.mjs → audit-F5iWkbcJ.mjs} +11 -4
  228. package/dist/auth/providers/github.d.mts +1 -1
  229. package/dist/auth/providers/google.d.mts +1 -1
  230. package/dist/{auth-control-guard-CITT8ZA_.mjs → auth-control-guard-DPOSBNFI.mjs} +1 -1
  231. package/dist/{authorize-KcI0pAfN.mjs → authorize-CXIjxIfC.mjs} +1 -1
  232. package/dist/{briefing-BgQTljQt.mjs → briefing-5zf0YZbR.mjs} +445 -447
  233. package/dist/{briefing-r3hXCDQC.mjs → briefing-DiupPvyN.mjs} +1 -1
  234. package/dist/{bundle-S6zx-V4D.mjs → bundle-DImnxo71.mjs} +3 -3
  235. package/dist/{byline-Ctil4rij.mjs → byline-DEZKlzD9.mjs} +107 -113
  236. package/dist/{byline-fields-51ja6JDa.d.mts → byline-fields-BO96fXLv.d.mts} +8 -8
  237. package/dist/{byline-fields-DiCyW6eQ.mjs → byline-fields-CY6V0ew1.mjs} +1 -1
  238. package/dist/{byline-fields-QpmruT5r.mjs → byline-fields-DGNKitg3.mjs} +3 -3
  239. package/dist/{byline-registry-rkr73qSE.mjs → byline-registry-CkuVVeJJ.mjs} +46 -76
  240. package/dist/{bylines-v_ZUQnR-.mjs → bylines-CXyKpVLQ.mjs} +6 -6
  241. package/dist/{bylines-BcuBpzVi.mjs → bylines-gSAfpHl4.mjs} +4 -4
  242. package/dist/{cache-V2BCplaY.mjs → cache-DZDOBJv3.mjs} +2 -2
  243. package/dist/{chunks-CnuL55JE.mjs → chunks-BnG3LPMN.mjs} +1 -1
  244. package/dist/cli/index.mjs +452 -263
  245. package/dist/cli/plugin-kit.d.mts +9 -9
  246. package/dist/cli/plugin-kit.mjs +2 -2
  247. package/dist/client/external-auth-headers.d.mts +1 -1
  248. package/dist/client/index.d.mts +11 -11
  249. package/dist/client/index.mjs +2 -2
  250. package/dist/{client-factory-C-y9VZDX.mjs → client-factory-6vLLT06O.mjs} +1 -1
  251. package/dist/{comment-_nvJSS-A.mjs → comment-kgLTdtQD.mjs} +15 -8
  252. package/dist/{comment-reaction-DhVgJ17S.mjs → comment-reaction-Cun5eIXL.mjs} +1 -1
  253. package/dist/{comments-D4mIDjvA.mjs → comments-ZYK_cZvx.mjs} +1 -1
  254. package/dist/{content-CVCrcuvD.mjs → content-D9xKUSno.mjs} +287 -165
  255. package/dist/{content-refresh-QvBIyb_g.mjs → content-refresh-9M9cc55-.mjs} +170 -193
  256. package/dist/{context-JjKucxBm.mjs → context-BU8AbLmY.mjs} +2 -2
  257. package/dist/{context-MftkHbWx.mjs → context-C5lPtfeh.mjs} +95 -77
  258. package/dist/{context-route-helpers-e1APrqSm.mjs → context-route-helpers-CWAHJFl3.mjs} +2 -2
  259. package/dist/{cron-mGVPQ5e6.mjs → cron-BVYo08mi.mjs} +36 -32
  260. package/dist/d1-binding-D6HZa3ks.mjs +8 -0
  261. package/dist/d1-dialect-BBxPg6Om.mjs +48 -0
  262. package/dist/{dashboard-ZJ7sMcBI.mjs → dashboard-BnD5krLg.mjs} +5 -5
  263. package/dist/database/batch.d.mts +22 -0
  264. package/dist/database/batch.mjs +92 -0
  265. package/dist/database/d1/index.d.mts +18 -0
  266. package/dist/database/d1/index.mjs +8 -0
  267. package/dist/db/d1.d.mts +7 -0
  268. package/dist/db/d1.mjs +13 -0
  269. package/dist/db/index.d.mts +4 -4
  270. package/dist/db/index.mjs +10 -7
  271. package/dist/db/libsql.d.mts +1 -1
  272. package/dist/db/libsql.mjs +46 -3
  273. package/dist/db/postgres.d.mts +1 -1
  274. package/dist/db/sqlite.d.mts +1 -1
  275. package/dist/{device-flow-eOcL5m0Q.mjs → device-flow-Prqg6ycD.mjs} +130 -94
  276. package/dist/{dialect-helpers-fk43GbDb.mjs → dialect-helpers-C6xtO-Ui.mjs} +1 -1
  277. package/dist/{discovery-CJkuHGhZ.mjs → discovery-CYcZJ1o3.mjs} +5 -5
  278. package/dist/{enrich-KErvJOuI.mjs → enrich-BjF-J4sF.mjs} +1 -1
  279. package/dist/{evidence-6IUv9ML3.mjs → evidence-krrA3uiG.mjs} +7 -7
  280. package/dist/{field-defs-cache-CwrIyZFT.mjs → field-defs-cache-BKKFFf_V.mjs} +5 -5
  281. package/dist/{forgeway-account-lYJ8iX3G.mjs → forgeway-account-CnWOIusE.mjs} +1 -1
  282. package/dist/{fts-manager-DX7ZkrCa.mjs → fts-manager-DA74x_uP.mjs} +72 -57
  283. package/dist/{hitl-requests-CmYVunm-.mjs → hitl-requests-CGjA1jND.mjs} +2 -2
  284. package/dist/{hitl-route-helpers-CRm537zS.mjs → hitl-route-helpers-BxSL0iZB.mjs} +5 -5
  285. package/dist/{import-DqRAgsKr.mjs → import-CayDCPaH.mjs} +9 -9
  286. package/dist/{index-Co7xtjkd.d.mts → index-mlJSqFkG.d.mts} +7 -4
  287. package/dist/index.d.mts +16 -16
  288. package/dist/index.mjs +103 -96
  289. package/dist/{integration-credentials-qudN6yRr.mjs → integration-credentials-Br16M1VE.mjs} +2 -2
  290. package/dist/{jsonld-BpvnSp2m.d.mts → jsonld-BUiFEiCZ.d.mts} +2 -2
  291. package/dist/{load-fCOciq0Q.mjs → load-B2oitobd.mjs} +1 -1
  292. package/dist/{loader-BDje8ME2.mjs → loader-Cgsx23wU.mjs} +4 -4
  293. package/dist/{manifest-schema-CfKD0thC.mjs → manifest-schema-DBXM_g8l.mjs} +1 -1
  294. package/dist/{mcp-reviewed-executor-DmhM3Cy6.mjs → mcp-reviewed-executor-RJ71uyQb.mjs} +7 -7
  295. package/dist/media/image-endpoint.mjs +1 -1
  296. package/dist/media/index.d.mts +1 -1
  297. package/dist/media/index.mjs +2 -2
  298. package/dist/media/local-runtime.d.mts +11 -11
  299. package/dist/media/local-runtime.mjs +3 -3
  300. package/dist/{media-dvRjj4po.mjs → media-BZqwtRTZ.mjs} +12 -4
  301. package/dist/{media-allowlist-DaG6lNoy.mjs → media-allowlist-CyByjUXh.mjs} +1 -1
  302. package/dist/{menus-CZbz5L_V.mjs → menus-2o-DVcwA.mjs} +8 -8
  303. package/dist/{menus-CpuR4Qkm.mjs → menus-5liJusbp.mjs} +138 -90
  304. package/dist/migrations-C7YXse7V.mjs +76 -0
  305. package/dist/oauth-authority-DOjME4Hh.mjs +43 -0
  306. package/dist/{oauth-authorization-Jf5e3azH.mjs → oauth-authorization-B_mmz7O2.mjs} +89 -98
  307. package/dist/{oauth-clients-tovQ4D4h.mjs → oauth-clients-Cr4pdIAE.mjs} +2 -2
  308. package/dist/object-cache/memory.d.mts +1 -1
  309. package/dist/{object-cache-D51qOseS.mjs → object-cache-BGjIlY9s.mjs} +1 -1
  310. package/dist/page/index.d.mts +10 -10
  311. package/dist/page/index.mjs +1 -1
  312. package/dist/{parse-IsGn-5lt.mjs → parse-BscLr3p2.mjs} +1 -1
  313. package/dist/plugin-utils.d.mts +9 -9
  314. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  315. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  316. package/dist/{plugins-DXyLI3Hb.mjs → plugins-f48yrwfI.mjs} +35 -84
  317. package/dist/{policy-DKdNMv8y.mjs → policy-CrK1vl8l.mjs} +2 -2
  318. package/dist/{preview-BXmS1SXL.mjs → preview-E1xKZGsX.mjs} +2 -2
  319. package/dist/{provider-loader-DDq7R_RN.d.mts → provider-loader-H2wdGD0o.d.mts} +1 -1
  320. package/dist/{public-url-Ci7UbC0W.d.mts → public-url-CI700CW4.d.mts} +1 -1
  321. package/dist/{public-url-BQ9vf0AS.d.mts → public-url-zoO-QbN6.d.mts} +2 -2
  322. package/dist/{publication-authorization-C-vYPGD8.mjs → publication-authorization-Dq_20SZR.mjs} +458 -33
  323. package/dist/{query-DcB9uGTW.mjs → query-BkWWdxyb.mjs} +4 -4
  324. package/dist/{query-CrW2yI6G.mjs → query-D6oNo9iz.mjs} +15 -15
  325. package/dist/{rate-limit-DEkoxTsP.mjs → rate-limit-RaBJEgyt.mjs} +2 -2
  326. package/dist/{redirect-DG-o0CKV.mjs → redirect-HLI3wT5Y.mjs} +26 -14
  327. package/dist/{redirects-Bjp4iKJU.mjs → redirects-D16GFaOa.mjs} +5 -5
  328. package/dist/{redirects-N8gmWhVM.mjs → redirects-DpRiuRWn.mjs} +3 -3
  329. package/dist/{registry-D-IV_h50.mjs → registry-DcV93OL_.mjs} +183 -186
  330. package/dist/release-CZfAeyXm.mjs +5148 -0
  331. package/dist/request-context.d.mts +8 -0
  332. package/dist/{request-meta-BW0the1R.mjs → request-meta-C6yGqnGD.mjs} +1 -1
  333. package/dist/{resolve-pZ4NQM-X.mjs → resolve-CpOV2jt_.mjs} +1 -1
  334. package/dist/review-payload-LLIi1sxO.mjs +1386 -0
  335. package/dist/{review-requests-DICrYH2-.mjs → review-requests-BF2eEKr8.mjs} +93 -37
  336. package/dist/{review-requests-BTKfeWlS.mjs → review-requests-C7prIbCo.mjs} +2 -2
  337. package/dist/{review-route-helpers-DaZBBps8.mjs → review-route-helpers-BYx3Px90.mjs} +2 -2
  338. package/dist/{revision-De7OmYVD.mjs → revision-090sZyGc.mjs} +28 -22
  339. package/dist/revocation-DZ8e4JCS.mjs +53 -0
  340. package/dist/{runner-DJiRFyLI.mjs → runner-CVeq0266.mjs} +594 -491
  341. package/dist/{runner-Dye73myO.d.mts → runner-Cxl-vyk2.d.mts} +1 -1
  342. package/dist/{runs-DEujUDOj.mjs → runs-B8kCirJ6.mjs} +5 -5
  343. package/dist/runtime-env-v-1UXPAH.mjs +19 -0
  344. package/dist/runtime.d.mts +10 -10
  345. package/dist/runtime.mjs +5 -5
  346. package/dist/schema-DFeC5axi.mjs +8 -0
  347. package/dist/{search-DxUKN9Zz.mjs → search-C9qOBgvo.mjs} +4 -4
  348. package/dist/{secrets-AdCrGg1c.mjs → secrets-BP2YTPWn.mjs} +10 -11
  349. package/dist/{sections-BPFOEMK6.mjs → sections-CkoQY7Z9.mjs} +2 -2
  350. package/dist/seed/index.d.mts +2 -2
  351. package/dist/seed/index.mjs +29 -25
  352. package/dist/seo/index.d.mts +3 -3
  353. package/dist/seo/index.mjs +11 -10
  354. package/dist/{seo-GfovzqpU.mjs → seo-Bypxm1iD.mjs} +1 -1
  355. package/dist/{seo-DWHdo5aW.mjs → seo-DYpc_rQ1.mjs} +25 -15
  356. package/dist/{service-BrNKVCjC.mjs → service-DOFqfUVv.mjs} +46 -21
  357. package/dist/{service-DbgjHWyW.mjs → service-mJBl4ZP4.mjs} +2 -2
  358. package/dist/{session-user-D8WwGEPH.mjs → session-user-DacoiKrJ.mjs} +1 -1
  359. package/dist/{settings-BKEHw6Bu.mjs → settings-2p7TuNWG.mjs} +2 -2
  360. package/dist/{settings-CAsQLi0N.mjs → settings-DRFy8JQx.mjs} +8 -8
  361. package/dist/{setup-complete-CHCYS5KV.mjs → setup-complete-CWMnrNFN.mjs} +1 -1
  362. package/dist/{site-activity-7oezuHXK.mjs → site-activity-BrN2NviL.mjs} +11 -4
  363. package/dist/{site-context-CA7rbxux.mjs → site-context-D9oETfxF.mjs} +50 -37
  364. package/dist/{site-url-DoZf_jVj.mjs → site-url-DoTPKRND.mjs} +1 -1
  365. package/dist/state-D8AogXCV.mjs +30 -0
  366. package/dist/storage/local.d.mts +1 -1
  367. package/dist/storage/local.mjs +1 -1
  368. package/dist/storage/s3.d.mts +1 -1
  369. package/dist/storage/s3.mjs +3 -3
  370. package/dist/{store-c4qx3gVh.mjs → store-CjmmGlVw.mjs} +37 -12
  371. package/dist/submission-BLvkvewK.mjs +411 -0
  372. package/dist/{taxonomies-ALDiRQ84.mjs → taxonomies-C5ayPp3T.mjs} +3 -3
  373. package/dist/{taxonomies-93DV-1QT.mjs → taxonomies-DW6Fps-w.mjs} +7 -7
  374. package/dist/{taxonomy-BOBTJ_aE.mjs → taxonomy-DWxxLpp5.mjs} +3 -3
  375. package/dist/{tokens-c-qxNqzC.mjs → tokens-I3tSjoFI.mjs} +1 -1
  376. package/dist/{trusted-proxy-CdEl6g6B.mjs → trusted-proxy-CvDP0g0F.mjs} +4 -12
  377. package/dist/{types-6KmeXInJ.d.mts → types-BFoQ5a1v.d.mts} +1 -1
  378. package/dist/{types-BpSTdH1H.mjs → types-BqxIv8Il.mjs} +2 -2
  379. package/dist/{types-BRCUO8NR.d.mts → types-CVRNRAA5.d.mts} +1 -0
  380. package/dist/{types-CfpX1og5.d.mts → types-Tt_IGMno.d.mts} +360 -172
  381. package/dist/ui/server-runtime.d.mts +13 -13
  382. package/dist/ui/server-runtime.mjs +28 -26
  383. package/dist/{user-D0NJ7gYf.mjs → user-1-YV30lf.mjs} +2 -2
  384. package/dist/{utils-BK2efsHv.mjs → utils-BoWkoty8.mjs} +2 -2
  385. package/dist/{validate-CDWVODvc.d.mts → validate-CCOsvPg2.d.mts} +3 -3
  386. package/dist/{validate-C9g9iX3q.mjs → validate-CupwWNWL.mjs} +3 -3
  387. package/dist/version-DpT-k_Ny.mjs +6 -0
  388. package/dist/{widgets-Cm5Qx2Np.mjs → widgets-DbOctkXv.mjs} +3 -3
  389. package/dist/{wordpress-slugs-WdPZaVXf.mjs → wordpress-slugs-pQlLXbKn.mjs} +1 -1
  390. package/dist/{worker-Bhuu7eqS.mjs → worker-wjRq4FI9.mjs} +76 -47
  391. package/dist/workers-build-QVrquLLe.mjs +36 -0
  392. package/dist/{zod-generator-DS5oZNaL.mjs → zod-generator-BzACAoR5.mjs} +2 -2
  393. package/package.json +34 -8
  394. package/dist/after-BfniwgIf.mjs +0 -9
  395. package/dist/api-tokens-CmT83Bgj.mjs +0 -3
  396. package/dist/db/libsql-http.d.mts +0 -27
  397. package/dist/db/libsql-http.mjs +0 -29
  398. package/dist/libsql-dialect-CANq6UNI.mjs +0 -47
  399. package/dist/oauth-user-lookup-B451pZmd.mjs +0 -25
  400. package/dist/review-payload-f1L4lzQg.mjs +0 -111
  401. package/dist/revocation-CkTOhdlw.mjs +0 -42
  402. package/dist/schema-IjuRxkqq.mjs +0 -8
  403. package/dist/submission-C47cHBIg.mjs +0 -67
  404. package/dist/transaction-BGQgnwUi.mjs +0 -28
  405. package/dist/version-CJqc1mwj.mjs +0 -6
  406. /package/dist/{base64-F8-DUraK.mjs → base64-Cz-aU0X1.mjs} +0 -0
  407. /package/dist/{challenge-store-CDKfye2r.mjs → challenge-store-DFGsDtCj.mjs} +0 -0
  408. /package/dist/{components-DAq_4iPX.mjs → components-gMTtJqHg.mjs} +0 -0
  409. /package/dist/{config-CVssduLe.mjs → config-XW5tMrH8.mjs} +0 -0
  410. /package/dist/{content-index-names-Bbu1FY1r.mjs → content-index-names-CDc2IQIx.mjs} +0 -0
  411. /package/dist/{context-types-CPWAJRs5.mjs → context-types-DLD_HnKT.mjs} +0 -0
  412. /package/dist/{default-BeIzUa1e.mjs → default-w3MwLng7.mjs} +0 -0
  413. /package/dist/{email-console-Bfi_exVg.mjs → email-console-CpvgEN1w.mjs} +0 -0
  414. /package/dist/{error-DLg1H2LT.mjs → error-B-44r5TD.mjs} +0 -0
  415. /package/dist/{escape-C6lkys0j.mjs → escape-B1GM0yJU.mjs} +0 -0
  416. /package/dist/{experimental-workflows-B9x8delL.mjs → experimental-workflows-fzJHB3ZI.mjs} +0 -0
  417. /package/dist/{hash-jhbF98tT.mjs → hash-DvMZXj2L.mjs} +0 -0
  418. /package/dist/{media-url-CL3NzgLh.mjs → media-url-D-elxQjL.mjs} +0 -0
  419. /package/dist/{mime-CDTtL7jE.mjs → mime-D_ae-u_U.mjs} +0 -0
  420. /package/dist/{mode-DJeacFCZ.mjs → mode-BJwb_MgK.mjs} +0 -0
  421. /package/dist/{normalize-Ev3FiBMx.mjs → normalize-5rct_U0I.mjs} +0 -0
  422. /package/dist/{oauth-state-store-Do1a_o3H.mjs → oauth-state-store-D2H9hKcN.mjs} +0 -0
  423. /package/dist/{options-1dBRkoCl.mjs → options-BcqHWpc-.mjs} +0 -0
  424. /package/dist/{output-8j9oltTf.mjs → output-CdmbQioY.mjs} +0 -0
  425. /package/dist/{parser-C9rzPuSZ.mjs → parser-ehIlj32k.mjs} +0 -0
  426. /package/dist/{passkey-config-CRN44T04.mjs → passkey-config-sUQoLEj_.mjs} +0 -0
  427. /package/dist/{patterns-3XE9bU4r.mjs → patterns-CZ7D4y_R.mjs} +0 -0
  428. /package/dist/{placeholder-D03pGvqM.d.mts → placeholder-CQKI6vLd.d.mts} +0 -0
  429. /package/dist/{portable-text-BdRm4uZq.d.mts → portable-text-BE7nszX6.d.mts} +0 -0
  430. /package/dist/{portable-text-tIk9_uz_.mjs → portable-text-DH3Om_2D.mjs} +0 -0
  431. /package/dist/{process-cache-B-L-A9zg.mjs → process-cache-MHM4Sqzs.mjs} +0 -0
  432. /package/dist/{provider-loader-C4i82ll1.mjs → provider-loader-Dnv2neOu.mjs} +0 -0
  433. /package/dist/{public-discovery-CyDzK1-S.mjs → public-discovery-CTql6jdZ.mjs} +0 -0
  434. /package/dist/{public-url-BVIjzMo3.mjs → public-url-4sMO36Gw.mjs} +0 -0
  435. /package/dist/{public-url-oudwI7K0.mjs → public-url-DNt9A1yS.mjs} +0 -0
  436. /package/dist/{redirect-Dp5u-8dH.mjs → redirect-Cjjb5VYr.mjs} +0 -0
  437. /package/dist/{request-cache-BruBnFAR.mjs → request-cache-DPmV5nk4.mjs} +0 -0
  438. /package/dist/{seo-contributions-BAtRDXEQ.mjs → seo-contributions-atY3jZEV.mjs} +0 -0
  439. /package/dist/{service-DeX1PRNt.mjs → service-CeEi6nax.mjs} +0 -0
  440. /package/dist/{setup-nonce-D-CEYlw7.mjs → setup-nonce-BUmfCiY1.mjs} +0 -0
  441. /package/dist/{sidecar-client-Bw2C0XTf.mjs → sidecar-client-CbrX8nuw.mjs} +0 -0
  442. /package/dist/{slugify-KSsVD_D3.mjs → slugify-Di8Q_MFq.mjs} +0 -0
  443. /package/dist/{ssrf-C7tTSD1r.mjs → ssrf-COxLChKv.mjs} +0 -0
  444. /package/dist/{stable-hash-DF7R5eN8.mjs → stable-hash-DEtJgcp7.mjs} +0 -0
  445. /package/dist/{status-Bba6RbkS.mjs → status-DBSB6tdS.mjs} +0 -0
  446. /package/dist/{transport-ktLL9r2O.d.mts → transport-CZbtxgKZ.d.mts} +0 -0
  447. /package/dist/{transport-BddGhTAI.mjs → transport-aPKvM53n.mjs} +0 -0
  448. /package/dist/{types-CKIt_jmM.d.mts → types-1qU0-N1P.d.mts} +0 -0
  449. /package/dist/{types-BQZFeZjd.mjs → types-BKsk4nnM.mjs} +0 -0
  450. /package/dist/{types-CLMOusxP.d.mts → types-BWsEjujW.d.mts} +0 -0
  451. /package/dist/{types--3oJQ0hs.d.mts → types-CAD4OvmF.d.mts} +0 -0
  452. /package/dist/{types-BbkkkAb6.mjs → types-ChSk0dmw.mjs} +0 -0
  453. /package/dist/{types-C0DPvhR5.mjs → types-CyBH89BS.mjs} +0 -0
  454. /package/dist/{types-CU3Wn2HC.d.mts → types-DNPP-eu4.d.mts} +0 -0
  455. /package/dist/{types-CPaVj_GC.d.mts → types-SddyDti7.d.mts} +0 -0
  456. /package/dist/{url-C_pLSrGZ.mjs → url-Ce0qtSdB.mjs} +0 -0
  457. /package/dist/{url-Dumsft7G.mjs → url-DfqolpO2.mjs} +0 -0
  458. /package/dist/{validate-VPnKoIzW.mjs → validate-Co3j6T_K.mjs} +0 -0
@@ -1,15 +1,21 @@
1
- import { a as __exportAll } from "./runner-DJiRFyLI.mjs";
2
- import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
3
- import { i as encodeCursor, n as ScheduledNotDueError, r as decodeCursor, t as DinewayValidationError } from "./types-BpSTdH1H.mjs";
4
- import { o as invalidateCollectionCache } from "./object-cache-D51qOseS.mjs";
5
- import { n as slugify } from "./slugify-KSsVD_D3.mjs";
6
- import { t as RevisionRepository } from "./revision-De7OmYVD.mjs";
1
+ import { c as __exportAll } from "./runner-CVeq0266.mjs";
2
+ import { atomicBatch, isD1Database, rowUnchanged } from "./database/batch.mjs";
3
+ import { t as validateIdentifier } from "./validate-Co3j6T_K.mjs";
4
+ import { o as isPostgres } from "./dialect-helpers-C6xtO-Ui.mjs";
5
+ import { i as encodeCursor, n as ScheduledNotDueError, r as decodeCursor, t as DinewayValidationError } from "./types-BqxIv8Il.mjs";
6
+ import { t as contentWriteChecks } from "./atomic-authority-CnBQJ14T.mjs";
7
+ import { o as invalidateCollectionCache } from "./object-cache-BGjIlY9s.mjs";
8
+ import { n as slugify } from "./slugify-Di8Q_MFq.mjs";
9
+ import { t as RevisionRepository } from "./revision-090sZyGc.mjs";
7
10
  import { sql } from "kysely";
8
11
  import { ulid } from "ulidx";
9
12
 
10
13
  //#region src/database/repositories/content.ts
11
14
  var content_exports = /* @__PURE__ */ __exportAll({ ContentRepository: () => ContentRepository });
12
15
  const ULID_PATTERN = /^[0-9A-Z]{26}$/;
16
+ const NUMERIC_TEXT = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
17
+ const BLOB_AFFINITY = /BLOB/i;
18
+ const TEXT_AFFINITY = /TEXT|CHAR|CLOB/i;
13
19
  const LIKE_WILDCARD_RE = /[\\%_]/g;
14
20
  const DATE_FILTER_COLUMNS = {
15
21
  createdAt: "created_at",
@@ -54,6 +60,17 @@ function serializeValue(value) {
54
60
  if (typeof value === "object") return JSON.stringify(value);
55
61
  return value;
56
62
  }
63
+ function normalizeAffinity(value, type) {
64
+ if (value === null || value === void 0) return null;
65
+ if (TEXT_AFFINITY.test(type)) return typeof value === "number" ? String(value) : value;
66
+ if (!type || BLOB_AFFINITY.test(type)) return value;
67
+ if (typeof value === "string" && NUMERIC_TEXT.test(value.trim())) {
68
+ const number = Number(value);
69
+ if (!Number.isFinite(number) || Number.isInteger(number) && !Number.isSafeInteger(number)) throw new DinewayValidationError("Numeric content must fit the supported JavaScript precision.");
70
+ return number;
71
+ }
72
+ return value;
73
+ }
57
74
  /**
58
75
  * Deserialize a value from database storage
59
76
  * Attempts to parse JSON strings that look like objects/arrays
@@ -86,20 +103,30 @@ var ContentRepository = class {
86
103
  constructor(db) {
87
104
  this.db = db;
88
105
  }
106
+ async normalizePreparedData(type, data) {
107
+ if (isPostgres(this.db)) return data;
108
+ const columns = await sql`SELECT name,type FROM pragma_table_info(${getTableName(type)})`.execute(this.db);
109
+ return Object.fromEntries(Object.entries(data).map(([name, value]) => {
110
+ const column = columns.rows.find((candidate) => candidate.name === name);
111
+ return [name, deserializeValue(column ? normalizeAffinity(serializeValue(value), column.type) : value)];
112
+ }));
113
+ }
89
114
  /**
90
115
  * Create a new content item
91
116
  */
92
- async create(input) {
117
+ async prepareCreate(input, options = {}) {
93
118
  const id = ulid();
94
119
  const now = (/* @__PURE__ */ new Date()).toISOString();
95
120
  const { type, slug, data, status = "draft", authorId, primaryBylineId, locale, translationOf, publishedAt, createdAt } = input;
96
121
  if (!type) throw new DinewayValidationError("Content type is required");
97
122
  const tableName = getTableName(type);
123
+ const checks = [];
98
124
  let translationGroup = id;
99
125
  if (translationOf) {
100
- const source = await this.findById(type, translationOf);
126
+ const source = (await sql`SELECT id, translation_group, deleted_at FROM ${sql.table(tableName)} WHERE id = ${translationOf} AND deleted_at IS NULL`.execute(this.db)).rows[0];
101
127
  if (!source) throw new DinewayValidationError("Translation source content not found");
102
- translationGroup = source.translationGroup || source.id;
128
+ translationGroup = String(source.translation_group || source.id);
129
+ checks.push(rowUnchanged(tableName, source));
103
130
  }
104
131
  const columns = [
105
132
  "id",
@@ -134,17 +161,84 @@ var ContentRepository = class {
134
161
  values.push(serializeValue(value));
135
162
  }
136
163
  }
164
+ let item;
165
+ if (options.captureDefaults) {
166
+ if (isPostgres(this.db)) throw new Error("Prepared content defaults require SQLite or D1.");
167
+ const schema = await sql`SELECT m.sql AS definition, p.name, p.type, p.dflt_value FROM sqlite_master m JOIN pragma_table_info(m.name) p WHERE m.name=${tableName} AND m.type='table'`.execute(this.db);
168
+ const definition = schema.rows[0]?.definition;
169
+ if (!definition) throw new DinewayValidationError("Content table not found");
170
+ const expressions = schema.rows.map((column) => {
171
+ const position = columns.indexOf(column.name);
172
+ const value = position >= 0 ? sql`${values[position]}` : column.dflt_value === null ? sql`NULL` : sql.raw(column.dflt_value);
173
+ return (TEXT_AFFINITY.test(column.type) ? sql`CAST(${value} AS TEXT)` : value).as(column.name);
174
+ });
175
+ const row = (await sql`SELECT ${sql.join(expressions)}`.execute(this.db)).rows[0];
176
+ for (const column of schema.rows) row[column.name] = normalizeAffinity(row[column.name], column.type);
177
+ columns.splice(0, columns.length, ...Object.keys(row));
178
+ values.splice(0, values.length, ...Object.values(row));
179
+ checks.push(sql`EXISTS (SELECT 1 FROM sqlite_master WHERE name=${tableName} AND sql=${definition})`);
180
+ item = this.mapRow(type, row);
181
+ }
137
182
  const columnRefs = columns.map((c) => sql.ref(c));
138
183
  const valuePlaceholders = values.map((v) => v === null ? sql`NULL` : sql`${v}`);
139
- await sql`
184
+ return {
185
+ id,
186
+ item,
187
+ batch: {
188
+ checks,
189
+ statements: [sql`
140
190
  INSERT INTO ${sql.ref(tableName)} (${sql.join(columnRefs, sql`, `)})
141
191
  VALUES (${sql.join(valuePlaceholders, sql`, `)})
142
- `.execute(this.db);
143
- invalidateCollectionCache(type);
144
- const item = await this.findById(type, id);
192
+ `.compile(this.db)]
193
+ }
194
+ };
195
+ }
196
+ async create(input) {
197
+ const prepared = await this.prepareCreate(input);
198
+ await atomicBatch(this.db, prepared.batch);
199
+ invalidateCollectionCache(input.type);
200
+ const item = await this.findById(input.type, prepared.id);
145
201
  if (!item) throw new Error("Failed to create content");
146
202
  return item;
147
203
  }
204
+ /** Capture database defaults and JSON values from the saved row inside the write batch. */
205
+ async prepareDraftSnapshot(type, id, authorId) {
206
+ const tableName = getTableName(type);
207
+ const checks = [];
208
+ let snapshot;
209
+ if (isPostgres(this.db)) snapshot = sql`(SELECT COALESCE(jsonb_object_agg(field.key, field.value), '{}'::jsonb)::text
210
+ FROM ${sql.table(tableName)} AS entry CROSS JOIN LATERAL jsonb_each(to_jsonb(entry)) AS field(key, value)
211
+ WHERE entry.id = ${id} AND field.value <> 'null'::jsonb
212
+ AND field.key NOT IN (${sql.join(Array.from(SYSTEM_COLUMNS, (name) => sql`${name}`))}))`;
213
+ else {
214
+ const schema = await sql`
215
+ SELECT m.sql AS definition, p.name FROM sqlite_master m
216
+ JOIN pragma_table_info(m.name) p WHERE m.name = ${tableName} AND m.type = 'table'
217
+ `.execute(this.db);
218
+ const definition = schema.rows[0]?.definition;
219
+ if (!definition) throw new DinewayValidationError("Content table not found");
220
+ const pairs = schema.rows.map((row) => row.name).filter((name) => !SYSTEM_COLUMNS.has(name)).map((name) => {
221
+ const column = sql.ref(name);
222
+ return sql`SELECT ${sql.lit(name)} AS name,
223
+ CASE WHEN typeof(${column}) = 'text' AND substr(${column}, 1, 1) IN ('{', '[') AND json_valid(${column})
224
+ THEN ${column} ELSE json_quote(${column}) END AS value
225
+ FROM candidate WHERE ${column} IS NOT NULL`;
226
+ });
227
+ snapshot = pairs.length ? sql`(WITH candidate AS (SELECT * FROM ${sql.table(tableName)} WHERE id = ${id})
228
+ SELECT json_group_object(name, json(value)) FROM (${sql.join(pairs, sql` UNION ALL `)}))` : sql`'{}'`;
229
+ checks.push(sql`EXISTS (SELECT 1 FROM sqlite_master WHERE name = ${tableName} AND sql = ${definition})`);
230
+ }
231
+ const revision = new RevisionRepository(this.db).prepareCreateSnapshot({
232
+ collection: type,
233
+ entryId: id,
234
+ data: snapshot,
235
+ authorId
236
+ });
237
+ return {
238
+ checks,
239
+ statements: [revision.statement, sql`UPDATE ${sql.table(tableName)} SET draft_revision_id = ${revision.id}, updated_at = ${(/* @__PURE__ */ new Date()).toISOString()} WHERE id = ${id}`.compile(this.db)]
240
+ };
241
+ }
148
242
  /**
149
243
  * Generate a unique slug for a content item within a collection.
150
244
  *
@@ -169,13 +263,15 @@ var ContentRepository = class {
169
263
  LIMIT 1
170
264
  `.execute(this.db)).rows.length === 0) return baseSlug;
171
265
  const pattern = `${baseSlug}-%`;
266
+ const prefix = `${baseSlug}-`;
267
+ const prefixMatch = isD1Database(this.db) ? sql`substr(slug, 1, length(${prefix})) = ${prefix}` : sql`slug LIKE ${pattern}`;
172
268
  const candidates = locale ? await sql`
173
269
  SELECT slug FROM ${sql.ref(tableName)}
174
- WHERE (slug = ${baseSlug} OR slug LIKE ${pattern})
270
+ WHERE (slug = ${baseSlug} OR ${prefixMatch})
175
271
  AND locale = ${locale}
176
272
  `.execute(this.db) : await sql`
177
273
  SELECT slug FROM ${sql.ref(tableName)}
178
- WHERE slug = ${baseSlug} OR slug LIKE ${pattern}
274
+ WHERE slug = ${baseSlug} OR ${prefixMatch}
179
275
  `.execute(this.db);
180
276
  let maxSuffix = 0;
181
277
  const suffixPattern = new RegExp(`^${escapeRegExp(baseSlug)}-(\\d+)$`);
@@ -193,21 +289,42 @@ var ContentRepository = class {
193
289
  * Creates a new draft copy with "(Copy)" appended to the title.
194
290
  * A slug is auto-generated from the new title by the handler layer.
195
291
  */
196
- async duplicate(type, id, authorId) {
197
- const original = await this.findById(type, id);
198
- if (!original) throw new DinewayValidationError("Content item not found");
292
+ async prepareDuplicate(type, id, authorId) {
293
+ const snapshot = await this.snapshot(type, id);
294
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
295
+ const original = snapshot.item;
199
296
  const newData = { ...original.data };
200
297
  if (typeof newData.title === "string") newData.title = `${newData.title} (Copy)`;
201
298
  else if (typeof newData.name === "string") newData.name = `${newData.name} (Copy)`;
202
299
  const slugSource = typeof newData.title === "string" ? newData.title : typeof newData.name === "string" ? newData.name : null;
203
300
  const slug = slugSource ? await this.generateUniqueSlug(type, slugSource, original.locale ?? void 0) : null;
204
- return this.create({
301
+ const prepared = await this.prepareCreate({
205
302
  type,
206
303
  slug,
207
304
  data: newData,
208
305
  status: "draft",
209
- authorId: authorId || original.authorId || void 0
306
+ authorId: authorId || original.authorId || void 0,
307
+ locale: original.locale ?? void 0
210
308
  });
309
+ return {
310
+ id: prepared.id,
311
+ batch: {
312
+ checks: [
313
+ snapshot.check,
314
+ ...contentWriteChecks(type, id, "edit"),
315
+ ...prepared.batch.checks ?? []
316
+ ],
317
+ statements: prepared.batch.statements
318
+ }
319
+ };
320
+ }
321
+ async duplicate(type, id, authorId) {
322
+ const prepared = await this.prepareDuplicate(type, id, authorId);
323
+ await atomicBatch(this.db, prepared.batch);
324
+ invalidateCollectionCache(type);
325
+ const item = await this.findById(type, prepared.id);
326
+ if (!item) throw new Error("Failed to reload duplicate");
327
+ return item;
211
328
  }
212
329
  /**
213
330
  * Find content by ID
@@ -343,10 +460,10 @@ var ContentRepository = class {
343
460
  /**
344
461
  * Update content
345
462
  */
346
- async update(type, id, input) {
463
+ prepareUpdate(type, id, input, now = (/* @__PURE__ */ new Date()).toISOString()) {
347
464
  const tableName = getTableName(type);
348
465
  const updates = {
349
- updated_at: (/* @__PURE__ */ new Date()).toISOString(),
466
+ updated_at: now,
350
467
  version: sql`version + 1`
351
468
  };
352
469
  if (input.status !== void 0) updates.status = input.status;
@@ -361,7 +478,21 @@ var ContentRepository = class {
361
478
  updates[key] = serializeValue(value);
362
479
  }
363
480
  }
364
- await this.db.updateTable(tableName).set(updates).where("id", "=", id).where("deleted_at", "is", null).execute();
481
+ return this.db.updateTable(tableName).set(updates).where("id", "=", id).where("deleted_at", "is", null).compile();
482
+ }
483
+ async snapshot(type, id, includeTrashed = false) {
484
+ const row = (await sql`SELECT * FROM ${sql.table(getTableName(type))} WHERE id = ${id} AND ${includeTrashed ? sql`true` : sql`deleted_at IS NULL`}`.execute(this.db)).rows[0];
485
+ return row ? {
486
+ item: this.mapRow(type, row),
487
+ deleted: row.deleted_at !== null,
488
+ check: rowUnchanged(getTableName(type), row)
489
+ } : null;
490
+ }
491
+ async update(type, id, input) {
492
+ await atomicBatch(this.db, {
493
+ checks: contentWriteChecks(type, id, "edit"),
494
+ statements: [this.prepareUpdate(type, id, input)]
495
+ });
365
496
  invalidateCollectionCache(type);
366
497
  const updated = await this.findById(type, id);
367
498
  if (!updated) throw new Error("Content not found");
@@ -370,15 +501,22 @@ var ContentRepository = class {
370
501
  /**
371
502
  * Delete content (soft delete - moves to trash)
372
503
  */
373
- async delete(type, id) {
504
+ prepareDelete(type, id) {
374
505
  const tableName = getTableName(type);
375
506
  const now = (/* @__PURE__ */ new Date()).toISOString();
376
- const changed = ((await sql`
507
+ return {
508
+ checks: contentWriteChecks(type, id, "delete"),
509
+ statements: [sql`
377
510
  UPDATE ${sql.ref(tableName)}
378
511
  SET deleted_at = ${now}
379
512
  WHERE id = ${id}
380
513
  AND deleted_at IS NULL
381
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
514
+ `.compile(this.db)]
515
+ };
516
+ }
517
+ async delete(type, id) {
518
+ const [result] = await atomicBatch(this.db, this.prepareDelete(type, id));
519
+ const changed = (result?.numAffectedRows ?? 0n) > 0n;
382
520
  if (changed) invalidateCollectionCache(type);
383
521
  return changed;
384
522
  }
@@ -387,13 +525,17 @@ var ContentRepository = class {
387
525
  */
388
526
  async restore(type, id) {
389
527
  const tableName = getTableName(type);
390
- const restored = (await sql`
528
+ const [result] = await atomicBatch(this.db, {
529
+ checks: contentWriteChecks(type, id, "edit"),
530
+ statements: [sql`
391
531
  UPDATE ${sql.ref(tableName)}
392
532
  SET deleted_at = NULL
393
533
  WHERE id = ${id}
394
534
  AND deleted_at IS NOT NULL
395
535
  RETURNING *
396
- `.execute(this.db)).rows[0];
536
+ `.compile(this.db)]
537
+ });
538
+ const restored = result?.rows[0];
397
539
  if (!restored) return null;
398
540
  invalidateCollectionCache(type);
399
541
  return this.mapRow(type, restored);
@@ -403,11 +545,15 @@ var ContentRepository = class {
403
545
  */
404
546
  async permanentDelete(type, id) {
405
547
  const tableName = getTableName(type);
406
- const changed = ((await sql`
548
+ const [result] = await atomicBatch(this.db, {
549
+ checks: contentWriteChecks(type, id, "permanent"),
550
+ statements: [sql`
407
551
  DELETE FROM ${sql.ref(tableName)}
408
552
  WHERE id = ${id}
409
553
  AND deleted_at IS NOT NULL
410
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
554
+ `.compile(this.db)]
555
+ });
556
+ const changed = (result?.numAffectedRows ?? 0n) > 0n;
411
557
  if (changed) invalidateCollectionCache(type);
412
558
  return changed;
413
559
  }
@@ -488,7 +634,7 @@ var ContentRepository = class {
488
634
  const pattern = `%${term.replace(LIKE_WILDCARD_RE, (character) => `\\${character}`)}%`;
489
635
  return query.where((eb) => eb.or(columns.map((column) => {
490
636
  validateIdentifier(column, "search column");
491
- return eb(sql`lower(${sql.ref(column)})`, "like", sql`lower(${pattern}) escape '\\'`);
637
+ return isD1Database(this.db) ? sql`instr(lower(${sql.ref(column)}), lower(${term})) > 0` : eb(sql`lower(${sql.ref(column)})`, "like", sql`lower(${pattern}) escape '\\'`);
492
638
  })));
493
639
  }
494
640
  applyDateFilter(query, where) {
@@ -528,17 +674,20 @@ var ContentRepository = class {
528
674
  const scheduledDate = new Date(scheduledAt);
529
675
  if (isNaN(scheduledDate.getTime())) throw new DinewayValidationError("Invalid scheduled date");
530
676
  if (scheduledDate <= /* @__PURE__ */ new Date()) throw new DinewayValidationError("Scheduled date must be in the future");
531
- const existing = await this.findById(type, id);
532
- if (!existing) throw new DinewayValidationError("Content item not found");
533
- const newStatus = existing.status === "published" ? "published" : "scheduled";
534
- await sql`
677
+ const snapshot = await this.snapshot(type, id);
678
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
679
+ const newStatus = snapshot.item.status === "published" ? "published" : "scheduled";
680
+ await atomicBatch(this.db, {
681
+ checks: [snapshot.check, ...contentWriteChecks(type, id, "publish")],
682
+ statements: [sql`
535
683
  UPDATE ${sql.ref(tableName)}
536
684
  SET status = ${newStatus},
537
685
  scheduled_at = ${scheduledAt},
538
686
  updated_at = ${now}
539
687
  WHERE id = ${id}
540
688
  AND deleted_at IS NULL
541
- `.execute(this.db);
689
+ `.compile(this.db)]
690
+ });
542
691
  invalidateCollectionCache(type);
543
692
  const updated = await this.findById(type, id);
544
693
  if (!updated) throw new Error("Content not found");
@@ -553,10 +702,12 @@ var ContentRepository = class {
553
702
  async unschedule(type, id) {
554
703
  const tableName = getTableName(type);
555
704
  const now = (/* @__PURE__ */ new Date()).toISOString();
556
- const existing = await this.findById(type, id);
557
- if (!existing) throw new DinewayValidationError("Content item not found");
558
- const newStatus = existing.status === "published" ? "published" : "draft";
559
- await sql`
705
+ const snapshot = await this.snapshot(type, id);
706
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
707
+ const newStatus = snapshot.item.status === "published" ? "published" : "draft";
708
+ await atomicBatch(this.db, {
709
+ checks: [snapshot.check, ...contentWriteChecks(type, id, "publish")],
710
+ statements: [sql`
560
711
  UPDATE ${sql.ref(tableName)}
561
712
  SET status = ${newStatus},
562
713
  scheduled_at = NULL,
@@ -564,7 +715,8 @@ var ContentRepository = class {
564
715
  WHERE id = ${id}
565
716
  AND scheduled_at IS NOT NULL
566
717
  AND deleted_at IS NULL
567
- `.execute(this.db);
718
+ `.compile(this.db)]
719
+ });
568
720
  invalidateCollectionCache(type);
569
721
  const updated = await this.findById(type, id);
570
722
  if (!updated) throw new Error("Content not found");
@@ -613,88 +765,55 @@ var ContentRepository = class {
613
765
  * `publishedAt` overrides the publication timestamp. If omitted, an existing
614
766
  * `published_at` is preserved and first publish falls back to the current time.
615
767
  */
616
- async publish(type, id, publishedAt, requireScheduledDue = false) {
768
+ async preparePublish(type, id, publishedAt, requireScheduledDue = false) {
617
769
  const tableName = getTableName(type);
618
770
  const now = (/* @__PURE__ */ new Date()).toISOString();
619
- const existing = await this.findById(type, id);
620
- if (!existing) throw new DinewayValidationError("Content item not found");
621
- let claimedScheduledAt = null;
622
- let claimedUpdatedAt = null;
623
- if (requireScheduledDue) {
624
- const claim = await sql`
625
- UPDATE ${sql.ref(tableName)}
626
- SET scheduled_at = NULL,
627
- updated_at = ${now}
628
- WHERE id = ${id}
629
- AND scheduled_at IS NOT NULL
630
- AND scheduled_at <= ${now}
631
- AND deleted_at IS NULL
632
- `.execute(this.db);
633
- if (Number(claim.numAffectedRows ?? 0) === 0) throw new ScheduledNotDueError();
634
- claimedScheduledAt = existing.scheduledAt;
635
- claimedUpdatedAt = existing.updatedAt;
636
- }
637
- let publishCommitted = false;
638
- try {
639
- const revisionRepo = new RevisionRepository(this.db);
640
- let revisionToPublish = existing.draftRevisionId || existing.liveRevisionId;
641
- if (!revisionToPublish) revisionToPublish = (await revisionRepo.create({
771
+ const snapshot = await this.snapshot(type, id);
772
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
773
+ const existing = snapshot.item;
774
+ if (requireScheduledDue && (!existing.scheduledAt || existing.scheduledAt > now)) throw new ScheduledNotDueError();
775
+ const checks = [snapshot.check];
776
+ const statements = [];
777
+ let revisionId = existing.draftRevisionId || existing.liveRevisionId;
778
+ let data = existing.data;
779
+ if (revisionId) {
780
+ const revision = await this.db.selectFrom("revisions").selectAll().where("id", "=", revisionId).executeTakeFirst();
781
+ if (!revision || revision.collection !== type || revision.entry_id !== id) throw new DinewayValidationError("Revision does not belong to the specified content item");
782
+ checks.push(rowUnchanged("revisions", revision));
783
+ data = JSON.parse(revision.data);
784
+ } else {
785
+ const revision = new RevisionRepository(this.db).prepareCreateSnapshot({
642
786
  collection: type,
643
787
  entryId: id,
644
- data: existing.data
645
- })).id;
646
- const revision = await revisionRepo.findById(revisionToPublish);
647
- if (revision) {
648
- await this.syncDataColumns(type, id, revision.data);
649
- if (typeof revision.data._slug === "string") await sql`
650
- UPDATE ${sql.ref(tableName)}
651
- SET slug = ${revision.data._slug}
652
- WHERE id = ${id}
653
- `.execute(this.db);
654
- }
655
- if (publishedAt !== void 0) await sql`
656
- UPDATE ${sql.ref(tableName)}
657
- SET live_revision_id = ${revisionToPublish},
658
- draft_revision_id = NULL,
659
- status = 'published',
660
- scheduled_at = NULL,
661
- published_at = ${publishedAt},
662
- updated_at = ${now}
663
- WHERE id = ${id}
664
- AND deleted_at IS NULL
665
- `.execute(this.db);
666
- else await sql`
667
- UPDATE ${sql.ref(tableName)}
668
- SET live_revision_id = ${revisionToPublish},
669
- draft_revision_id = NULL,
670
- status = 'published',
671
- scheduled_at = NULL,
672
- published_at = COALESCE(published_at, ${now}),
673
- updated_at = ${now}
674
- WHERE id = ${id}
675
- AND deleted_at IS NULL
676
- `.execute(this.db);
677
- publishCommitted = true;
678
- const updated = await this.findById(type, id);
679
- if (!updated) throw new Error("Content not found");
680
- invalidateCollectionCache(type);
681
- return updated;
682
- } catch (error) {
683
- if (requireScheduledDue && claimedScheduledAt && !publishCommitted) try {
684
- await sql`
685
- UPDATE ${sql.ref(tableName)}
686
- SET scheduled_at = ${claimedScheduledAt},
687
- updated_at = ${claimedUpdatedAt ?? now}
688
- WHERE id = ${id}
689
- AND scheduled_at IS NULL
690
- AND deleted_at IS NULL
691
- AND (status != 'published' OR draft_revision_id IS NOT NULL)
692
- `.execute(this.db);
693
- } catch (restoreError) {
694
- console.error(`[content] Failed to restore schedule for ${type}/${id} after publish failure:`, restoreError);
695
- }
696
- throw error;
788
+ data: sql`${JSON.stringify(data)}`
789
+ });
790
+ revisionId = revision.id;
791
+ statements.push(revision.statement);
697
792
  }
793
+ const sync = this.prepareSyncDataColumns(type, id, data);
794
+ if (sync) statements.push(sync);
795
+ const slug = typeof data._slug === "string" ? data._slug : existing.slug;
796
+ statements.push(sql`UPDATE ${sql.table(tableName)} SET slug = ${slug},
797
+ live_revision_id = ${revisionId}, draft_revision_id = NULL,
798
+ status = 'published', scheduled_at = NULL,
799
+ published_at = ${publishedAt !== void 0 ? sql`${publishedAt}` : sql`COALESCE(published_at, ${now})`}, updated_at = ${now}
800
+ WHERE id = ${id} AND deleted_at IS NULL`.compile(this.db));
801
+ return {
802
+ batch: {
803
+ checks,
804
+ statements
805
+ },
806
+ previous: existing,
807
+ slug
808
+ };
809
+ }
810
+ async publish(type, id, publishedAt, requireScheduledDue = false) {
811
+ const prepared = await this.preparePublish(type, id, publishedAt, requireScheduledDue);
812
+ await atomicBatch(this.db, prepared.batch);
813
+ invalidateCollectionCache(type);
814
+ const item = await this.findById(type, id);
815
+ if (!item) throw new Error("Content not found");
816
+ return item;
698
817
  }
699
818
  /**
700
819
  * Stage an existing revision as the draft for a content item.
@@ -704,18 +823,19 @@ var ContentRepository = class {
704
823
  */
705
824
  async setDraftRevision(type, id, revisionId) {
706
825
  const tableName = getTableName(type);
707
- const now = (/* @__PURE__ */ new Date()).toISOString();
708
- if (!await this.findById(type, id)) throw new DinewayValidationError("Content item not found");
709
- const revision = await new RevisionRepository(this.db).findById(revisionId);
826
+ const snapshot = await this.snapshot(type, id);
827
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
828
+ const revision = await this.db.selectFrom("revisions").selectAll().where("id", "=", revisionId).executeTakeFirst();
710
829
  if (!revision) throw new DinewayValidationError("Revision not found");
711
- if (revision.collection !== type || revision.entryId !== id) throw new DinewayValidationError("Revision does not belong to the specified content item");
712
- await sql`
713
- UPDATE ${sql.ref(tableName)}
714
- SET draft_revision_id = ${revisionId},
715
- updated_at = ${now}
716
- WHERE id = ${id}
717
- AND deleted_at IS NULL
718
- `.execute(this.db);
830
+ if (revision.collection !== type || revision.entry_id !== id) throw new DinewayValidationError("Revision does not belong to the specified content item");
831
+ await atomicBatch(this.db, {
832
+ checks: [
833
+ snapshot.check,
834
+ rowUnchanged("revisions", revision),
835
+ ...contentWriteChecks(type, id, "edit")
836
+ ],
837
+ statements: [sql`UPDATE ${sql.table(tableName)} SET draft_revision_id = ${revisionId}, updated_at = ${(/* @__PURE__ */ new Date()).toISOString()} WHERE id = ${id} AND deleted_at IS NULL`.compile(this.db)]
838
+ });
719
839
  invalidateCollectionCache(type);
720
840
  }
721
841
  /**
@@ -726,37 +846,35 @@ var ContentRepository = class {
726
846
  */
727
847
  async unpublish(type, id) {
728
848
  const tableName = getTableName(type);
729
- const now = (/* @__PURE__ */ new Date()).toISOString();
730
- const existing = await this.findById(type, id);
731
- if (!existing) throw new DinewayValidationError("Content item not found");
732
- if (!existing.draftRevisionId && existing.liveRevisionId) {
733
- const revisionRepo = new RevisionRepository(this.db);
734
- const liveRevision = await revisionRepo.findById(existing.liveRevisionId);
735
- if (liveRevision) {
736
- const draft = await revisionRepo.create({
737
- collection: type,
738
- entryId: id,
739
- data: liveRevision.data
740
- });
741
- await sql`
742
- UPDATE ${sql.ref(tableName)}
743
- SET draft_revision_id = ${draft.id}
744
- WHERE id = ${id}
745
- `.execute(this.db);
746
- }
849
+ const snapshot = await this.snapshot(type, id);
850
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
851
+ const existing = snapshot.item;
852
+ const checks = [snapshot.check, ...contentWriteChecks(type, id, "publish")];
853
+ const statements = [];
854
+ let draftId = existing.draftRevisionId;
855
+ if (!draftId && existing.liveRevisionId) {
856
+ const live = await this.db.selectFrom("revisions").selectAll().where("id", "=", existing.liveRevisionId).executeTakeFirst();
857
+ if (!live || live.collection !== type || live.entry_id !== id) throw new DinewayValidationError("Live revision not found");
858
+ checks.push(rowUnchanged("revisions", live));
859
+ const draft = new RevisionRepository(this.db).prepareCreateSnapshot({
860
+ collection: type,
861
+ entryId: id,
862
+ data: sql`${live.data}`
863
+ });
864
+ draftId = draft.id;
865
+ statements.push(draft.statement);
747
866
  }
748
- await sql`
749
- UPDATE ${sql.ref(tableName)}
750
- SET live_revision_id = NULL,
751
- status = 'draft',
752
- updated_at = ${now}
753
- WHERE id = ${id}
754
- AND deleted_at IS NULL
755
- `.execute(this.db);
867
+ statements.push(sql`UPDATE ${sql.table(tableName)} SET live_revision_id = NULL,
868
+ draft_revision_id = ${draftId}, status = 'draft', updated_at = ${(/* @__PURE__ */ new Date()).toISOString()}
869
+ WHERE id = ${id} AND deleted_at IS NULL`.compile(this.db));
870
+ await atomicBatch(this.db, {
871
+ checks,
872
+ statements
873
+ });
756
874
  invalidateCollectionCache(type);
757
- const updated = await this.findById(type, id);
758
- if (!updated) throw new Error("Content not found");
759
- return updated;
875
+ const item = await this.findById(type, id);
876
+ if (!item) throw new Error("Content not found");
877
+ return item;
760
878
  }
761
879
  /**
762
880
  * Discard pending draft changes
@@ -767,16 +885,20 @@ var ContentRepository = class {
767
885
  async discardDraft(type, id) {
768
886
  const tableName = getTableName(type);
769
887
  const now = (/* @__PURE__ */ new Date()).toISOString();
770
- const existing = await this.findById(type, id);
771
- if (!existing) throw new DinewayValidationError("Content item not found");
888
+ const snapshot = await this.snapshot(type, id);
889
+ if (!snapshot) throw new DinewayValidationError("Content item not found");
890
+ const existing = snapshot.item;
772
891
  if (!existing.draftRevisionId) return existing;
773
- await sql`
892
+ await atomicBatch(this.db, {
893
+ checks: [snapshot.check, ...contentWriteChecks(type, id, "edit")],
894
+ statements: [sql`
774
895
  UPDATE ${sql.ref(tableName)}
775
896
  SET draft_revision_id = NULL,
776
897
  updated_at = ${now}
777
898
  WHERE id = ${id}
778
899
  AND deleted_at IS NULL
779
- `.execute(this.db);
900
+ `.compile(this.db)]
901
+ });
780
902
  invalidateCollectionCache(type);
781
903
  const updated = await this.findById(type, id);
782
904
  if (!updated) throw new Error("Content not found");
@@ -787,7 +909,7 @@ var ContentRepository = class {
787
909
  * Used to promote revision data into the content table on publish.
788
910
  * Keys starting with _ are revision metadata (e.g. _slug) and are skipped.
789
911
  */
790
- async syncDataColumns(type, id, data) {
912
+ prepareSyncDataColumns(type, id, data) {
791
913
  const tableName = getTableName(type);
792
914
  const updates = {};
793
915
  for (const [key, value] of Object.entries(data)) {
@@ -796,8 +918,8 @@ var ContentRepository = class {
796
918
  validateIdentifier(key, "content field name");
797
919
  updates[key] = serializeValue(value);
798
920
  }
799
- if (Object.keys(updates).length === 0) return;
800
- await this.db.updateTable(tableName).set(updates).where("id", "=", id).execute();
921
+ if (Object.keys(updates).length === 0) return null;
922
+ return this.db.updateTable(tableName).set(updates).where("id", "=", id).compile();
801
923
  }
802
924
  /**
803
925
  * Count content items with a pending schedule.