dineway 0.2.0 → 0.2.1

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 (403) hide show
  1. package/dist/activity-DUaz_w7p.mjs +79 -0
  2. package/dist/{activity-events-y6eT8UW6.mjs → activity-events-CJDvE2uc.mjs} +1 -77
  3. package/dist/{actor-CrObAPV0.mjs → actor-0QJ1Gbtf.mjs} +1 -1
  4. package/dist/{allowed-origins-_oeyP6x-.mjs → allowed-origins--OwHHiY8.mjs} +1 -1
  5. package/dist/api/route-utils.d.mts +9 -10
  6. package/dist/api/route-utils.mjs +14 -14
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +5 -5
  9. package/dist/{api-ByrU2q-Z.mjs → api-B4PHIF4V.mjs} +51 -23
  10. package/dist/{api-tokens-CjVMQT-X.mjs → api-tokens-tbK_sORH.mjs} +1 -1
  11. package/dist/{apply-bZswmZPm.mjs → apply-DjTqq6Ae.mjs} +19 -19
  12. package/dist/astro/index.d.mts +10 -11
  13. package/dist/astro/index.mjs +10 -5
  14. package/dist/astro/middleware/auth.d.mts +9 -19
  15. package/dist/astro/middleware/auth.mjs +6 -6
  16. package/dist/astro/middleware/redirect.mjs +5 -5
  17. package/dist/astro/middleware/request-context.mjs +2 -2
  18. package/dist/astro/middleware/seed.d.mts +1 -1
  19. package/dist/astro/middleware/seed.mjs +1 -1
  20. package/dist/astro/middleware/setup.mjs +1 -1
  21. package/dist/astro/middleware.mjs +140 -98
  22. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
  23. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
  24. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  25. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  26. package/dist/astro/routes/api/admin/briefing.mjs +18 -18
  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 +9 -9
  29. package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
  30. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
  31. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +16 -16
  32. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
  33. package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
  34. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
  35. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  36. package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
  37. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  38. package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
  39. package/dist/astro/routes/api/admin/context/_id_/history.mjs +25 -24
  40. package/dist/astro/routes/api/admin/context/_id_/index.mjs +25 -24
  41. package/dist/astro/routes/api/admin/context/_id_/review.mjs +30 -29
  42. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +30 -29
  43. package/dist/astro/routes/api/admin/context/diff.mjs +29 -28
  44. package/dist/astro/routes/api/admin/context/index.mjs +30 -29
  45. package/dist/astro/routes/api/admin/context/stale.mjs +29 -28
  46. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +25 -24
  47. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +29 -28
  48. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +29 -28
  49. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +26 -25
  50. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +2 -2
  51. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
  52. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
  53. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +52 -51
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +52 -51
  55. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +44 -44
  56. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +51 -50
  57. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +51 -50
  58. package/dist/astro/routes/api/admin/plugins/index.mjs +44 -44
  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 +44 -44
  61. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +51 -50
  62. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +44 -44
  63. package/dist/astro/routes/api/admin/plugins/updates.mjs +44 -44
  64. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +5 -5
  65. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +30 -65
  66. package/dist/astro/routes/api/admin/review-requests/index.d.mts +2 -1
  67. package/dist/astro/routes/api/admin/review-requests/index.mjs +58 -11
  68. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +44 -44
  69. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  70. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +44 -44
  71. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  72. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  73. package/dist/astro/routes/api/admin/users/_id_/index.mjs +7 -7
  74. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  75. package/dist/astro/routes/api/admin/users/index.mjs +6 -6
  76. package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
  77. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  78. package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
  79. package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
  80. package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
  81. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  82. package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
  83. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  84. package/dist/astro/routes/api/auth/me.mjs +8 -8
  85. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  86. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +2 -2
  87. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  88. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
  89. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  90. package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
  91. package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
  92. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
  93. package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
  94. package/dist/astro/routes/api/auth/setup-token/index.mjs +5 -5
  95. package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
  96. package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
  97. package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
  98. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  99. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
  100. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
  101. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  102. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -5
  103. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +6 -5
  104. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +6 -5
  105. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -10
  106. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +49 -21
  107. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +6 -5
  108. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  109. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +67 -33
  110. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +14 -14
  111. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  112. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -5
  113. package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
  114. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  115. package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
  116. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
  117. package/dist/astro/routes/api/dashboard.mjs +8 -8
  118. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  119. package/dist/astro/routes/api/health.mjs +1 -1
  120. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  121. package/dist/astro/routes/api/import/probe.mjs +19 -19
  122. package/dist/astro/routes/api/import/wordpress/analyze.mjs +8 -8
  123. package/dist/astro/routes/api/import/wordpress/execute.d.mts +8 -9
  124. package/dist/astro/routes/api/import/wordpress/execute.mjs +35 -34
  125. package/dist/astro/routes/api/import/wordpress/media.d.mts +8 -9
  126. package/dist/astro/routes/api/import/wordpress/media.mjs +12 -12
  127. package/dist/astro/routes/api/import/wordpress/prepare.mjs +34 -33
  128. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +9 -10
  129. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +31 -30
  130. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  131. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +22 -22
  132. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +8 -9
  133. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +40 -39
  134. package/dist/astro/routes/api/manifest.mjs +4 -4
  135. package/dist/astro/routes/api/mcp.mjs +554 -167
  136. package/dist/astro/routes/api/media/_id_/confirm.mjs +10 -10
  137. package/dist/astro/routes/api/media/_id_.mjs +8 -8
  138. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  139. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  140. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  141. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  142. package/dist/astro/routes/api/media/upload-url.mjs +11 -11
  143. package/dist/astro/routes/api/media.mjs +14 -14
  144. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +30 -29
  145. package/dist/astro/routes/api/menus/_name_/items.mjs +30 -29
  146. package/dist/astro/routes/api/menus/_name_/reorder.mjs +30 -29
  147. package/dist/astro/routes/api/menus/_name_/translations.mjs +30 -29
  148. package/dist/astro/routes/api/menus/_name_.mjs +30 -29
  149. package/dist/astro/routes/api/menus/index.mjs +30 -29
  150. package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
  151. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  152. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  153. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  154. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  155. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  156. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  157. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  158. package/dist/astro/routes/api/openapi.json.mjs +4 -4
  159. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +20 -5
  160. package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
  161. package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
  162. package/dist/astro/routes/api/redirects/_id_.mjs +31 -30
  163. package/dist/astro/routes/api/redirects/index.mjs +31 -30
  164. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  165. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  166. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +46 -45
  167. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +46 -45
  168. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +46 -45
  169. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +46 -45
  170. package/dist/astro/routes/api/schema/collections/index.mjs +46 -45
  171. package/dist/astro/routes/api/schema/index.mjs +8 -8
  172. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +44 -44
  173. package/dist/astro/routes/api/schema/orphans/index.mjs +44 -44
  174. package/dist/astro/routes/api/search/enable.mjs +11 -11
  175. package/dist/astro/routes/api/search/index.mjs +10 -10
  176. package/dist/astro/routes/api/search/rebuild.mjs +11 -11
  177. package/dist/astro/routes/api/search/stats.mjs +6 -6
  178. package/dist/astro/routes/api/search/suggest.mjs +10 -10
  179. package/dist/astro/routes/api/sections/_slug_.mjs +30 -29
  180. package/dist/astro/routes/api/sections/index.mjs +30 -29
  181. package/dist/astro/routes/api/settings/email.mjs +3 -3
  182. package/dist/astro/routes/api/settings.mjs +30 -29
  183. package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
  184. package/dist/astro/routes/api/setup/admin.mjs +10 -10
  185. package/dist/astro/routes/api/setup/dev-bypass.mjs +25 -25
  186. package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
  187. package/dist/astro/routes/api/setup/index.mjs +27 -27
  188. package/dist/astro/routes/api/setup/status.mjs +3 -3
  189. package/dist/astro/routes/api/snapshot.mjs +6 -6
  190. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +33 -32
  191. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +33 -32
  192. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +33 -32
  193. package/dist/astro/routes/api/taxonomies/index.mjs +33 -32
  194. package/dist/astro/routes/api/themes/preview.mjs +4 -4
  195. package/dist/astro/routes/api/typegen.mjs +4 -4
  196. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  197. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  198. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  199. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +29 -28
  200. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +30 -29
  201. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +30 -29
  202. package/dist/astro/routes/api/widget-areas/_name_.mjs +27 -26
  203. package/dist/astro/routes/api/widget-areas/index.mjs +30 -29
  204. package/dist/astro/routes/api/widget-components.mjs +2 -2
  205. package/dist/astro/routes/robots.txt.mjs +6 -6
  206. package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
  207. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  208. package/dist/astro/session-driver.d.mts +1 -1
  209. package/dist/astro/session-driver.mjs +2 -2
  210. package/dist/astro/types.d.mts +13 -12
  211. package/dist/{audit-ByVKIwWF.mjs → audit-B2pRxZ20.mjs} +1 -1
  212. package/dist/auth/providers/github.d.mts +1 -1
  213. package/dist/auth/providers/google.d.mts +1 -1
  214. package/dist/{auth-control-guard-CqeUmQsv.mjs → auth-control-guard-D71jourk.mjs} +1 -1
  215. package/dist/{authorize-CcBxcHtz.mjs → authorize-ZXPGPwKn.mjs} +1 -1
  216. package/dist/{briefing-CawZ59CY.mjs → briefing-0rf-su3-.mjs} +7 -7
  217. package/dist/{briefing-BJaJI8dm.mjs → briefing-kRhegBoF.mjs} +1 -1
  218. package/dist/{bundle-7C_DpkEq.mjs → bundle-CEcdUa1s.mjs} +2 -2
  219. package/dist/{byline-e51-fWRs.mjs → byline-7xR185Ly.mjs} +6 -6
  220. package/dist/{byline-fields-D-N5qVIG.mjs → byline-fields-BKzA0fJU.mjs} +1 -1
  221. package/dist/{byline-fields-CUvbslGc.d.mts → byline-fields-Ckeqd1OY.d.mts} +57 -47
  222. package/dist/{byline-fields-DOJO16Gm.mjs → byline-fields-WN7RQT4q.mjs} +10 -4
  223. package/dist/{byline-registry-87nNnYl4.mjs → byline-registry-Ba54M74c.mjs} +2 -2
  224. package/dist/{bylines-CMQNCNFh.mjs → bylines-C-EL6dh3.mjs} +3 -3
  225. package/dist/{bylines-y4LO-dTj.mjs → bylines-CmZFCMr0.mjs} +5 -5
  226. package/dist/{cache-C-FNTFYK.mjs → cache-DkVCKGio.mjs} +2 -2
  227. package/dist/{chunks-CxBt-GxR.mjs → chunks-ChGNDY8r.mjs} +1 -1
  228. package/dist/cli/index.d.mts +29 -1
  229. package/dist/cli/index.mjs +1391 -1123
  230. package/dist/cli/plugin-kit.d.mts +75 -0
  231. package/dist/cli/plugin-kit.mjs +4 -0
  232. package/dist/client/external-auth-headers.d.mts +1 -1
  233. package/dist/client/index.d.mts +27 -52
  234. package/dist/client/index.mjs +34 -7
  235. package/dist/client-factory-BDD9azPJ.mjs +233 -0
  236. package/dist/{comment-DlA4iChg.mjs → comment-DFALgsJD.mjs} +1 -1
  237. package/dist/{comment-reaction-DfFao1ST.mjs → comment-reaction-C37bf99u.mjs} +1 -1
  238. package/dist/{comments-DApFGMsP.mjs → comments-B3NwDBxl.mjs} +1 -1
  239. package/dist/{content-Bh4BDjv8.mjs → content-DJcAYFhz.mjs} +2 -2
  240. package/dist/{content-refresh-CgutSUfO.mjs → content-refresh-B4ZCmxgd.mjs} +5 -5
  241. package/dist/{context-CK4ym2Sf.mjs → context-DnpXcp6Y.mjs} +2 -2
  242. package/dist/{context-C5W3G18y.mjs → context-fSCYLL3c.mjs} +24 -13
  243. package/dist/{context-route-helpers-MASyGgWf.mjs → context-route-helpers-CI8XzcsK.mjs} +2 -2
  244. package/dist/{dashboard-DQkVT7Ei.mjs → dashboard-D0nj5oWg.mjs} +4 -4
  245. package/dist/db/index.d.mts +3 -3
  246. package/dist/db/index.mjs +1 -1
  247. package/dist/db/libsql.d.mts +1 -1
  248. package/dist/db/postgres.d.mts +1 -1
  249. package/dist/db/sqlite.d.mts +1 -1
  250. package/dist/{device-flow-BnqRH-T9.mjs → device-flow-BJe6VEhP.mjs} +5 -5
  251. package/dist/{enrich-DIFIFA8O.mjs → enrich-Ck9tfMqe.mjs} +1 -1
  252. package/dist/{experimental-workflows-BMsUnIAw.mjs → experimental-workflows-GVhUgzEs.mjs} +1 -1
  253. package/dist/{field-defs-cache-DRNdhBJv.mjs → field-defs-cache-DL-T2XVS.mjs} +4 -4
  254. package/dist/forgeway-seo-client-G5ddhVHd.mjs +456 -0
  255. package/dist/{fts-manager-Crzypjqu.mjs → fts-manager-ewTGohf4.mjs} +1 -1
  256. package/dist/{hitl-requests-B4Vbcmaq.mjs → hitl-requests-DEFj8e6u.mjs} +2 -2
  257. package/dist/{hitl-route-helpers-hEVzvP8l.mjs → hitl-route-helpers-C23JHaWz.mjs} +5 -5
  258. package/dist/{import-Bh9biJfx.mjs → import-CXXL5pip.mjs} +7 -7
  259. package/dist/{index-D4y6NGiy.d.mts → index-DcnOCD1e.d.mts} +79 -3
  260. package/dist/index.d.mts +15 -17
  261. package/dist/index.mjs +81 -78
  262. package/dist/{jsonld-Dq0gsnOH.d.mts → jsonld-DzKbhRZ4.d.mts} +2 -2
  263. package/dist/{load-DmYeniXl.mjs → load-CFtJRT3c.mjs} +1 -1
  264. package/dist/{loader-CjWqjweO.mjs → loader-aWkkc1_o.mjs} +2 -2
  265. package/dist/{manifest-schema-BxVPYMJR.mjs → manifest-schema-uA6pRFXi.mjs} +6 -2
  266. package/dist/{mcp-reviewed-executor-TwVbMzG6.mjs → mcp-reviewed-executor-Dn52L_yY.mjs} +6 -3
  267. package/dist/media/image-endpoint.mjs +1 -1
  268. package/dist/media/index.d.mts +1 -1
  269. package/dist/media/index.mjs +2 -2
  270. package/dist/media/local-runtime.d.mts +10 -11
  271. package/dist/media/local-runtime.mjs +2 -2
  272. package/dist/{media-DMj0grzC.mjs → media-CVMOoywq.mjs} +1 -1
  273. package/dist/{media-allowlist-BlVCSzHx.mjs → media-allowlist-zDNJmXCo.mjs} +1 -1
  274. package/dist/{menus-xvsnVZXw.mjs → menus-CCG2z5um.mjs} +6 -6
  275. package/dist/{menus-TaW1gKnk.mjs → menus-CmyIkRG5.mjs} +2 -2
  276. package/dist/{oauth-authorization-DiaGvRVz.mjs → oauth-authorization-B9H7X85L.mjs} +5 -5
  277. package/dist/{oauth-clients-Dl9E8dEM.mjs → oauth-clients-Dwl32-Uj.mjs} +2 -2
  278. package/dist/object-cache/memory.d.mts +1 -1
  279. package/dist/output-DhBe5_Pi.mjs +68 -0
  280. package/dist/page/index.d.mts +9 -3
  281. package/dist/page/index.mjs +1 -1
  282. package/dist/{parse-CbymENaR.mjs → parse-i15EFSAE.mjs} +1 -1
  283. package/dist/plugin-utils.d.mts +8 -9
  284. package/dist/plugins/adapt-sandbox-entry.d.mts +8 -9
  285. package/dist/plugins/adapt-sandbox-entry.mjs +3 -1
  286. package/dist/{plugins-BolVa-tl.mjs → plugins-CPA2PtfY.mjs} +95 -10
  287. package/dist/portable-text-E79LyjGo.d.mts +45 -0
  288. package/dist/{preview-vSVg6fwG.mjs → preview-BjedZm8G.mjs} +2 -2
  289. package/dist/project-env-DKibmuP8.mjs +95 -0
  290. package/dist/{provider-loader-MD8zAbnH.d.mts → provider-loader-DC2JdWeO.d.mts} +1 -1
  291. package/dist/{public-url-gsp3oUbu.d.mts → public-url-DQJCnYi9.d.mts} +1 -1
  292. package/dist/publication-authorization-RKiHXKtq.mjs +985 -0
  293. package/dist/{query-jaAmw8E1.mjs → query-C2U5u5_p.mjs} +3 -3
  294. package/dist/{query-CfRCdaL3.mjs → query-DEv5x6yB.mjs} +13 -13
  295. package/dist/{rate-limit-ZLdyWoZF.mjs → rate-limit-DglsAJSw.mjs} +2 -2
  296. package/dist/{redirect-BAjt4Z6b.mjs → redirect-ubhEqQCQ.mjs} +2 -2
  297. package/dist/{redirects-CA-xylPG.mjs → redirects-Bhpm8bRe.mjs} +18 -10
  298. package/dist/{redirects-BTdwpQtE.mjs → redirects-xs2yahLq.mjs} +4 -4
  299. package/dist/{registry-CtyVedcN.mjs → registry-BYYyb2tF.mjs} +24 -10
  300. package/dist/{request-meta-CUypToDJ.mjs → request-meta-CFe1tW2M.mjs} +1 -1
  301. package/dist/review-payload-BysRWpxS.mjs +111 -0
  302. package/dist/{review-requests-DUyEmtmG.mjs → review-requests-CTWGnWUt.mjs} +1 -1
  303. package/dist/review-requests-D42VEP1l.mjs +142 -0
  304. package/dist/review-route-helpers-C31vO6SI.mjs +41 -0
  305. package/dist/{runner-DB7CRfOF.mjs → runner-BgmttQmD.mjs} +1151 -447
  306. package/dist/{runner-1tC2tIRV.d.mts → runner-D6hzs8L9.d.mts} +1 -1
  307. package/dist/runtime.d.mts +9 -10
  308. package/dist/runtime.mjs +3 -3
  309. package/dist/schema-DUtnZxjZ.mjs +8 -0
  310. package/dist/{search-DSaLgEFI.mjs → search-DUKgZUlm.mjs} +3 -3
  311. package/dist/{secrets-CDZo2k8L.mjs → secrets-ZV5rd8yV.mjs} +1 -1
  312. package/dist/{sections-PVVXHGfp.mjs → sections-DvFgsnda.mjs} +2 -2
  313. package/dist/seed/index.d.mts +2 -2
  314. package/dist/seed/index.mjs +19 -19
  315. package/dist/seo/index.d.mts +1 -1
  316. package/dist/seo/index.mjs +1 -1
  317. package/dist/{seo-CQG3GCHQ.mjs → seo-BU8MLCS9.mjs} +1 -1
  318. package/dist/{service-DiN4ZuPp.mjs → service-FL3fB0Rx.mjs} +2 -2
  319. package/dist/{settings-BbqgHWpU.mjs → settings-BECcAIRH.mjs} +5 -5
  320. package/dist/{settings-i4VPP8bT.mjs → settings-EzADu-dd.mjs} +2 -2
  321. package/dist/{site-activity-Dy3FROs0.mjs → site-activity-h8smOlYI.mjs} +1 -1
  322. package/dist/{site-context-DQiL8Fl5.mjs → site-context-B8T1kpUP.mjs} +565 -129
  323. package/dist/stable-hash-DshcXvRE.mjs +19 -0
  324. package/dist/storage/local.d.mts +1 -1
  325. package/dist/storage/local.mjs +1 -1
  326. package/dist/storage/s3.d.mts +1 -1
  327. package/dist/storage/s3.mjs +1 -1
  328. package/dist/{taxonomies-9s-v03H-.mjs → taxonomies-BiM9NtgW.mjs} +3 -3
  329. package/dist/{taxonomies-DRiixp_E.mjs → taxonomies-DSnY5nOa.mjs} +6 -6
  330. package/dist/{taxonomy-Dvsw6BOs.mjs → taxonomy-0k_vRVsD.mjs} +2 -2
  331. package/dist/{types-4garmdWa.mjs → types-A8fPOJnl.mjs} +5 -2
  332. package/dist/{types-DW_-sFyz.d.mts → types-B_FlxIIl.d.mts} +2 -0
  333. package/dist/{types-Dq1qT19x.mjs → types-ChxYDRvx.mjs} +1 -1
  334. package/dist/{types-DU0bU2Wu.d.mts → types-DuQn1G7-.d.mts} +583 -2
  335. package/dist/{runtime-BOeiQsCv.d.mts → types-DwoUifGE.d.mts} +3560 -1355
  336. package/dist/{types-C_ly5eTp.d.mts → types-opjX_kz6.d.mts} +1 -1
  337. package/dist/ui/server-runtime.d.mts +12 -14
  338. package/dist/ui/server-runtime.mjs +21 -21
  339. package/dist/{user-BIZPzCb9.mjs → user-BH-n01y3.mjs} +2 -2
  340. package/dist/{utils-CMDhr5Xd.mjs → utils-D1SrKGtP.mjs} +1 -1
  341. package/dist/{validate-CZvb-BKB.d.mts → validate-CbVFoJgc.d.mts} +59 -5
  342. package/dist/{validate-DNs0pTSc.mjs → validate-D1HL-oLR.mjs} +2 -2
  343. package/dist/version-C3iVRuaF.mjs +6 -0
  344. package/dist/{widgets-f0ibZUIq.mjs → widgets-BZrLrNgS.mjs} +3 -3
  345. package/dist/{wordpress-slugs-BhHJX8XE.mjs → wordpress-slugs-C3PWcowq.mjs} +1 -1
  346. package/dist/{zod-generator-B7TMjyFJ.mjs → zod-generator-C7AsLpSB.mjs} +2 -2
  347. package/package.json +13 -5
  348. package/dist/hitl-Hw1RmWOq.mjs +0 -677
  349. package/dist/review-requests-C9Ff11Vq.mjs +0 -79
  350. package/dist/schema-DXdYj4R3.mjs +0 -8
  351. package/dist/types-C46EvNdc.d.mts +0 -56
  352. package/dist/types-C8XW6L19.d.mts +0 -1468
  353. package/dist/version-BTvfRGc6.mjs +0 -6
  354. /package/dist/{adapters-NVSs4UH7.d.mts → adapters-BiRymx02.d.mts} +0 -0
  355. /package/dist/{api-tokens-2r7OWi_I.mjs → api-tokens-Ypaly90d.mjs} +0 -0
  356. /package/dist/{challenge-store-Bjlepa2E.mjs → challenge-store-D5pSY2S1.mjs} +0 -0
  357. /package/dist/{components-Bclf98Be.mjs → components-DImzlLhb.mjs} +0 -0
  358. /package/dist/{context-types-DqTo6C79.mjs → context-types-eBuMDAg-.mjs} +0 -0
  359. /package/dist/{cron-cKcNTix_.mjs → cron-B1SL_lsb.mjs} +0 -0
  360. /package/dist/{default--K40jqm0.mjs → default-D4Vygcy_.mjs} +0 -0
  361. /package/dist/{email-console-ChgKFO8-.mjs → email-console-Bp0r68iF.mjs} +0 -0
  362. /package/dist/{error-CytFlgcd.mjs → error-CSVaQNZy.mjs} +0 -0
  363. /package/dist/{escape-Bd4P_xKg.mjs → escape-DN4Qmjsl.mjs} +0 -0
  364. /package/dist/{hash-BPmX6P8I.mjs → hash-mxxx2oPW.mjs} +0 -0
  365. /package/dist/{media-url-lEKSrpr9.mjs → media-url-BdoLPvg8.mjs} +0 -0
  366. /package/dist/{mime-CA7Lgovc.mjs → mime-C0vOHFm7.mjs} +0 -0
  367. /package/dist/{mode-C4CIyjtR.mjs → mode-C8yZnIlR.mjs} +0 -0
  368. /package/dist/{normalize-5ek_z7de.mjs → normalize-Cyt7JdF7.mjs} +0 -0
  369. /package/dist/{oauth-state-store-CNoXafF7.mjs → oauth-state-store-CndT35iw.mjs} +0 -0
  370. /package/dist/{oauth-user-lookup-Ygw4bNyt.mjs → oauth-user-lookup-CMehAaKs.mjs} +0 -0
  371. /package/dist/{parser-C1nYd-81.mjs → parser-06LLLL4E.mjs} +0 -0
  372. /package/dist/{passkey-config-BUwu8BA3.mjs → passkey-config-NYukYGed.mjs} +0 -0
  373. /package/dist/{patterns-BhAvqO0S.mjs → patterns-CoqlXUvk.mjs} +0 -0
  374. /package/dist/{placeholder-uvNRZBX9.d.mts → placeholder-DkWkXfDI.d.mts} +0 -0
  375. /package/dist/{portable-text-dA_UlJwW.mjs → portable-text-BASHceim.mjs} +0 -0
  376. /package/dist/{process-cache-7xgAO9JY.mjs → process-cache-CCDgti7j.mjs} +0 -0
  377. /package/dist/{provider-loader-D0w9dqjm.mjs → provider-loader-BtfrrzfD.mjs} +0 -0
  378. /package/dist/{public-url-BEz_sM9n.mjs → public-url-Cp6hyjVR.mjs} +0 -0
  379. /package/dist/{redirect-wphRBv4y.mjs → redirect-DrbEmU9a.mjs} +0 -0
  380. /package/dist/{request-cache-D9GQBxMP.mjs → request-cache-CBFjCwSt.mjs} +0 -0
  381. /package/dist/{resolve-Cb6Dbz-C.mjs → resolve-DE71WcL9.mjs} +0 -0
  382. /package/dist/{seo-qa7Dn0jK.mjs → seo-BLszyJxd.mjs} +0 -0
  383. /package/dist/{seo-contributions-C1EnikHB.mjs → seo-contributions-GnCuL1ML.mjs} +0 -0
  384. /package/dist/{session-user-CAKImna3.mjs → session-user-Ct6GBLvn.mjs} +0 -0
  385. /package/dist/{setup-complete-B8fl-mjV.mjs → setup-complete-Da0axZEE.mjs} +0 -0
  386. /package/dist/{setup-nonce-CoyjILvW.mjs → setup-nonce-BtkKnvxQ.mjs} +0 -0
  387. /package/dist/{sidecar-client-C3mqXg4C.mjs → sidecar-client-Ctzfyyp-.mjs} +0 -0
  388. /package/dist/{site-url-BML3GQYm.mjs → site-url-DJEid0ml.mjs} +0 -0
  389. /package/dist/{ssrf-DWe8jwAp.mjs → ssrf-FJqwQzj4.mjs} +0 -0
  390. /package/dist/{status-DANd8ERo.mjs → status-NqWOSFAD.mjs} +0 -0
  391. /package/dist/{tokens-1RK1n6ED.mjs → tokens-BDQU29Vd.mjs} +0 -0
  392. /package/dist/{transaction-C2EOMTJA.mjs → transaction-0LEAAy8R.mjs} +0 -0
  393. /package/dist/{transport-BNmCqLu7.mjs → transport-C46KHLMP.mjs} +0 -0
  394. /package/dist/{transport-CcJu3Co8.d.mts → transport-D9pKAzFP.d.mts} +0 -0
  395. /package/dist/{trusted-proxy-DTXQ2IMv.mjs → trusted-proxy-Dm7Mxvt6.mjs} +0 -0
  396. /package/dist/{types-B3t5cxhU.mjs → types-B7TDDFMG.mjs} +0 -0
  397. /package/dist/{types-DF7ZuGGk.d.mts → types-BLQCz46p.d.mts} +0 -0
  398. /package/dist/{types-CDpH6MA4.d.mts → types-Cw0PeCT_.d.mts} +0 -0
  399. /package/dist/{types-Rc3gQqqw.d.mts → types-g0zMtraY.d.mts} +0 -0
  400. /package/dist/{types-C5CVgwsV.mjs → types-mVVgRPaU.mjs} +0 -0
  401. /package/dist/{types-POH8PQZh.d.mts → types-wFu80FrO.d.mts} +0 -0
  402. /package/dist/{url-CpyFDFpO.mjs → url-EMAguGVk.mjs} +0 -0
  403. /package/dist/{url-Cac7a9QZ.mjs → url-guoXQQcV.mjs} +0 -0
@@ -0,0 +1,985 @@
1
+ import { i as encodeCursor, r as decodeCursor } from "./types-ChxYDRvx.mjs";
2
+ import { t as SiteActivityRepository } from "./site-activity-h8smOlYI.mjs";
3
+ import { t as ReviewRequestRepository } from "./review-requests-CTWGnWUt.mjs";
4
+ import { a as getSiteSettingsWithDb } from "./settings-BECcAIRH.mjs";
5
+ import { n as buildStableActionHash, t as ReviewPayloadBuilder } from "./review-payload-BysRWpxS.mjs";
6
+ import { t as SYSTEM_ACTOR_ID } from "./actor-0QJ1Gbtf.mjs";
7
+ import { n as redactActivityRecord } from "./activity-DUaz_w7p.mjs";
8
+ import { ulid } from "ulidx";
9
+
10
+ //#region src/database/repositories/content-release-grants.ts
11
+ var ContentReleaseGrantRepository = class {
12
+ constructor(db) {
13
+ this.db = db;
14
+ }
15
+ async createOrReplaceActive(input) {
16
+ return this.db.transaction().execute(async (transaction) => {
17
+ const existing = await findActiveForTarget(transaction, input.collection, input.entryId, input.operation);
18
+ if (existing?.actionHash === input.actionHash) return existing;
19
+ const now = input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
20
+ if (existing) {
21
+ const revoked = await transaction.updateTable("_dineway_content_release_grants").set({
22
+ status: "revoked",
23
+ updated_at: now,
24
+ revoked_at: now,
25
+ revocation_reason: "replaced"
26
+ }).where("id", "=", existing.id).where("status", "=", "active").executeTakeFirst();
27
+ if (Number(revoked.numUpdatedRows ?? 0) !== 1) throw new Error("Active content release grant changed during replacement");
28
+ }
29
+ const id = ulid();
30
+ await transaction.insertInto("_dineway_content_release_grants").values(toInsertableGrant(id, input, now)).execute();
31
+ const created = await findById(transaction, id);
32
+ if (!created) throw new Error("Failed to create content release grant");
33
+ return created;
34
+ });
35
+ }
36
+ async findById(id) {
37
+ return findById(this.db, id);
38
+ }
39
+ async findActiveForTarget(collection, entryId, operation) {
40
+ return findActiveForTarget(this.db, collection, entryId, operation);
41
+ }
42
+ async list(query = {}) {
43
+ const limit = clampLimit$1(query.limit);
44
+ let statement = this.db.selectFrom("_dineway_content_release_grants").selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
45
+ if (query.status) statement = statement.where("status", "=", query.status);
46
+ if (query.collection) statement = statement.where("collection", "=", query.collection);
47
+ if (query.entryId) statement = statement.where("entry_id", "=", query.entryId);
48
+ if (query.operation) statement = statement.where("operation", "=", query.operation);
49
+ if (query.cursor) {
50
+ const cursor = decodeCursor(query.cursor);
51
+ if (cursor) statement = statement.where((eb) => eb.or([eb("created_at", "<", cursor.orderValue), eb.and([eb("created_at", "=", cursor.orderValue), eb("id", "<", cursor.id)])]));
52
+ }
53
+ const rows = await statement.execute();
54
+ const items = rows.slice(0, limit).map(rowToGrant);
55
+ const result = { items };
56
+ if (rows.length > limit && items.length > 0) {
57
+ const last = items.at(-1);
58
+ result.nextCursor = encodeCursor(last.createdAt, last.id);
59
+ }
60
+ return result;
61
+ }
62
+ async findDueScheduled(now, limit = 50) {
63
+ return (await this.db.selectFrom("_dineway_content_release_grants").selectAll().where("status", "=", "active").where("operation", "=", "schedule").where("scheduled_at", "<=", now).where((eb) => eb.or([eb("expires_at", "is", null), eb("expires_at", ">", now)])).orderBy("scheduled_at", "asc").orderBy("id", "asc").limit(clampLimit$1(limit)).execute()).map(rowToGrant);
64
+ }
65
+ async consume(id, transitionedAt = (/* @__PURE__ */ new Date()).toISOString()) {
66
+ return this.transition(id, "consumed", transitionedAt);
67
+ }
68
+ async revoke(id, reason, transitionedAt = (/* @__PURE__ */ new Date()).toISOString()) {
69
+ return this.transition(id, "revoked", transitionedAt, reason);
70
+ }
71
+ async expire(id, transitionedAt = (/* @__PURE__ */ new Date()).toISOString()) {
72
+ return this.transition(id, "expired", transitionedAt);
73
+ }
74
+ async transition(id, status, transitionedAt, revocationReason) {
75
+ const result = await this.db.updateTable("_dineway_content_release_grants").set({
76
+ status,
77
+ updated_at: transitionedAt,
78
+ consumed_at: status === "consumed" ? transitionedAt : null,
79
+ revoked_at: status === "revoked" ? transitionedAt : null,
80
+ revocation_reason: status === "revoked" ? revocationReason ?? "revoked" : null
81
+ }).where("id", "=", id).where("status", "=", "active").executeTakeFirst();
82
+ if (Number(result.numUpdatedRows ?? 0) === 1) return this.findById(id);
83
+ const existing = await this.findById(id);
84
+ return existing?.status === status ? existing : null;
85
+ }
86
+ };
87
+ async function findById(db, id) {
88
+ const row = await db.selectFrom("_dineway_content_release_grants").selectAll().where("id", "=", id).executeTakeFirst();
89
+ return row ? rowToGrant(row) : null;
90
+ }
91
+ async function findActiveForTarget(db, collection, entryId, operation) {
92
+ const row = await db.selectFrom("_dineway_content_release_grants").selectAll().where("collection", "=", collection).where("entry_id", "=", entryId).where("operation", "=", operation).where("status", "=", "active").executeTakeFirst();
93
+ return row ? rowToGrant(row) : null;
94
+ }
95
+ function toInsertableGrant(id, input, now) {
96
+ return {
97
+ id,
98
+ status: "active",
99
+ collection: input.collection,
100
+ entry_id: input.entryId,
101
+ scope: input.scope ?? `content:${input.collection}:${input.entryId}`,
102
+ live_revision_id: input.liveRevisionId,
103
+ draft_revision_id: input.draftRevisionId,
104
+ reviewed_rev: input.reviewedRev,
105
+ editorial_review_request_id: input.editorialReviewRequestId,
106
+ release_hitl_request_id: input.releaseHitlRequestId,
107
+ operation: input.operation,
108
+ scheduled_at: input.scheduledAt,
109
+ published_at: input.publishedAt,
110
+ site_timezone: input.siteTimezone,
111
+ action_hash: input.actionHash,
112
+ policy_contributions: JSON.stringify(input.policyContributions),
113
+ authorization_method: input.authorizationMethod,
114
+ authorized_by_actor_type: input.authorizedByActorType,
115
+ authorized_by_actor_id: input.authorizedByActorId,
116
+ authorized_auth_metadata: jsonOrNull(input.authorizedAuthMetadata),
117
+ expires_at: input.expiresAt ?? null,
118
+ created_at: now,
119
+ updated_at: now,
120
+ consumed_at: null,
121
+ revoked_at: null,
122
+ revocation_reason: null
123
+ };
124
+ }
125
+ function rowToGrant(row) {
126
+ return {
127
+ id: row.id,
128
+ status: row.status,
129
+ collection: row.collection,
130
+ entryId: row.entry_id,
131
+ scope: row.scope,
132
+ liveRevisionId: row.live_revision_id,
133
+ draftRevisionId: row.draft_revision_id,
134
+ reviewedRev: row.reviewed_rev,
135
+ editorialReviewRequestId: row.editorial_review_request_id,
136
+ releaseHitlRequestId: row.release_hitl_request_id,
137
+ operation: row.operation,
138
+ scheduledAt: row.scheduled_at,
139
+ publishedAt: row.published_at,
140
+ siteTimezone: row.site_timezone,
141
+ actionHash: row.action_hash,
142
+ policyContributions: parsePolicyContributions(row.policy_contributions),
143
+ authorizationMethod: row.authorization_method,
144
+ authorizedByActorType: row.authorized_by_actor_type,
145
+ authorizedByActorId: row.authorized_by_actor_id,
146
+ authorizedAuthMetadata: parseNullableRecord$1(row.authorized_auth_metadata),
147
+ expiresAt: row.expires_at,
148
+ createdAt: row.created_at,
149
+ updatedAt: row.updated_at,
150
+ consumedAt: row.consumed_at,
151
+ revokedAt: row.revoked_at,
152
+ revocationReason: row.revocation_reason
153
+ };
154
+ }
155
+ function parsePolicyContributions(value) {
156
+ try {
157
+ const parsed = JSON.parse(value);
158
+ if (!Array.isArray(parsed)) return [];
159
+ return parsed.filter(isPolicyContribution);
160
+ } catch {
161
+ return [];
162
+ }
163
+ }
164
+ function isPolicyContribution(value) {
165
+ if (!isRecord$2(value)) return false;
166
+ return typeof value.providerId === "string" && typeof value.policyVersion === "string" && typeof value.fingerprint === "string" && (value.reservationId === null || typeof value.reservationId === "string");
167
+ }
168
+ function parseNullableRecord$1(value) {
169
+ if (!value) return null;
170
+ try {
171
+ const parsed = JSON.parse(value);
172
+ return isRecord$2(parsed) ? parsed : null;
173
+ } catch {
174
+ return null;
175
+ }
176
+ }
177
+ function jsonOrNull(value) {
178
+ return value ? JSON.stringify(value) : null;
179
+ }
180
+ function isRecord$2(value) {
181
+ return typeof value === "object" && value !== null && !Array.isArray(value);
182
+ }
183
+ function clampLimit$1(limit) {
184
+ if (!Number.isFinite(limit)) return 50;
185
+ return Math.max(1, Math.min(100, Math.floor(limit ?? 50)));
186
+ }
187
+
188
+ //#endregion
189
+ //#region src/database/repositories/hitl-requests.ts
190
+ const HITL_REQUEST_STATUSES = [
191
+ "pending",
192
+ "approved",
193
+ "rejected"
194
+ ];
195
+ const HITL_REQUEST_PRIORITIES = [
196
+ "low",
197
+ "normal",
198
+ "high",
199
+ "urgent"
200
+ ];
201
+ var HitlRequestRepository = class {
202
+ constructor(db) {
203
+ this.db = db;
204
+ }
205
+ async create(input) {
206
+ const id = ulid();
207
+ const now = input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
208
+ await this.db.insertInto("_dineway_hitl_requests").values(toInsertableHitlRequest(id, input, now)).execute();
209
+ const request = await this.findById(id);
210
+ if (!request) throw new Error("Failed to create HITL request");
211
+ return request;
212
+ }
213
+ async findById(id) {
214
+ const row = await this.db.selectFrom("_dineway_hitl_requests").selectAll().where("id", "=", id).executeTakeFirst();
215
+ return row ? rowToHitlRequest(row) : null;
216
+ }
217
+ async list(query = {}) {
218
+ const limit = clampLimit(query.limit);
219
+ const rows = await this.queryRows(query).execute();
220
+ const items = rows.slice(0, limit).map(rowToHitlRequest);
221
+ const result = { items };
222
+ if (rows.length > limit && items.length > 0) {
223
+ const last = items.at(-1);
224
+ result.nextCursor = encodeCursor(last.createdAt, last.id);
225
+ }
226
+ return result;
227
+ }
228
+ async resolve(id, input) {
229
+ const resolvedAt = input.resolvedAt ?? (/* @__PURE__ */ new Date()).toISOString();
230
+ const result = await this.db.updateTable("_dineway_hitl_requests").set({
231
+ status: input.decision,
232
+ resolved_by_actor_type: input.resolvedByActorType,
233
+ resolved_by_actor_id: input.resolvedByActorId,
234
+ resolved_auth_metadata: jsonStringOrNull(input.resolvedAuthMetadata),
235
+ review_note: input.reviewNote ?? null,
236
+ resolved_at: resolvedAt,
237
+ updated_at: resolvedAt
238
+ }).where("id", "=", id).where("status", "=", "pending").executeTakeFirst();
239
+ if (Number(result.numUpdatedRows ?? 0) === 0) return null;
240
+ return this.findById(id);
241
+ }
242
+ queryRows(query) {
243
+ const limit = clampLimit(query.limit);
244
+ let q = this.db.selectFrom("_dineway_hitl_requests").selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
245
+ if (query.scope) q = q.where("scope", "=", query.scope);
246
+ if (query.scopes && query.scopes.length > 0) q = q.where("scope", "in", query.scopes);
247
+ if (query.statuses && query.statuses.length > 0) q = q.where("status", "in", query.statuses);
248
+ if (query.priority) q = q.where("priority", "=", query.priority);
249
+ if (query.actionType) q = q.where("action_type", "=", query.actionType);
250
+ if (query.targetRefType) q = q.where("target_ref_type", "=", query.targetRefType);
251
+ if (query.targetRefId) q = q.where("target_ref_id", "=", query.targetRefId);
252
+ if (query.relatedAssignmentId) q = q.where("related_assignment_id", "=", query.relatedAssignmentId);
253
+ if (query.requestedByActorType && query.requestedByActorId) q = q.where("requested_by_actor_type", "=", query.requestedByActorType).where("requested_by_actor_id", "=", query.requestedByActorId);
254
+ if (query.participantActor) q = q.where("requested_by_actor_type", "=", query.participantActor.actorType).where("requested_by_actor_id", "=", query.participantActor.actorId);
255
+ if (query.since) q = q.where("updated_at", ">=", query.since);
256
+ if (query.cursor) {
257
+ const decoded = decodeCursor(query.cursor);
258
+ if (decoded) q = q.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
259
+ }
260
+ return q;
261
+ }
262
+ };
263
+ function toInsertableHitlRequest(id, input, now) {
264
+ return {
265
+ id,
266
+ scope: input.scope,
267
+ action_type: input.actionType,
268
+ status: "pending",
269
+ priority: input.priority ?? "normal",
270
+ title: input.title,
271
+ summary: input.summary ?? null,
272
+ risk_reason: input.riskReason,
273
+ review_payload: JSON.stringify(input.reviewPayload),
274
+ target_ref_type: input.targetRefType,
275
+ target_ref_id: input.targetRefId,
276
+ requested_by_actor_type: input.requestedByActorType,
277
+ requested_by_actor_id: input.requestedByActorId,
278
+ requested_auth_metadata: jsonStringOrNull(input.requestedAuthMetadata),
279
+ resolved_by_actor_type: null,
280
+ resolved_by_actor_id: null,
281
+ resolved_auth_metadata: null,
282
+ review_note: null,
283
+ metadata: jsonString(input.metadata),
284
+ related_assignment_id: input.relatedAssignmentId ?? null,
285
+ related_handoff_snapshot_id: input.relatedHandoffSnapshotId ?? null,
286
+ sla_due_at: input.slaDueAt ?? null,
287
+ created_at: now,
288
+ updated_at: now,
289
+ resolved_at: null
290
+ };
291
+ }
292
+ function rowToHitlRequest(row) {
293
+ return {
294
+ id: row.id,
295
+ scope: row.scope,
296
+ actionType: row.action_type,
297
+ status: row.status,
298
+ priority: row.priority,
299
+ title: row.title,
300
+ summary: row.summary,
301
+ riskReason: row.risk_reason,
302
+ reviewPayload: parseRecord(row.review_payload),
303
+ targetRefType: row.target_ref_type,
304
+ targetRefId: row.target_ref_id,
305
+ requestedByActorType: row.requested_by_actor_type,
306
+ requestedByActorId: row.requested_by_actor_id,
307
+ requestedAuthMetadata: parseNullableRecord(row.requested_auth_metadata),
308
+ resolvedByActorType: row.resolved_by_actor_type,
309
+ resolvedByActorId: row.resolved_by_actor_id,
310
+ resolvedAuthMetadata: parseNullableRecord(row.resolved_auth_metadata),
311
+ reviewNote: row.review_note,
312
+ metadata: parseRecord(row.metadata),
313
+ relatedAssignmentId: row.related_assignment_id,
314
+ relatedHandoffSnapshotId: row.related_handoff_snapshot_id,
315
+ slaDueAt: row.sla_due_at,
316
+ createdAt: row.created_at,
317
+ updatedAt: row.updated_at,
318
+ resolvedAt: row.resolved_at
319
+ };
320
+ }
321
+ function jsonString(value) {
322
+ return JSON.stringify(value ?? {});
323
+ }
324
+ function jsonStringOrNull(value) {
325
+ return value ? JSON.stringify(value) : null;
326
+ }
327
+ function parseRecord(value) {
328
+ if (!value) return {};
329
+ try {
330
+ const parsed = JSON.parse(value);
331
+ return isRecord$1(parsed) ? parsed : {};
332
+ } catch {
333
+ return {};
334
+ }
335
+ }
336
+ function parseNullableRecord(value) {
337
+ if (!value) return null;
338
+ return parseRecord(value);
339
+ }
340
+ function isRecord$1(value) {
341
+ return typeof value === "object" && value !== null && !Array.isArray(value);
342
+ }
343
+ function clampLimit(limit) {
344
+ if (!limit || limit < 1) return 50;
345
+ return Math.min(limit, 100);
346
+ }
347
+
348
+ //#endregion
349
+ //#region src/site-context/release-payload.ts
350
+ async function buildContentReleaseActionHash(input) {
351
+ return buildStableActionHash({
352
+ actionType: input.actionType,
353
+ collection: input.collection,
354
+ entryId: input.entryId,
355
+ liveRevisionId: input.liveRevisionId,
356
+ draftRevisionId: input.draftRevisionId,
357
+ reviewedRev: input.reviewedRev,
358
+ editorialReviewRequestId: input.editorialReviewRequestId,
359
+ editorialActionHash: input.editorialActionHash,
360
+ operation: input.operation,
361
+ publishedAt: normalizeOptionalTimestamp(input.publishedAt),
362
+ scheduledAt: normalizeOptionalTimestamp(input.scheduledAt),
363
+ siteTimezone: input.siteTimezone,
364
+ policyContributions: normalizePolicyContributions(input.policyContributions)
365
+ });
366
+ }
367
+ var ReleasePayloadBuilder = class {
368
+ reviewPayloadBuilder;
369
+ constructor(options) {
370
+ this.options = options;
371
+ this.reviewPayloadBuilder = new ReviewPayloadBuilder(options.handlers);
372
+ }
373
+ async buildContentReleasePayload(input) {
374
+ assertReleaseInput(input);
375
+ const editorial = await this.reviewPayloadBuilder.buildContentReviewPayload({
376
+ collection: input.collection,
377
+ id: input.id
378
+ });
379
+ const review = await this.loadApprovedReview(input.editorialReviewRequestId);
380
+ if (!reviewMatchesEditorialTarget(review, editorial)) throw new Error("Editorial review does not match the current draft");
381
+ const actionType = input.operation === "publish" ? "content.release.publish" : "content.release.schedule";
382
+ const publishedAt = normalizeOptionalTimestamp(input.publishedAt);
383
+ const scheduledAt = normalizeOptionalTimestamp(input.scheduledAt);
384
+ const policyContributions = normalizePolicyContributions(input.policyContributions ?? []);
385
+ const actionFingerprint = {
386
+ actionType,
387
+ collection: editorial.collection,
388
+ entryId: editorial.entryId,
389
+ liveRevisionId: editorial.liveRevisionId,
390
+ draftRevisionId: editorial.draftRevisionId,
391
+ reviewedRev: editorial.reviewedRev,
392
+ editorialReviewRequestId: review.id,
393
+ editorialActionHash: editorial.actionHash,
394
+ operation: input.operation,
395
+ publishedAt,
396
+ scheduledAt,
397
+ siteTimezone: input.siteTimezone,
398
+ policyContributions
399
+ };
400
+ const actionHash = await buildContentReleaseActionHash(actionFingerprint);
401
+ return {
402
+ collection: editorial.collection,
403
+ entryId: editorial.entryId,
404
+ scope: editorial.scope,
405
+ liveRevisionId: editorial.liveRevisionId,
406
+ draftRevisionId: editorial.draftRevisionId,
407
+ reviewedRev: editorial.reviewedRev,
408
+ actionType,
409
+ operation: input.operation,
410
+ editorialReviewRequestId: review.id,
411
+ editorialActionHash: editorial.actionHash,
412
+ publishedAt,
413
+ scheduledAt,
414
+ siteTimezone: input.siteTimezone,
415
+ policyContributions,
416
+ actionHash,
417
+ releasePayload: {
418
+ kind: "content_release",
419
+ actionType,
420
+ target: {
421
+ ...actionFingerprint,
422
+ scope: editorial.scope,
423
+ actionHash
424
+ },
425
+ editorialReview: {
426
+ requestId: review.id,
427
+ resolvedByActorType: review.resolvedByActorType,
428
+ resolvedByActorId: review.resolvedByActorId,
429
+ resolvedAt: review.resolvedAt
430
+ }
431
+ }
432
+ };
433
+ }
434
+ async loadApprovedReview(id) {
435
+ const review = await this.options.reviewRequests.findById(id);
436
+ if (!review) throw new Error("Editorial review request not found");
437
+ if (review.status !== "approved") throw new Error("Editorial review is not approved");
438
+ return review;
439
+ }
440
+ };
441
+ function assertReleaseInput(input) {
442
+ if (input.siteTimezone.trim().length === 0) throw new Error("Site timezone is required");
443
+ if (input.operation === "schedule" && !normalizeOptionalTimestamp(input.scheduledAt)) throw new Error("Scheduled time is required for a schedule release");
444
+ if (input.operation === "publish" && normalizeOptionalTimestamp(input.scheduledAt)) throw new Error("Scheduled time is only valid for a schedule release");
445
+ if (input.operation === "schedule" && normalizeOptionalTimestamp(input.publishedAt)) throw new Error("Published time is only valid for an immediate publish release");
446
+ }
447
+ function reviewMatchesEditorialTarget(review, editorial) {
448
+ return review.collection === editorial.collection && review.entryId === editorial.entryId && review.scope === editorial.scope && review.liveRevisionId === editorial.liveRevisionId && review.draftRevisionId === editorial.draftRevisionId && review.reviewedRev === editorial.reviewedRev && review.actionType === editorial.actionType && review.actionHash === editorial.actionHash;
449
+ }
450
+ function normalizePolicyContributions(contributions) {
451
+ const normalized = contributions.map((contribution) => {
452
+ assertNonEmpty("Policy provider ID", contribution.providerId);
453
+ assertNonEmpty("Policy version", contribution.policyVersion);
454
+ assertNonEmpty("Policy fingerprint", contribution.fingerprint);
455
+ return {
456
+ providerId: contribution.providerId,
457
+ policyVersion: contribution.policyVersion,
458
+ fingerprint: contribution.fingerprint,
459
+ reservationId: normalizeOptionalString(contribution.reservationId)
460
+ };
461
+ });
462
+ const providerIds = /* @__PURE__ */ new Set();
463
+ for (const contribution of normalized) {
464
+ if (providerIds.has(contribution.providerId)) throw new Error(`Duplicate publication release policy provider: ${contribution.providerId}`);
465
+ providerIds.add(contribution.providerId);
466
+ }
467
+ return normalized.toSorted((left, right) => left.providerId.localeCompare(right.providerId));
468
+ }
469
+ function normalizeOptionalTimestamp(value) {
470
+ return normalizeOptionalString(value);
471
+ }
472
+ function normalizeOptionalString(value) {
473
+ return value && value.length > 0 ? value : null;
474
+ }
475
+ function assertNonEmpty(label, value) {
476
+ if (value.length === 0) throw new Error(`${label} is required`);
477
+ }
478
+
479
+ //#endregion
480
+ //#region src/site-context/publication-authorization.ts
481
+ var PublicationAuthorizationError = class extends Error {
482
+ constructor(code, message) {
483
+ super(message);
484
+ this.code = code;
485
+ this.name = "PublicationAuthorizationError";
486
+ }
487
+ };
488
+ var PublicationAuthorizationService = class {
489
+ reviewRequests;
490
+ releaseGrants;
491
+ hitlRequests;
492
+ activity;
493
+ releasePayloadBuilder;
494
+ policies;
495
+ getSiteTimezone;
496
+ now;
497
+ constructor(options) {
498
+ this.options = options;
499
+ this.reviewRequests = new ReviewRequestRepository(options.db);
500
+ this.releaseGrants = new ContentReleaseGrantRepository(options.db);
501
+ this.hitlRequests = new HitlRequestRepository(options.db);
502
+ this.activity = new SiteActivityRepository(options.db);
503
+ this.releasePayloadBuilder = new ReleasePayloadBuilder({
504
+ handlers: options.handlers,
505
+ reviewRequests: this.reviewRequests
506
+ });
507
+ this.policies = [...options.policies ?? []].toSorted((left, right) => left.id.localeCompare(right.id));
508
+ this.assertUniquePolicyIds();
509
+ this.getSiteTimezone = options.getSiteTimezone ?? (async () => {
510
+ return (await getSiteSettingsWithDb(options.db)).timezone?.trim() || "UTC";
511
+ });
512
+ this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
513
+ }
514
+ async publishAuthorizedContent(input) {
515
+ const siteTimezone = await this.getSiteTimezone();
516
+ const authorized = await this.authorize({
517
+ ...input,
518
+ operation: "publish",
519
+ siteTimezone
520
+ });
521
+ const result = await this.options.handlers.handleContentPublish(input.collection, input.id, { publishedAt: input.publishedAt });
522
+ if (!result.success) await this.failAuthorizedRelease(authorized, "content_publish_failed", result.error?.code);
523
+ const consumed = await this.releaseGrants.consume(authorized.grant.id, this.now());
524
+ if (!consumed) {
525
+ await this.releasePolicies(authorized.preparedPolicies, "release_grant_transition_failed");
526
+ throw new PublicationAuthorizationError("RELEASE_GRANT_TRANSITION_FAILED", "Content published but its release grant could not be consumed");
527
+ }
528
+ await this.consumePolicies(authorized.preparedPolicies);
529
+ await this.logSuccess(input, authorized.release, consumed);
530
+ return {
531
+ grant: consumed,
532
+ result
533
+ };
534
+ }
535
+ async scheduleAuthorizedContent(input) {
536
+ const siteTimezone = await this.getSiteTimezone();
537
+ const authorized = await this.authorize({
538
+ ...input,
539
+ operation: "schedule",
540
+ siteTimezone
541
+ });
542
+ const result = await this.options.handlers.handleContentSchedule(input.collection, input.id, input.scheduledAt);
543
+ if (!result.success) await this.failAuthorizedRelease(authorized, "content_schedule_failed", result.error?.code);
544
+ await this.logSuccess(input, authorized.release, authorized.grant);
545
+ return {
546
+ grant: authorized.grant,
547
+ result
548
+ };
549
+ }
550
+ async publishAuthorizedDueContent(input) {
551
+ const grant = await this.releaseGrants.findActiveForTarget(input.collection, input.id, "schedule");
552
+ if (!grant) {
553
+ await this.blockScheduledRelease(input, null, "schedule_grant_required");
554
+ throw new PublicationAuthorizationError("SCHEDULE_GRANT_REQUIRED", "Due content has no active Schedule grant");
555
+ }
556
+ const preparedPolicies = this.restorePreparedPolicies(grant.policyContributions);
557
+ let release;
558
+ try {
559
+ release = await this.revalidateScheduledGrant(input, grant, preparedPolicies);
560
+ } catch (error) {
561
+ const reason = errorReason(error);
562
+ await this.releasePolicies(preparedPolicies, reason);
563
+ if (error instanceof PublicationAuthorizationError && error.code === "SCHEDULE_GRANT_EXPIRED") await this.releaseGrants.expire(grant.id, this.now());
564
+ else await this.releaseGrants.revoke(grant.id, reason, this.now());
565
+ await this.blockScheduledRelease(input, grant, reason);
566
+ throw error;
567
+ }
568
+ const result = await this.options.handlers.handleContentPublish(input.collection, input.id, {
569
+ publishedAt: input.publishedAt,
570
+ requireScheduledDue: true
571
+ });
572
+ if (!result.success) throw new PublicationAuthorizationError(result.error?.code ?? "RELEASE_GRANT_FAILED", "Authorized scheduled publication failed and remains eligible for retry");
573
+ const consumed = await this.releaseGrants.consume(grant.id, this.now());
574
+ if (!consumed) throw new PublicationAuthorizationError("RELEASE_GRANT_TRANSITION_FAILED", "Scheduled content published but its release grant could not be consumed");
575
+ await this.consumePolicies(preparedPolicies);
576
+ await this.logScheduledPublish(release, consumed);
577
+ return {
578
+ grant: consumed,
579
+ result
580
+ };
581
+ }
582
+ async unscheduleAuthorizedContent(input) {
583
+ const activeGrant = await this.releaseGrants.findActiveForTarget(input.collection, input.id, "schedule");
584
+ let revokedGrant = null;
585
+ if (activeGrant) {
586
+ await this.releasePolicies(this.restorePreparedPolicies(activeGrant.policyContributions), "content_unscheduled");
587
+ revokedGrant = await this.releaseGrants.revoke(activeGrant.id, "content_unscheduled", this.now());
588
+ if (!revokedGrant) throw new PublicationAuthorizationError("RELEASE_GRANT_TRANSITION_FAILED", "Content schedule grant could not be revoked");
589
+ }
590
+ const result = await this.options.handlers.handleContentUnschedule(input.collection, input.id);
591
+ if (!result.success) throw new PublicationAuthorizationError(result.error?.code ?? "CONTENT_UNSCHEDULE_ERROR", "Authorized content unschedule failed");
592
+ await this.logUnschedule(input, revokedGrant);
593
+ return {
594
+ grant: revokedGrant,
595
+ result
596
+ };
597
+ }
598
+ async authorize(input) {
599
+ if (input.actor.actorType === "system") throw new PublicationAuthorizationError("ACTOR_NOT_ALLOWED", "System actors must use the scheduled publication boundary");
600
+ let preparedPolicies = [];
601
+ try {
602
+ const activeGrant = await this.releaseGrants.findActiveForTarget(input.collection, input.id, input.operation);
603
+ const baseRelease = await this.buildRelease(input, []);
604
+ preparedPolicies = await this.preparePolicies(toPreparationTarget(baseRelease, activeGrant?.policyContributions ?? []));
605
+ const release = await this.buildRelease(input, preparedPolicies.map((prepared) => prepared.contribution));
606
+ await this.validatePolicies(release, preparedPolicies);
607
+ const tokenActor = isTokenAuthenticatedActor(input.actor);
608
+ const hitl = tokenActor ? await this.requireApprovedReleaseHitl(input, release) : null;
609
+ const grant = await this.releaseGrants.createOrReplaceActive({
610
+ collection: release.collection,
611
+ entryId: release.entryId,
612
+ scope: release.scope,
613
+ liveRevisionId: release.liveRevisionId,
614
+ draftRevisionId: release.draftRevisionId,
615
+ reviewedRev: release.reviewedRev,
616
+ editorialReviewRequestId: release.editorialReviewRequestId,
617
+ releaseHitlRequestId: hitl?.id ?? null,
618
+ operation: release.operation,
619
+ scheduledAt: release.scheduledAt,
620
+ publishedAt: release.publishedAt,
621
+ siteTimezone: release.siteTimezone,
622
+ actionHash: release.actionHash,
623
+ policyContributions: toStoredPolicyContributions(release.policyContributions),
624
+ authorizationMethod: tokenActor ? "approved_hitl" : "human_action",
625
+ authorizedByActorType: input.actor.actorType,
626
+ authorizedByActorId: input.actor.actorId,
627
+ authorizedAuthMetadata: redactActivityRecord(input.actor.authMetadata),
628
+ createdAt: this.now()
629
+ });
630
+ if (activeGrant && activeGrant.id !== grant.id) await this.releaseReplacedPolicies(activeGrant.policyContributions, preparedPolicies);
631
+ return {
632
+ release,
633
+ grant,
634
+ preparedPolicies
635
+ };
636
+ } catch (error) {
637
+ await this.releasePolicies(preparedPolicies, errorReason(error));
638
+ if (error instanceof PublicationAuthorizationError) throw error;
639
+ throw new PublicationAuthorizationError("RELEASE_GRANT_FAILED", error instanceof Error ? error.message : "Failed to authorize content release");
640
+ }
641
+ }
642
+ async revalidateScheduledGrant(input, grant, preparedPolicies) {
643
+ const now = this.now();
644
+ if (grant.expiresAt && grant.expiresAt <= now) throw new PublicationAuthorizationError("SCHEDULE_GRANT_EXPIRED", "Schedule grant expired before execution");
645
+ if (grant.scheduledAt !== input.scheduledAt) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "Schedule grant time does not match the due content");
646
+ const review = await this.reviewRequests.findById(grant.editorialReviewRequestId);
647
+ if (!review || !reviewMatchesGrant(review, grant)) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "Schedule grant editorial approval is no longer valid");
648
+ const content = extractContentState(await this.options.handlers.handleContentGet(input.collection, input.id));
649
+ if (!content || content.id !== grant.entryId || content.liveRevisionId !== grant.liveRevisionId || content.draftRevisionId !== grant.draftRevisionId || content.scheduledAt !== grant.scheduledAt) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "Scheduled content no longer matches its authorized release");
650
+ if (((await this.getSiteTimezone()).trim() || "UTC") !== grant.siteTimezone) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "Site timezone changed after the release was authorized");
651
+ if (preparedPolicies.length !== grant.policyContributions.length) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "A release policy required by the Schedule grant is unavailable");
652
+ const actionType = "content.release.schedule";
653
+ const actionHash = await buildContentReleaseActionHash({
654
+ actionType,
655
+ collection: grant.collection,
656
+ entryId: grant.entryId,
657
+ liveRevisionId: grant.liveRevisionId,
658
+ draftRevisionId: grant.draftRevisionId,
659
+ reviewedRev: grant.reviewedRev,
660
+ editorialReviewRequestId: grant.editorialReviewRequestId,
661
+ editorialActionHash: review.actionHash,
662
+ operation: "schedule",
663
+ publishedAt: grant.publishedAt,
664
+ scheduledAt: grant.scheduledAt,
665
+ siteTimezone: grant.siteTimezone,
666
+ policyContributions: grant.policyContributions
667
+ });
668
+ const release = {
669
+ collection: grant.collection,
670
+ entryId: grant.entryId,
671
+ scope: grant.scope,
672
+ liveRevisionId: grant.liveRevisionId,
673
+ draftRevisionId: grant.draftRevisionId,
674
+ reviewedRev: grant.reviewedRev,
675
+ actionType,
676
+ operation: "schedule",
677
+ editorialReviewRequestId: grant.editorialReviewRequestId,
678
+ editorialActionHash: review.actionHash,
679
+ publishedAt: grant.publishedAt,
680
+ scheduledAt: grant.scheduledAt,
681
+ siteTimezone: grant.siteTimezone,
682
+ policyContributions: grant.policyContributions,
683
+ actionHash,
684
+ releasePayload: {
685
+ kind: "content_release",
686
+ actionType,
687
+ target: {
688
+ actionType,
689
+ collection: grant.collection,
690
+ entryId: grant.entryId,
691
+ liveRevisionId: grant.liveRevisionId,
692
+ draftRevisionId: grant.draftRevisionId,
693
+ reviewedRev: grant.reviewedRev,
694
+ editorialReviewRequestId: grant.editorialReviewRequestId,
695
+ editorialActionHash: review.actionHash,
696
+ operation: "schedule",
697
+ publishedAt: grant.publishedAt,
698
+ scheduledAt: grant.scheduledAt,
699
+ siteTimezone: grant.siteTimezone,
700
+ policyContributions: grant.policyContributions,
701
+ scope: grant.scope,
702
+ actionHash
703
+ },
704
+ editorialReview: {
705
+ requestId: review.id,
706
+ resolvedByActorType: review.resolvedByActorType,
707
+ resolvedByActorId: review.resolvedByActorId,
708
+ resolvedAt: review.resolvedAt
709
+ }
710
+ }
711
+ };
712
+ if (actionHash !== grant.actionHash) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "Schedule grant fingerprint no longer matches");
713
+ if (grant.authorizationMethod === "approved_hitl") {
714
+ const request = grant.releaseHitlRequestId ? await this.hitlRequests.findById(grant.releaseHitlRequestId) : null;
715
+ if (!request || !matchesReleaseHitl(request, release, grantActor(grant))) throw new PublicationAuthorizationError("SCHEDULE_GRANT_INVALID", "Schedule grant release approval is no longer valid");
716
+ }
717
+ await this.validatePolicies(release, preparedPolicies);
718
+ return release;
719
+ }
720
+ async buildRelease(input, policyContributions) {
721
+ try {
722
+ return await this.releasePayloadBuilder.buildContentReleasePayload({
723
+ collection: input.collection,
724
+ id: input.id,
725
+ operation: input.operation,
726
+ editorialReviewRequestId: input.editorialReviewRequestId,
727
+ publishedAt: input.publishedAt,
728
+ scheduledAt: input.scheduledAt,
729
+ siteTimezone: input.siteTimezone,
730
+ policyContributions
731
+ });
732
+ } catch (error) {
733
+ throw new PublicationAuthorizationError("EDITORIAL_REVIEW_INVALID", error instanceof Error ? error.message : "Editorial review is invalid");
734
+ }
735
+ }
736
+ async requireApprovedReleaseHitl(input, release) {
737
+ if (!input.releaseHitlRequestId) throw new PublicationAuthorizationError("RELEASE_HITL_REQUIRED", "Token-authenticated publication requires an approved release HITL request");
738
+ const request = await this.hitlRequests.findById(input.releaseHitlRequestId);
739
+ if (!request || !matchesReleaseHitl(request, release, input.actor)) throw new PublicationAuthorizationError("RELEASE_HITL_INVALID", "Release HITL request is not approved for the current operation");
740
+ return request;
741
+ }
742
+ async preparePolicies(target) {
743
+ const prepared = [];
744
+ try {
745
+ for (const policy of this.policies) {
746
+ const contribution = await policy.prepare(target);
747
+ if (contribution.providerId !== policy.id) throw new Error(`Publication policy ${policy.id} returned another provider ID`);
748
+ prepared.push({
749
+ policy,
750
+ contribution
751
+ });
752
+ }
753
+ return prepared;
754
+ } catch (error) {
755
+ await this.releasePolicies(prepared, "release_policy_prepare_failed");
756
+ throw new PublicationAuthorizationError("RELEASE_POLICY_FAILED", error instanceof Error ? error.message : "Publication release policy failed");
757
+ }
758
+ }
759
+ async validatePolicies(release, preparedPolicies) {
760
+ try {
761
+ for (const prepared of preparedPolicies) await prepared.policy.validate(release, prepared.contribution);
762
+ } catch (error) {
763
+ throw new PublicationAuthorizationError("RELEASE_POLICY_FAILED", error instanceof Error ? error.message : "Publication release policy rejected release");
764
+ }
765
+ }
766
+ async failAuthorizedRelease(authorized, reason, handlerErrorCode) {
767
+ await this.releaseGrants.revoke(authorized.grant.id, reason, this.now());
768
+ await this.releasePolicies(authorized.preparedPolicies, reason);
769
+ throw new PublicationAuthorizationError(handlerErrorCode ?? "RELEASE_GRANT_FAILED", `Authorized content ${authorized.release.operation} failed`);
770
+ }
771
+ async consumePolicies(preparedPolicies) {
772
+ for (const prepared of preparedPolicies) await prepared.policy.consume?.(prepared.contribution);
773
+ }
774
+ async releasePolicies(preparedPolicies, reason) {
775
+ for (const prepared of preparedPolicies.toReversed()) await prepared.policy.release?.(prepared.contribution, reason);
776
+ }
777
+ async releaseReplacedPolicies(contributions, currentPolicies) {
778
+ const currentByProvider = new Map(currentPolicies.map((prepared) => [prepared.contribution.providerId, prepared.contribution]));
779
+ const replaced = this.restorePreparedPolicies(contributions).filter((prepared) => {
780
+ const current = currentByProvider.get(prepared.contribution.providerId);
781
+ return !current || current.reservationId !== prepared.contribution.reservationId || current.fingerprint !== prepared.contribution.fingerprint;
782
+ });
783
+ try {
784
+ await this.releasePolicies(replaced, "release_grant_replaced");
785
+ } catch (error) {
786
+ console.error("[publication-authorization] Failed to release replaced policy state:", error);
787
+ }
788
+ }
789
+ restorePreparedPolicies(contributions) {
790
+ const policiesById = new Map(this.policies.map((policy) => [policy.id, policy]));
791
+ return contributions.flatMap((contribution) => {
792
+ const policy = policiesById.get(contribution.providerId);
793
+ return policy ? [{
794
+ policy,
795
+ contribution: {
796
+ providerId: contribution.providerId,
797
+ policyVersion: contribution.policyVersion,
798
+ fingerprint: contribution.fingerprint,
799
+ ...contribution.reservationId ? { reservationId: contribution.reservationId } : {}
800
+ }
801
+ }] : [];
802
+ });
803
+ }
804
+ async logSuccess(input, release, grant) {
805
+ await this.activity.create({
806
+ actorType: input.actor.actorType,
807
+ actorId: input.actor.actorId,
808
+ authMetadata: redactActivityRecord(input.actor.authMetadata),
809
+ actionType: release.actionType,
810
+ subjectType: "content",
811
+ subjectId: release.entryId,
812
+ relatedSubjectType: "review_request",
813
+ relatedSubjectId: release.editorialReviewRequestId,
814
+ sourceType: input.sourceType ?? "unknown",
815
+ sourceName: input.sourceName ?? null,
816
+ resultStatus: "succeeded",
817
+ scope: release.scope,
818
+ summary: `${release.operation === "publish" ? "Published" : "Scheduled"} ${release.collection}/${release.entryId}`,
819
+ detail: {
820
+ editorialReviewRequestId: release.editorialReviewRequestId,
821
+ releaseHitlRequestId: grant.releaseHitlRequestId,
822
+ releaseGrantId: grant.id,
823
+ actionHash: release.actionHash,
824
+ scheduledAt: release.scheduledAt,
825
+ publishedAt: release.publishedAt
826
+ },
827
+ createdAt: this.now()
828
+ });
829
+ }
830
+ async logUnschedule(input, grant) {
831
+ await this.activity.create({
832
+ actorType: input.actor.actorType,
833
+ actorId: input.actor.actorId,
834
+ authMetadata: redactActivityRecord(input.actor.authMetadata),
835
+ actionType: "content.unscheduled",
836
+ subjectType: "content",
837
+ subjectId: input.id,
838
+ sourceType: input.sourceType ?? "unknown",
839
+ sourceName: input.sourceName ?? null,
840
+ resultStatus: "succeeded",
841
+ scope: `content:${input.collection}:${input.id}`,
842
+ summary: `Unscheduled ${input.collection}/${input.id}`,
843
+ detail: {
844
+ releaseGrantId: grant?.id ?? null,
845
+ revocationReason: grant?.revocationReason ?? null
846
+ },
847
+ createdAt: this.now()
848
+ });
849
+ }
850
+ async blockScheduledRelease(input, grant, reason) {
851
+ const result = await this.options.handlers.handleContentUnschedule(input.collection, input.id);
852
+ await this.activity.create({
853
+ actorType: "system",
854
+ actorId: SYSTEM_ACTOR_ID,
855
+ authMetadata: { auth_method: "system" },
856
+ actionType: "content.schedule_blocked",
857
+ subjectType: "content",
858
+ subjectId: input.id,
859
+ relatedSubjectType: grant ? "review_request" : null,
860
+ relatedSubjectId: grant?.editorialReviewRequestId ?? null,
861
+ sourceType: "system",
862
+ sourceName: "scheduled_publish",
863
+ resultStatus: "blocked",
864
+ scope: `content:${input.collection}:${input.id}`,
865
+ summary: `Blocked scheduled publication for ${input.collection}/${input.id}`,
866
+ detail: {
867
+ reason,
868
+ releaseGrantId: grant?.id ?? null,
869
+ unscheduled: result.success
870
+ },
871
+ createdAt: this.now()
872
+ });
873
+ if (!result.success) throw new PublicationAuthorizationError(result.error?.code ?? "CONTENT_UNSCHEDULE_ERROR", "Blocked scheduled content could not be unscheduled");
874
+ }
875
+ async logScheduledPublish(release, grant) {
876
+ await this.activity.create({
877
+ actorType: "system",
878
+ actorId: SYSTEM_ACTOR_ID,
879
+ authMetadata: { auth_method: "system" },
880
+ actionType: "content.release.publish",
881
+ subjectType: "content",
882
+ subjectId: release.entryId,
883
+ relatedSubjectType: "review_request",
884
+ relatedSubjectId: release.editorialReviewRequestId,
885
+ sourceType: "system",
886
+ sourceName: "scheduled_publish",
887
+ resultStatus: "succeeded",
888
+ scope: release.scope,
889
+ summary: `Published scheduled content ${release.collection}/${release.entryId}`,
890
+ detail: {
891
+ editorialReviewRequestId: release.editorialReviewRequestId,
892
+ releaseHitlRequestId: grant.releaseHitlRequestId,
893
+ releaseGrantId: grant.id,
894
+ actionHash: release.actionHash,
895
+ scheduledAt: release.scheduledAt,
896
+ authorizedByActorType: grant.authorizedByActorType,
897
+ authorizedByActorId: grant.authorizedByActorId,
898
+ authorizedAuthMetadata: grant.authorizedAuthMetadata
899
+ },
900
+ createdAt: this.now()
901
+ });
902
+ }
903
+ assertUniquePolicyIds() {
904
+ const ids = /* @__PURE__ */ new Set();
905
+ for (const policy of this.policies) {
906
+ if (ids.has(policy.id)) throw new Error(`Duplicate publication release policy: ${policy.id}`);
907
+ ids.add(policy.id);
908
+ }
909
+ }
910
+ };
911
+ function toPreparationTarget(release, replacedPolicyContributions) {
912
+ return {
913
+ collection: release.collection,
914
+ entryId: release.entryId,
915
+ scope: release.scope,
916
+ operation: release.operation,
917
+ liveRevisionId: release.liveRevisionId,
918
+ draftRevisionId: release.draftRevisionId,
919
+ reviewedRev: release.reviewedRev,
920
+ editorialReviewRequestId: release.editorialReviewRequestId,
921
+ editorialActionHash: release.editorialActionHash,
922
+ publishedAt: release.publishedAt,
923
+ scheduledAt: release.scheduledAt,
924
+ siteTimezone: release.siteTimezone,
925
+ replacedPolicyContributions: replacedPolicyContributions.map((contribution) => ({
926
+ providerId: contribution.providerId,
927
+ policyVersion: contribution.policyVersion,
928
+ fingerprint: contribution.fingerprint,
929
+ ...contribution.reservationId ? { reservationId: contribution.reservationId } : {}
930
+ }))
931
+ };
932
+ }
933
+ function toStoredPolicyContributions(contributions) {
934
+ return contributions.map((contribution) => ({ ...contribution }));
935
+ }
936
+ function matchesReleaseHitl(request, release, actor) {
937
+ return request.status === "approved" && request.scope === release.scope && request.actionType === release.actionType && request.targetRefType === "content" && request.targetRefId === release.entryId && request.requestedByActorType === actor.actorType && request.requestedByActorId === actor.actorId && extractActionHash(request.metadata) === release.actionHash;
938
+ }
939
+ function reviewMatchesGrant(review, grant) {
940
+ return review.status === "approved" && review.collection === grant.collection && review.entryId === grant.entryId && review.scope === grant.scope && review.liveRevisionId === grant.liveRevisionId && review.draftRevisionId === grant.draftRevisionId && review.reviewedRev === grant.reviewedRev && review.actionType === "content.publish";
941
+ }
942
+ function grantActor(grant) {
943
+ return {
944
+ actorType: grant.authorizedByActorType,
945
+ actorId: grant.authorizedByActorId,
946
+ authMetadata: grant.authorizedAuthMetadata ?? {}
947
+ };
948
+ }
949
+ function extractContentState(result) {
950
+ if (!result.success) return null;
951
+ const item = asRecord(asRecord(result.data)?.item ?? result.data);
952
+ const id = stringOrNull(item?.id);
953
+ if (!item || !id) return null;
954
+ return {
955
+ id,
956
+ liveRevisionId: stringOrNull(item.liveRevisionId),
957
+ draftRevisionId: stringOrNull(item.draftRevisionId),
958
+ scheduledAt: stringOrNull(item.scheduledAt)
959
+ };
960
+ }
961
+ function asRecord(value) {
962
+ return isRecord(value) ? value : null;
963
+ }
964
+ function isRecord(value) {
965
+ return typeof value === "object" && value !== null && !Array.isArray(value);
966
+ }
967
+ function stringOrNull(value) {
968
+ return typeof value === "string" && value.length > 0 ? value : null;
969
+ }
970
+ function extractActionHash(metadata) {
971
+ const value = metadata.actionHash;
972
+ return typeof value === "string" && value.length > 0 ? value : null;
973
+ }
974
+ function isTokenAuthenticatedActor(actor) {
975
+ if (actor.actorType === "api_token") return true;
976
+ const authMethod = actor.authMetadata.auth_method;
977
+ return authMethod === "api_token" || authMethod === "oauth_token";
978
+ }
979
+ function errorReason(error) {
980
+ if (error instanceof PublicationAuthorizationError) return error.code.toLowerCase();
981
+ return "release_authorization_failed";
982
+ }
983
+
984
+ //#endregion
985
+ export { HITL_REQUEST_STATUSES as a, HITL_REQUEST_PRIORITIES as i, PublicationAuthorizationService as n, HitlRequestRepository as o, ReleasePayloadBuilder as r, PublicationAuthorizationError as t };