dineway 0.2.40 → 0.2.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (460) hide show
  1. package/dist/{activity-LXZdjKwI.mjs → activity-BuhkMdv8.mjs} +2 -2
  2. package/dist/{activity-events-DoqeOM8x.mjs → activity-events-DkHsy7Y0.mjs} +1 -1
  3. package/dist/{allowed-origins-B4zstd2d.mjs → allowed-origins-DASdFW-l.mjs} +1 -1
  4. package/dist/api/route-utils.d.mts +15 -12
  5. package/dist/api/route-utils.mjs +27 -20
  6. package/dist/api/schemas/index.d.mts +1 -1
  7. package/dist/api/schemas/index.mjs +10 -5
  8. package/dist/{api-CQishNjZ.mjs → api-BBXfpMJw.mjs} +41 -13
  9. package/dist/{api-tokens-CNHnKO57.mjs → api-tokens-ciHNTdN2.mjs} +1 -1
  10. package/dist/{apply-D4rZHDyg.mjs → apply-CZDKUvZ4.mjs} +62 -18
  11. package/dist/astro/index.d.mts +16 -13
  12. package/dist/astro/index.mjs +31 -5
  13. package/dist/astro/middleware/auth.d.mts +14 -11
  14. package/dist/astro/middleware/auth.mjs +8 -8
  15. package/dist/astro/middleware/redirect.mjs +10 -6
  16. package/dist/astro/middleware/request-context.mjs +5 -5
  17. package/dist/astro/middleware/seed.d.mts +1 -1
  18. package/dist/astro/middleware/seed.mjs +2 -2
  19. package/dist/astro/middleware/setup.mjs +1 -1
  20. package/dist/astro/middleware.d.mts +2 -2
  21. package/dist/astro/middleware.mjs +266 -176
  22. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +12 -7
  23. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +12 -7
  24. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  25. package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
  26. package/dist/astro/routes/api/admin/briefing.mjs +41 -22
  27. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  28. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +14 -10
  29. package/dist/astro/routes/api/admin/byline-fields/index.mjs +14 -10
  30. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +14 -10
  31. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +25 -19
  32. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +25 -19
  33. package/dist/astro/routes/api/admin/bylines/index.mjs +25 -19
  34. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +20 -16
  35. package/dist/astro/routes/api/admin/comments/_id_.mjs +10 -7
  36. package/dist/astro/routes/api/admin/comments/bulk.mjs +18 -13
  37. package/dist/astro/routes/api/admin/comments/counts.mjs +10 -7
  38. package/dist/astro/routes/api/admin/comments/index.mjs +18 -13
  39. package/dist/astro/routes/api/admin/context/_id_/history.mjs +51 -39
  40. package/dist/astro/routes/api/admin/context/_id_/index.mjs +51 -39
  41. package/dist/astro/routes/api/admin/context/_id_/review.mjs +57 -44
  42. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +57 -44
  43. package/dist/astro/routes/api/admin/context/diff.mjs +56 -43
  44. package/dist/astro/routes/api/admin/context/index.mjs +57 -44
  45. package/dist/astro/routes/api/admin/context/stale.mjs +56 -43
  46. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +51 -39
  47. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +56 -43
  48. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +56 -43
  49. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +52 -40
  50. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  51. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +7 -7
  52. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +7 -7
  53. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +78 -68
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +78 -68
  55. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +71 -60
  56. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +78 -67
  57. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +78 -67
  58. package/dist/astro/routes/api/admin/plugins/index.mjs +71 -60
  59. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  60. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -60
  61. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +78 -67
  62. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -60
  63. package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -60
  64. package/dist/astro/routes/api/admin/review-requests/_id_/image.mjs +38 -23
  65. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +46 -36
  66. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +63 -52
  67. package/dist/astro/routes/api/admin/review-requests/_id_/revoke.mjs +9 -9
  68. package/dist/astro/routes/api/admin/review-requests/index.mjs +61 -50
  69. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -60
  70. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  71. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -60
  72. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
  73. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  74. package/dist/astro/routes/api/admin/users/_id_/index.mjs +11 -7
  75. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  76. package/dist/astro/routes/api/admin/users/index.mjs +12 -7
  77. package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
  78. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  79. package/dist/astro/routes/api/auth/invite/complete.mjs +17 -12
  80. package/dist/astro/routes/api/auth/invite/index.mjs +14 -9
  81. package/dist/astro/routes/api/auth/invite/register-options.mjs +16 -11
  82. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  83. package/dist/astro/routes/api/auth/magic-link/send.mjs +17 -12
  84. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  85. package/dist/astro/routes/api/auth/me.mjs +14 -11
  86. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  87. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  88. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +3 -3
  89. package/dist/astro/routes/api/auth/passkey/_id_.mjs +12 -7
  90. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  91. package/dist/astro/routes/api/auth/passkey/options.mjs +19 -14
  92. package/dist/astro/routes/api/auth/passkey/register/options.mjs +16 -11
  93. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +17 -12
  94. package/dist/astro/routes/api/auth/passkey/verify.mjs +17 -12
  95. package/dist/astro/routes/api/auth/setup-token/index.mjs +6 -6
  96. package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
  97. package/dist/astro/routes/api/auth/signup/complete.mjs +17 -12
  98. package/dist/astro/routes/api/auth/signup/request.mjs +17 -12
  99. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  100. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts +14 -11
  101. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +23 -19
  102. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +23 -18
  103. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  104. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +8 -8
  105. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +8 -8
  106. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +8 -8
  107. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +25 -20
  108. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +41 -31
  109. package/dist/astro/routes/api/content/_collection_/_id_/release-readiness.mjs +14 -9
  110. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +8 -8
  111. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  112. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +41 -31
  113. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +30 -20
  114. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  115. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +8 -8
  116. package/dist/astro/routes/api/content/_collection_/_id_.mjs +25 -14
  117. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  118. package/dist/astro/routes/api/content/_collection_/index.mjs +25 -14
  119. package/dist/astro/routes/api/content/_collection_/trash.mjs +13 -8
  120. package/dist/astro/routes/api/dashboard.mjs +21 -13
  121. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  122. package/dist/astro/routes/api/health.mjs +1 -1
  123. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  124. package/dist/astro/routes/api/import/probe.mjs +30 -23
  125. package/dist/astro/routes/api/import/wordpress/analyze.mjs +13 -10
  126. package/dist/astro/routes/api/import/wordpress/execute.d.mts +14 -11
  127. package/dist/astro/routes/api/import/wordpress/execute.mjs +58 -47
  128. package/dist/astro/routes/api/import/wordpress/media.d.mts +14 -11
  129. package/dist/astro/routes/api/import/wordpress/media.mjs +17 -14
  130. package/dist/astro/routes/api/import/wordpress/prepare.mjs +61 -48
  131. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +15 -12
  132. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +58 -45
  133. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  134. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +32 -26
  135. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  136. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +14 -11
  137. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +63 -52
  138. package/dist/astro/routes/api/integration/artifact.mjs +9 -9
  139. package/dist/astro/routes/api/integration/dispatch.mjs +14 -14
  140. package/dist/astro/routes/api/integrations/_provider_.mjs +9 -9
  141. package/dist/astro/routes/api/integrations/index.mjs +8 -8
  142. package/dist/astro/routes/api/manifest.mjs +5 -5
  143. package/dist/astro/routes/api/mcp.mjs +141 -93
  144. package/dist/astro/routes/api/media/_id_/confirm.mjs +15 -12
  145. package/dist/astro/routes/api/media/_id_.mjs +14 -9
  146. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  147. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  148. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  149. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  150. package/dist/astro/routes/api/media/upload-url.mjs +16 -13
  151. package/dist/astro/routes/api/media.mjs +19 -16
  152. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +57 -44
  153. package/dist/astro/routes/api/menus/_name_/items.mjs +57 -44
  154. package/dist/astro/routes/api/menus/_name_/reorder.mjs +57 -44
  155. package/dist/astro/routes/api/menus/_name_/translations.mjs +57 -44
  156. package/dist/astro/routes/api/menus/_name_.mjs +57 -44
  157. package/dist/astro/routes/api/menus/index.mjs +57 -44
  158. package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
  159. package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
  160. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  161. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  162. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  163. package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
  164. package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
  165. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  166. package/dist/astro/routes/api/openapi.json.mjs +10 -5
  167. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  168. package/dist/astro/routes/api/redirects/404s/index.mjs +15 -13
  169. package/dist/astro/routes/api/redirects/404s/summary.mjs +15 -13
  170. package/dist/astro/routes/api/redirects/_id_.mjs +57 -44
  171. package/dist/astro/routes/api/redirects/index.mjs +57 -44
  172. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  173. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  174. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -62
  175. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +73 -62
  176. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +73 -62
  177. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +73 -62
  178. package/dist/astro/routes/api/schema/collections/index.mjs +73 -62
  179. package/dist/astro/routes/api/schema/index.mjs +13 -10
  180. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -60
  181. package/dist/astro/routes/api/schema/orphans/index.mjs +71 -60
  182. package/dist/astro/routes/api/search/enable.mjs +20 -13
  183. package/dist/astro/routes/api/search/index.mjs +19 -12
  184. package/dist/astro/routes/api/search/rebuild.mjs +20 -13
  185. package/dist/astro/routes/api/search/stats.mjs +12 -7
  186. package/dist/astro/routes/api/search/suggest.mjs +19 -12
  187. package/dist/astro/routes/api/sections/_slug_.mjs +57 -44
  188. package/dist/astro/routes/api/sections/index.mjs +57 -44
  189. package/dist/astro/routes/api/settings/email.mjs +5 -5
  190. package/dist/astro/routes/api/settings/reviews.mjs +11 -11
  191. package/dist/astro/routes/api/settings.mjs +57 -44
  192. package/dist/astro/routes/api/setup/admin-verify.mjs +19 -14
  193. package/dist/astro/routes/api/setup/admin.mjs +17 -12
  194. package/dist/astro/routes/api/setup/dev-bypass.mjs +44 -32
  195. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  196. package/dist/astro/routes/api/setup/index.mjs +47 -34
  197. package/dist/astro/routes/api/setup/status.mjs +3 -3
  198. package/dist/astro/routes/api/snapshot.mjs +9 -9
  199. package/dist/astro/routes/api/system/heartbeat.mjs +2 -2
  200. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +60 -47
  201. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +60 -47
  202. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +60 -47
  203. package/dist/astro/routes/api/taxonomies/index.mjs +60 -47
  204. package/dist/astro/routes/api/themes/preview.mjs +7 -7
  205. package/dist/astro/routes/api/typegen.mjs +4 -4
  206. package/dist/astro/routes/api/well-known/auth.mjs +3 -3
  207. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  208. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  209. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +56 -43
  210. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +57 -44
  211. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +57 -44
  212. package/dist/astro/routes/api/widget-areas/_name_.mjs +53 -41
  213. package/dist/astro/routes/api/widget-areas/index.mjs +57 -44
  214. package/dist/astro/routes/api/widget-components.mjs +2 -2
  215. package/dist/astro/routes/robots.txt.mjs +14 -9
  216. package/dist/astro/routes/sitemap-_collection_.xml.mjs +20 -16
  217. package/dist/astro/routes/sitemap.xml.mjs +19 -15
  218. package/dist/astro/session-driver.d.mts +1 -1
  219. package/dist/astro/session-driver.mjs +8 -3
  220. package/dist/astro/types.d.mts +21 -14
  221. package/dist/{atomic-authority-CnBQJ14T.mjs → atomic-authority-Bf5QZboB.mjs} +2 -2
  222. package/dist/{audit-Cl495Ze3.mjs → audit-hXJBTPY0.mjs} +1 -1
  223. package/dist/auth/providers/github.d.mts +1 -1
  224. package/dist/auth/providers/google.d.mts +1 -1
  225. package/dist/{auth-control-guard-DbjgJdlo.mjs → auth-control-guard-DpUP6Fs_.mjs} +1 -1
  226. package/dist/{authorize-DDmgmnW-.mjs → authorize-DWNOqMKq.mjs} +1 -1
  227. package/dist/{briefing-DsD-Ouwc.mjs → briefing-BShyAm_Z.mjs} +1 -1
  228. package/dist/{briefing-COw-WcYz.mjs → briefing-CaeEFvkD.mjs} +995 -7
  229. package/dist/{bundle-bhiszAui.mjs → bundle-DWn5eFKz.mjs} +2 -2
  230. package/dist/{byline-fields-D-b9CWux.d.mts → byline-fields-B7pQ3LMi.d.mts} +14 -10
  231. package/dist/{byline-fields-BKj5f3Ub.mjs → byline-fields-DRMCc0V_.mjs} +1 -1
  232. package/dist/{byline-fields-DZ46DF10.mjs → byline-fields-wWu2Cb3l.mjs} +3 -3
  233. package/dist/{byline-registry-CJihchD1.mjs → byline-registry-Caj0_gbU.mjs} +1 -1
  234. package/dist/{byline-TYk2kad6.mjs → byline-uuVB2B3E.mjs} +65 -14
  235. package/dist/{bylines-6T9iVC9j.mjs → bylines-PLlsL31L.mjs} +3 -3
  236. package/dist/{bylines-CvTSCAw9.mjs → bylines-XGlNK0Lo.mjs} +5 -5
  237. package/dist/{patterns-Ay-4KImK.mjs → cache-DsEbwFVE.mjs} +51 -1
  238. package/dist/{chunks-C8vSD_5L.mjs → chunks-Bb56aCtB.mjs} +1 -1
  239. package/dist/cli/index.mjs +486 -48
  240. package/dist/cli/plugin-kit.d.mts +14 -11
  241. package/dist/cli/plugin-kit.mjs +2 -2
  242. package/dist/client/external-auth-headers.d.mts +1 -1
  243. package/dist/client/index.d.mts +16 -13
  244. package/dist/client/index.mjs +2 -2
  245. package/dist/{client-factory-C1ZQCMog.mjs → client-factory-BLbm250o.mjs} +1 -1
  246. package/dist/{comment-DAQfUjqt.mjs → comment-BWDG1nQm.mjs} +2 -2
  247. package/dist/{comment-reaction-Dp3G7UZc.mjs → comment-reaction-B7pLTlQ7.mjs} +1 -1
  248. package/dist/{comments-BrvIaRAx.mjs → comments-xkten8nV.mjs} +1 -1
  249. package/dist/config-6R0bchVE.mjs +125 -0
  250. package/dist/{content-CIKsrvU9.mjs → content-BNeuaVCS.mjs} +302 -45
  251. package/dist/content-Dr22fzA_.mjs +390 -0
  252. package/dist/{content-refresh-BilzqcLt.mjs → content-refresh-D7wpVFJ_.mjs} +14 -8
  253. package/dist/content-storage/index.d.mts +193 -0
  254. package/dist/content-storage/index.mjs +29 -0
  255. package/dist/content-storage/store.d.mts +3 -0
  256. package/dist/content-storage/store.mjs +5 -0
  257. package/dist/{review-payload-Bap86e75.mjs → content-write-43KZZ7dz.mjs} +838 -131
  258. package/dist/{context-DAs_MZjJ.mjs → context-Cjz0y4Al.mjs} +292 -23
  259. package/dist/{context-DVTvucNb.mjs → context-DuYXPlfZ.mjs} +2 -2
  260. package/dist/{context-route-helpers-BP-UJ4u8.mjs → context-route-helpers-TP3EqxRQ.mjs} +2 -2
  261. package/dist/{dashboard-BAjWCGCP.mjs → dashboard-BquGX1ue.mjs} +4 -4
  262. package/dist/database/batch.d.mts +1 -1
  263. package/dist/database/batch.mjs +1 -1
  264. package/dist/database/d1/index.d.mts +14 -11
  265. package/dist/database/d1/index.mjs +4 -4
  266. package/dist/database/instrumentation.mjs +3 -2
  267. package/dist/db/index.d.mts +3 -3
  268. package/dist/db/index.mjs +1 -1
  269. package/dist/db/libsql.d.mts +1 -1
  270. package/dist/db/postgres.d.mts +1 -1
  271. package/dist/db/sqlite.d.mts +1 -1
  272. package/dist/{device-flow-Dh0rNlh1.mjs → device-flow-SoZh-HvN.mjs} +3 -3
  273. package/dist/{discovery-V0e0Gg8j.mjs → discovery-BwCZFUXm.mjs} +4 -4
  274. package/dist/{enrich-B7PIJ8Iy.mjs → enrich-CAMsD1aT.mjs} +1 -1
  275. package/dist/{error-B5a45Tfb.mjs → error-sL4aemcW.mjs} +2 -0
  276. package/dist/{evidence-Vnp_fQbC.mjs → evidence-1Gr8TlTf.mjs} +7 -7
  277. package/dist/{field-defs-cache-aXUeXJdC.mjs → field-defs-cache-dn5Tw79A.mjs} +4 -4
  278. package/dist/{fts-manager-BrPpYtK0.mjs → fts-manager-Zu5ITic0.mjs} +1 -1
  279. package/dist/{hitl-requests-BxMMON3s.mjs → hitl-requests-Bdab4DhO.mjs} +2 -2
  280. package/dist/{hitl-route-helpers-sdnjpx2k.mjs → hitl-route-helpers-DGMLQajA.mjs} +5 -5
  281. package/dist/hook-events-BQw73jc7.d.mts +32 -0
  282. package/dist/{import-C2-v4FCs.mjs → import-DJFlvQey.mjs} +9 -9
  283. package/dist/{index-BVGe04wF.d.mts → index-CLj17kW9.d.mts} +12 -5
  284. package/dist/index.d.mts +19 -16
  285. package/dist/index.mjs +107 -98
  286. package/dist/{integration-credentials-DMEXZU2J.mjs → integration-credentials-DpuRw1kx.mjs} +2 -2
  287. package/dist/{jsonld-wRF85RXo.d.mts → jsonld-CPijKSUe.d.mts} +2 -2
  288. package/dist/{load-DvCVppOF.mjs → load-CiRTddkJ.mjs} +1 -1
  289. package/dist/{loader-Dp6zLmQm.mjs → loader-Bq1aW12P.mjs} +16 -5
  290. package/dist/{manifest-schema-CCvogfrP.mjs → manifest-schema-DaQpgyTB.mjs} +1 -1
  291. package/dist/{mcp-reviewed-executor-B8Gbin3T.mjs → mcp-reviewed-executor-DtTnFcqC.mjs} +6 -6
  292. package/dist/media/image-endpoint.mjs +1 -1
  293. package/dist/media/index.d.mts +1 -1
  294. package/dist/media/index.mjs +2 -2
  295. package/dist/media/local-runtime.d.mts +16 -13
  296. package/dist/media/local-runtime.mjs +3 -3
  297. package/dist/{media-C5ba8fvI.mjs → media-BjH5OD-A.mjs} +1 -1
  298. package/dist/{media-allowlist-DQvscVkS.mjs → media-allowlist-C8HJ2O61.mjs} +1 -1
  299. package/dist/{menus-w5xwT-f5.mjs → menus-BXkfzNR1.mjs} +7 -7
  300. package/dist/{menus-CyNpBQrX.mjs → menus-CbBi7Ad7.mjs} +2 -2
  301. package/dist/migration-D9OY6vI9.mjs +526 -0
  302. package/dist/{migrations-CLlX25HO.mjs → migrations-BAjF60cl.mjs} +1 -1
  303. package/dist/{oauth-authorization-CdqJZUMf.mjs → oauth-authorization-CSSRMOKn.mjs} +4 -4
  304. package/dist/{oauth-clients-CHNb9MAZ.mjs → oauth-clients-DX5HIJJv.mjs} +2 -2
  305. package/dist/object-cache/memory.d.mts +1 -1
  306. package/dist/{object-cache-mxCW-Rpt.mjs → object-cache-DyI1SOBK.mjs} +3 -1
  307. package/dist/owned-metadata-C99DzQuq.mjs +69 -0
  308. package/dist/page/index.d.mts +15 -12
  309. package/dist/page/index.mjs +1 -1
  310. package/dist/{parse-THHCpJLB.mjs → parse-C6kCR1OT.mjs} +1 -1
  311. package/dist/plugin-utils.d.mts +14 -11
  312. package/dist/plugins/adapt-sandbox-entry.d.mts +14 -11
  313. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  314. package/dist/{plugins-pfraURNp.mjs → plugins-LtyuDuIb.mjs} +16 -962
  315. package/dist/{policy-D2USlibj.mjs → policy-Drg5yr1-.mjs} +2 -2
  316. package/dist/{preview-Bh7D7F27.mjs → preview-CWiIjMDi.mjs} +2 -2
  317. package/dist/{provider-loader-DT7vQ5FI.d.mts → provider-loader-oLKm1AU8.d.mts} +1 -1
  318. package/dist/{public-url-Ccv0Xmue.d.mts → public-url-CEC1vj02.d.mts} +2 -2
  319. package/dist/{public-url-CG5YbNqB.d.mts → public-url-cMnsBUZB.d.mts} +1 -1
  320. package/dist/{publication-authorization-B_HJSnzR.mjs → publication-authorization-CJ4Jr5Hg.mjs} +43 -17
  321. package/dist/{query-xspvw7Ui.mjs → query-CLWTwcTr.mjs} +14 -14
  322. package/dist/{query-DLeahg3x.mjs → query-CP9M8xxX.mjs} +4 -4
  323. package/dist/{rate-limit-BsBr_U9g.mjs → rate-limit-DeVLLe4z.mjs} +2 -2
  324. package/dist/{redirect-BQFa1THe.mjs → redirect-CJ-FAbNK.mjs} +2 -2
  325. package/dist/{redirects-DJcsgz_X.mjs → redirects-BKi6mek4.mjs} +4 -5
  326. package/dist/{redirects-CVfxefrz.mjs → redirects-I78-ZYLV.mjs} +5 -386
  327. package/dist/{registry-Dclv9iHv.mjs → registry-B-HULaJI.mjs} +7 -7
  328. package/dist/{release-Da2UFygt.mjs → release-D615eKav.mjs} +173 -22
  329. package/dist/request-context.d.mts +30 -0
  330. package/dist/{request-meta-CjORiJQ_.mjs → request-meta-DZYuLXx_.mjs} +1 -1
  331. package/dist/review-payload-Bhi52CbI.mjs +112 -0
  332. package/dist/{review-requests-CcSUTm_l.mjs → review-requests-CGQ1u7uY.mjs} +2 -2
  333. package/dist/{review-requests-CUVn0RBl.mjs → review-requests-DZYM51yI.mjs} +2 -2
  334. package/dist/{review-route-helpers-CKBfGKCi.mjs → review-route-helpers-DXNDyx_q.mjs} +2 -2
  335. package/dist/{revision-W6FDfDqx.mjs → revision-DlxUfOD5.mjs} +42 -7
  336. package/dist/revisions-qNkae-Dq.mjs +57 -0
  337. package/dist/{revocation-C_ZQvGRT.mjs → revocation-4we8kfBg.mjs} +2 -2
  338. package/dist/{runner-CRU7BXjr.mjs → runner-CuG8o1uW.mjs} +558 -487
  339. package/dist/{runner-SoP1rphP.d.mts → runner-DXQkyPeX.d.mts} +1 -1
  340. package/dist/{runs-BtaAiLTw.mjs → runs-BjgLfqCn.mjs} +5 -5
  341. package/dist/runtime-Bs2JMbb2.d.mts +45 -0
  342. package/dist/runtime-Ch5G-tnG.mjs +400 -0
  343. package/dist/runtime.d.mts +15 -12
  344. package/dist/runtime.mjs +9 -4
  345. package/dist/schema-DVeOJpqA.mjs +8 -0
  346. package/dist/{search-BI9uKr7U.mjs → search-zMoM2_uq.mjs} +4 -98
  347. package/dist/{secrets-D_pergcD.mjs → secrets-CIYcw9T9.mjs} +4 -4
  348. package/dist/{sections-BqqYq9RW.mjs → sections-BtO0Zdv5.mjs} +2 -2
  349. package/dist/seed/index.d.mts +2 -2
  350. package/dist/seed/index.mjs +38 -26
  351. package/dist/seo/index.d.mts +3 -3
  352. package/dist/seo/index.mjs +12 -9
  353. package/dist/{seo-B-5PsaJO.mjs → seo-DwcULb78.mjs} +1 -1
  354. package/dist/{seo-Bs_DUxJf.mjs → seo-uliFa7s-.mjs} +44 -5
  355. package/dist/{service-W2xuGLgw.mjs → service-BBJM08uD.mjs} +2 -2
  356. package/dist/{service-B65aJsN7.mjs → service-CkMuD5AE.mjs} +3 -3
  357. package/dist/{settings-CyJ2-MKx.mjs → settings-D31Y4msD.mjs} +2 -2
  358. package/dist/{settings-DsBzKeUQ.mjs → settings-DDOB3gW1.mjs} +7 -7
  359. package/dist/{setup-complete-t9yamqBb.mjs → setup-complete-5GxB7hiF.mjs} +1 -1
  360. package/dist/{site-activity-DU0UPDji.mjs → site-activity-hpfJkmxQ.mjs} +1 -1
  361. package/dist/{site-context-Dic2jHuw.mjs → site-context-D3AmDdpQ.mjs} +15 -15
  362. package/dist/{site-url-Tw6CfBB2.mjs → site-url-CYatfe3q.mjs} +1 -1
  363. package/dist/{state-jx6Yiwsm.mjs → state-ClG1I4wl.mjs} +1 -1
  364. package/dist/storage/local.d.mts +1 -1
  365. package/dist/storage/local.mjs +1 -1
  366. package/dist/storage/s3.d.mts +1 -1
  367. package/dist/storage/s3.mjs +2 -2
  368. package/dist/{store-32e6dfD-.mjs → store-BzaAtszy.mjs} +3 -3
  369. package/dist/submission-DgLES24O.mjs +205 -0
  370. package/dist/{taxonomies-BFsUR7kc.mjs → taxonomies-B4hE8Yb3.mjs} +3 -3
  371. package/dist/{taxonomies-lWGNLKgn.mjs → taxonomies-BI26Bk-M.mjs} +7 -7
  372. package/dist/{taxonomy-DN6i1upz.mjs → taxonomy-B8w8F2Cs.mjs} +53 -3
  373. package/dist/terms-EskuqbKE.mjs +104 -0
  374. package/dist/text-extraction-CdqMGYQK.mjs +96 -0
  375. package/dist/{tokens-D-StaTAQ.mjs → tokens-D8HEH277.mjs} +1 -1
  376. package/dist/{trusted-proxy-hYufGFPK.mjs → trusted-proxy-Dg3U9Lrv.mjs} +1 -1
  377. package/dist/{types-D5JfvPvx.d.mts → types-0gRlZbhN.d.mts} +88 -32
  378. package/dist/{types-RFzE_V1M.mjs → types-BI3ULB3A.mjs} +2 -2
  379. package/dist/{types-B--VyN3n.d.mts → types-Dpv_MvwZ.d.mts} +1 -1
  380. package/dist/{types-CgcOeaiQ.d.mts → types-ex-UrNlz.d.mts} +1 -1
  381. package/dist/types-qOEot0UQ.d.mts +83 -0
  382. package/dist/ui/server-runtime.d.mts +18 -15
  383. package/dist/ui/server-runtime.mjs +29 -25
  384. package/dist/{user-Btai9rl3.mjs → user-Bl2_8rhJ.mjs} +2 -2
  385. package/dist/{utils-CYxGuO_P.mjs → utils-CklSLz9F.mjs} +2 -2
  386. package/dist/{validate-C05z0m7M.mjs → validate-C-yk7mmX.mjs} +3 -3
  387. package/dist/{validate-kmN2lS8H.d.mts → validate-DUscf6VG.d.mts} +3 -3
  388. package/dist/version-Co258u70.mjs +6 -0
  389. package/dist/version-store-BXv2D0de.mjs +208 -0
  390. package/dist/version-store-B_THJCc0.d.mts +98 -0
  391. package/dist/{widgets-BOrDZdQ3.mjs → widgets-B99mnftw.mjs} +3 -3
  392. package/dist/{wordpress-slugs-ROzITIBK.mjs → wordpress-slugs-yaeD7cxn.mjs} +1 -1
  393. package/dist/{worker-CKU70ODm.mjs → worker-DdI-KtvF.mjs} +10 -10
  394. package/dist/write-intent-DuHVqks9.mjs +108 -0
  395. package/dist/{zod-generator-DkrWuID7.mjs → zod-generator-B5Pt8fv0.mjs} +2 -2
  396. package/package.json +16 -4
  397. package/dist/cache-B5NSHhxG.mjs +0 -52
  398. package/dist/cron-C7HCJPPl.mjs +0 -271
  399. package/dist/schema-CosVhHJt.mjs +0 -8
  400. package/dist/submission-DJmRejGR.mjs +0 -411
  401. package/dist/version-CISd4wX_.mjs +0 -6
  402. /package/dist/{actor-DxUAJgQX.mjs → actor-D0AW80ld.mjs} +0 -0
  403. /package/dist/{adapter-symbols-Bq3JsWGM.d.mts → adapter-symbols-B9mi-BUh.d.mts} +0 -0
  404. /package/dist/{adapters-C8nRpUuj.d.mts → adapters-lDnJjNDz.d.mts} +0 -0
  405. /package/dist/{api-tokens-0N3nafqZ.mjs → api-tokens-CdfsE9PL.mjs} +0 -0
  406. /package/dist/{base64-Cz-aU0X1.mjs → base64-qvSs0Gxy.mjs} +0 -0
  407. /package/dist/{challenge-store-DFGsDtCj.mjs → challenge-store-Dq5HiMO3.mjs} +0 -0
  408. /package/dist/{components-rFN8NH3N.mjs → components-JA6tFHmE.mjs} +0 -0
  409. /package/dist/{context-types-CPWAJRs5.mjs → context-types-DDIJhGLs.mjs} +0 -0
  410. /package/dist/{default-BS6VQRkB.mjs → default-C2azCFSB.mjs} +0 -0
  411. /package/dist/{email-console-GqK6hgMJ.mjs → email-console-BYQp_5Qr.mjs} +0 -0
  412. /package/dist/{escape-CE7xOWzJ.mjs → escape-4_NNa6GR.mjs} +0 -0
  413. /package/dist/{experimental-workflows-BbxpWwBy.mjs → experimental-workflows-CPNiI2EL.mjs} +0 -0
  414. /package/dist/{forgeway-account-DcTxh3Gw.mjs → forgeway-account-7N-3srH-.mjs} +0 -0
  415. /package/dist/{hash-D2Rqd2J2.mjs → hash-qSYPMJ8w.mjs} +0 -0
  416. /package/dist/{media-url-D9kdpoLS.mjs → media-url-D5E1a47B.mjs} +0 -0
  417. /package/dist/{mime-BnVhH671.mjs → mime-FkfazULS.mjs} +0 -0
  418. /package/dist/{mode-BJwb_MgK.mjs → mode-B_m1BGFh.mjs} +0 -0
  419. /package/dist/{normalize-aTwryvvi.mjs → normalize-DrmlLn40.mjs} +0 -0
  420. /package/dist/{oauth-authority-P5YMSk2z.mjs → oauth-authority-DVlLFhsZ.mjs} +0 -0
  421. /package/dist/{oauth-state-store-CMqLdo4I.mjs → oauth-state-store-nf-78RbK.mjs} +0 -0
  422. /package/dist/{options-JiLWB6Bt.mjs → options-yFkLUuTw.mjs} +0 -0
  423. /package/dist/{output-7HDrYTSQ.mjs → output-B1GiXeT8.mjs} +0 -0
  424. /package/dist/{parser-kettsjWc.mjs → parser-CTlxybRo.mjs} +0 -0
  425. /package/dist/{passkey-config-DVzQ3dv3.mjs → passkey-config-BLon3ct9.mjs} +0 -0
  426. /package/dist/{placeholder-DJLP_HY7.d.mts → placeholder-DdZV3I8x.d.mts} +0 -0
  427. /package/dist/{portable-text-BE7nszX6.d.mts → portable-text-HNmwL-7L.d.mts} +0 -0
  428. /package/dist/{portable-text-tQhvPLf1.mjs → portable-text-p0Ojfpfo.mjs} +0 -0
  429. /package/dist/{process-cache-C19OA3am.mjs → process-cache-CMy5M80h.mjs} +0 -0
  430. /package/dist/{provider-loader-DERzBMUz.mjs → provider-loader-DlaT1usE.mjs} +0 -0
  431. /package/dist/{public-discovery-BGyhuD5U.mjs → public-discovery-BnqYofSK.mjs} +0 -0
  432. /package/dist/{public-url-DFXUU6Wp.mjs → public-url-BHjYWuaN.mjs} +0 -0
  433. /package/dist/{public-url-sR8SVmTt.mjs → public-url-GQygrYmg.mjs} +0 -0
  434. /package/dist/{redirect-BxacnBYL.mjs → redirect-CokmLN5o.mjs} +0 -0
  435. /package/dist/{request-cache-8_ifFzVw.mjs → request-cache-CizvDoxV.mjs} +0 -0
  436. /package/dist/{resolve-DEKC4qVa.mjs → resolve-BxFGSKYu.mjs} +0 -0
  437. /package/dist/{runtime-env-CPTzh0mZ.mjs → runtime-env-DpYGy4pT.mjs} +0 -0
  438. /package/dist/{scheduled-publish-BxdShRGs.d.mts → scheduled-publish-eCNGpvNm.d.mts} +0 -0
  439. /package/dist/{seo-contributions-LEFs1d7w.mjs → seo-contributions-ZKqrqsdT.mjs} +0 -0
  440. /package/dist/{service-kQ5ljRzX.mjs → service-DeX1PRNt.mjs} +0 -0
  441. /package/dist/{session-user-B8yYh0g5.mjs → session-user-B0XMp1GC.mjs} +0 -0
  442. /package/dist/{setup-nonce-B6A5Y1ea.mjs → setup-nonce-B9IO7PbK.mjs} +0 -0
  443. /package/dist/{sidecar-client-BwPhhz-F.mjs → sidecar-client-2hx5G46s.mjs} +0 -0
  444. /package/dist/{slugify-kD31VIv2.mjs → slugify-DvoaEPtL.mjs} +0 -0
  445. /package/dist/{ssrf-C9dyjU8O.mjs → ssrf-DcD8vn3E.mjs} +0 -0
  446. /package/dist/{stable-hash-B9Tbb2f_.mjs → stable-hash-9RDJgfif.mjs} +0 -0
  447. /package/dist/{status-Bjf_uSrW.mjs → status-B2xUokyJ.mjs} +0 -0
  448. /package/dist/{transport-BrU1aDY5.mjs → transport-BK_me2MZ.mjs} +0 -0
  449. /package/dist/{transport-CZbtxgKZ.d.mts → transport-CVU5rp7W.d.mts} +0 -0
  450. /package/dist/{types-DNBL-4Sn.mjs → types-B3Uq7Czg.mjs} +0 -0
  451. /package/dist/{types-DsJTXStN.d.mts → types-BJztoTbF.d.mts} +0 -0
  452. /package/dist/{types-COvyXIp7.mjs → types-BgUxCuwu.mjs} +0 -0
  453. /package/dist/{types-KFzuijKE.d.mts → types-C0heD9oI.d.mts} +0 -0
  454. /package/dist/{types-B03h5jt_.d.mts → types-DheoByey.d.mts} +0 -0
  455. /package/dist/{types-SlLXjRpg.d.mts → types-I5LHzk_M.d.mts} +0 -0
  456. /package/dist/{types-PLJ9hlhh.mjs → types-Nm0cMxEh.mjs} +0 -0
  457. /package/dist/{types-CtGSEKEJ.d.mts → types-PxxPTFSl.d.mts} +0 -0
  458. /package/dist/{url-DGG3hw_h.mjs → url-Coamqvs4.mjs} +0 -0
  459. /package/dist/{url-DUz3LbCs.mjs → url-dn4mFfCI.mjs} +0 -0
  460. /package/dist/{workers-build-BkmPhclj.mjs → workers-build-XNBt1wGF.mjs} +0 -0
@@ -1,10 +1,13 @@
1
1
  import { atomicBatch, rowUnchanged } from "./database/batch.mjs";
2
- import { i as encodeCursor, r as decodeCursor } from "./types-RFzE_V1M.mjs";
3
- import { t as SiteActivityRepository } from "./site-activity-DU0UPDji.mjs";
4
- import { r as ReviewRequestRepository } from "./review-requests-CUVn0RBl.mjs";
5
- import { n as isSiteContextType, t as SITE_CONTEXT_TYPES } from "./context-types-CPWAJRs5.mjs";
6
- import { n as SchemaRegistry } from "./registry-Dclv9iHv.mjs";
7
- import { a as getSiteSettingsWithDb } from "./settings-DsBzKeUQ.mjs";
2
+ import { i as getContentStorageRuntime } from "./runtime-Ch5G-tnG.mjs";
3
+ import { i as encodeCursor, r as decodeCursor } from "./types-BI3ULB3A.mjs";
4
+ import { o as contentStorageHookSchema } from "./content-BNeuaVCS.mjs";
5
+ import { t as SiteActivityRepository } from "./site-activity-hpfJkmxQ.mjs";
6
+ import { r as ReviewRequestRepository } from "./review-requests-DZYM51yI.mjs";
7
+ import { t as PluginContextFactory } from "./context-Cjz0y4Al.mjs";
8
+ import { n as isSiteContextType, t as SITE_CONTEXT_TYPES } from "./context-types-DDIJhGLs.mjs";
9
+ import { n as SchemaRegistry } from "./registry-B-HULaJI.mjs";
10
+ import { a as getSiteSettingsWithDb } from "./settings-DDOB3gW1.mjs";
8
11
  import { sql } from "kysely";
9
12
  import { ulid } from "ulidx";
10
13
 
@@ -319,6 +322,975 @@ function clampLimit$1(value) {
319
322
  return Math.min(Math.max(1, value ?? 50), 100);
320
323
  }
321
324
 
325
+ //#endregion
326
+ //#region src/plugins/hooks.ts
327
+ /**
328
+ * Plugin Hooks System v2
329
+ *
330
+ * Uses the unified PluginContext for all hooks.
331
+ * Manages lifecycle hooks with:
332
+ * - Deterministic ordering via priority + dependencies
333
+ * - Timeout enforcement
334
+ * - Error isolation
335
+ * - Observability
336
+ *
337
+ */
338
+ /**
339
+ * Hook pipeline for executing hooks in order
340
+ */
341
+ var HookPipeline = class HookPipeline {
342
+ hooks = /* @__PURE__ */ new Map();
343
+ pluginMap = /* @__PURE__ */ new Map();
344
+ contextFactory = null;
345
+ /** Stored so setContextFactory can merge incrementally. */
346
+ contextFactoryOptions = {};
347
+ /** Hook names where at least one handler declared exclusive: true */
348
+ exclusiveHookNames = /* @__PURE__ */ new Set();
349
+ /**
350
+ * Selected provider plugin ID for each exclusive hook.
351
+ * Set by the PluginManager after resolution.
352
+ */
353
+ exclusiveSelections = /* @__PURE__ */ new Map();
354
+ constructor(plugins, factoryOptions) {
355
+ if (factoryOptions) {
356
+ this.contextFactory = new PluginContextFactory(factoryOptions);
357
+ this.contextFactoryOptions = { ...factoryOptions };
358
+ }
359
+ for (const plugin of plugins) this.pluginMap.set(plugin.id, plugin);
360
+ this.registerPlugins(plugins);
361
+ }
362
+ /**
363
+ * Set or update the context factory options.
364
+ *
365
+ * When called on a pipeline that already has a factory, the new options
366
+ * are merged on top of the existing ones so that callers don't need to
367
+ * repeat every field (e.g. adding `cronReschedule` without losing
368
+ * `storage` / `getUploadUrl`).
369
+ */
370
+ setContextFactory(options) {
371
+ const merged = {
372
+ ...this.contextFactoryOptions,
373
+ ...options
374
+ };
375
+ this.contextFactory = new PluginContextFactory(merged);
376
+ this.contextFactoryOptions = merged;
377
+ }
378
+ /**
379
+ * Get context for a plugin
380
+ */
381
+ getContext(pluginId) {
382
+ const plugin = this.pluginMap.get(pluginId);
383
+ if (!plugin) throw new Error(`Plugin "${pluginId}" not found`);
384
+ if (!this.contextFactory) throw new Error("Context factory not initialized - call setContextFactory first");
385
+ return this.contextFactory.createContext(plugin);
386
+ }
387
+ /**
388
+ * Get typed hooks for a specific hook name.
389
+ * The internal map stores ResolvedHook<unknown>, but we know each name
390
+ * maps to a specific handler type via HookHandlerMap.
391
+ *
392
+ * Exclusive hooks that have a selected provider are filtered out — they
393
+ * should only run via invokeExclusiveHook(), not in the regular pipeline.
394
+ */
395
+ getTypedHooks(name) {
396
+ const all = this.hooks.get(name) ?? [];
397
+ if (this.exclusiveSelections.has(name)) return all.filter((h) => !h.exclusive);
398
+ return all;
399
+ }
400
+ assertContentStorageHooks() {
401
+ this.contentStorageTargets(contentStorageHookSchema.options);
402
+ }
403
+ contentStorageTargets(names) {
404
+ return names.flatMap((name) => this.getTypedHooks(name).map((hook) => {
405
+ if (hook.idempotent !== true) throw new Error(`Plugin ${hook.pluginId} must declare ${name} idempotent and handle its event key before content storage routing can be enabled.`);
406
+ return {
407
+ hook: name,
408
+ pluginId: hook.pluginId,
409
+ timeoutMs: hook.timeout
410
+ };
411
+ }));
412
+ }
413
+ async deliverContentStorageHook(target, event) {
414
+ const hook = this.getTypedHooks(target.hook).find((value) => value.pluginId === target.pluginId);
415
+ if (!hook || hook.idempotent !== true) throw new Error("The durable content subscriber is unavailable or no longer declares idempotent delivery.");
416
+ await this.executeWithTimeout(() => hook.handler(event, this.getContext(hook.pluginId)), Math.min(target.timeoutMs, hook.timeout));
417
+ }
418
+ /**
419
+ * Register all hooks from plugins.
420
+ *
421
+ * Registers each hook name individually to preserve type safety. The
422
+ * internal map stores ResolvedHook<unknown> since it's keyed by string,
423
+ * but getTypedHooks() restores the correct handler type on retrieval.
424
+ */
425
+ registerPlugins(plugins) {
426
+ for (const plugin of plugins) {
427
+ this.registerPluginHook(plugin, "plugin:install");
428
+ this.registerPluginHook(plugin, "plugin:activate");
429
+ this.registerPluginHook(plugin, "plugin:deactivate");
430
+ this.registerPluginHook(plugin, "plugin:uninstall");
431
+ this.registerPluginHook(plugin, "content:beforeSave");
432
+ this.registerPluginHook(plugin, "content:afterSave");
433
+ this.registerPluginHook(plugin, "content:beforeDelete");
434
+ this.registerPluginHook(plugin, "content:afterDelete");
435
+ this.registerPluginHook(plugin, "content:afterPublish");
436
+ this.registerPluginHook(plugin, "content:afterUnpublish");
437
+ this.registerPluginHook(plugin, "content:afterRestore");
438
+ this.registerPluginHook(plugin, "content:afterSchedule");
439
+ this.registerPluginHook(plugin, "content:afterUnschedule");
440
+ this.registerPluginHook(plugin, "media:beforeUpload");
441
+ this.registerPluginHook(plugin, "media:afterUpload");
442
+ this.registerPluginHook(plugin, "cron");
443
+ this.registerPluginHook(plugin, "email:beforeSend");
444
+ this.registerPluginHook(plugin, "email:deliver");
445
+ this.registerPluginHook(plugin, "email:afterSend");
446
+ this.registerPluginHook(plugin, "comment:beforeCreate");
447
+ this.registerPluginHook(plugin, "comment:moderate");
448
+ this.registerPluginHook(plugin, "comment:afterCreate");
449
+ this.registerPluginHook(plugin, "comment:afterModerate");
450
+ this.registerPluginHook(plugin, "page:metadata");
451
+ this.registerPluginHook(plugin, "page:fragments");
452
+ }
453
+ for (const [hookName, hooks] of this.hooks) this.hooks.set(hookName, this.sortHooks(hooks));
454
+ }
455
+ /**
456
+ * Maps hook names to the capability required to register them.
457
+ *
458
+ * Hooks not listed here have no capability requirement (e.g. lifecycle
459
+ * hooks, cron). Any plugin declaring a listed hook without the required
460
+ * capability will have that hook silently skipped at registration time.
461
+ */
462
+ static HOOK_REQUIRED_CAPABILITY = new Map([
463
+ ["email:beforeSend", "hooks.email-events:register"],
464
+ ["email:afterSend", "hooks.email-events:register"],
465
+ ["email:deliver", "hooks.email-transport:register"],
466
+ ["content:beforeSave", "content:write"],
467
+ ["content:afterSave", "content:read"],
468
+ ["content:beforeDelete", "content:read"],
469
+ ["content:afterDelete", "content:read"],
470
+ ["content:afterPublish", "content:read"],
471
+ ["content:afterUnpublish", "content:read"],
472
+ ["content:afterRestore", "content:read"],
473
+ ["content:afterSchedule", "content:read"],
474
+ ["content:afterUnschedule", "content:read"],
475
+ ["media:beforeUpload", "media:write"],
476
+ ["media:afterUpload", "media:read"],
477
+ ["comment:beforeCreate", "users:read"],
478
+ ["comment:moderate", "users:read"],
479
+ ["comment:afterCreate", "users:read"],
480
+ ["comment:afterModerate", "users:read"],
481
+ ["page:fragments", "hooks.page-fragments:register"]
482
+ ]);
483
+ /**
484
+ * Register a single plugin's hook by name
485
+ */
486
+ registerPluginHook(plugin, name) {
487
+ const hook = plugin.hooks[name];
488
+ if (!hook) return;
489
+ const requiredCapability = HookPipeline.HOOK_REQUIRED_CAPABILITY.get(name);
490
+ if (requiredCapability && !plugin.capabilities.includes(requiredCapability)) {
491
+ console.warn(`[hooks] Plugin "${plugin.id}" declares ${name} hook without ${requiredCapability} capability — skipping`);
492
+ return;
493
+ }
494
+ if (hook.exclusive) this.exclusiveHookNames.add(name);
495
+ this.registerHook(name, hook);
496
+ }
497
+ /**
498
+ * Register a single hook
499
+ */
500
+ registerHook(name, hook) {
501
+ const existing = this.hooks.get(name) || [];
502
+ existing.push(hook);
503
+ this.hooks.set(name, existing);
504
+ }
505
+ /**
506
+ * Sort hooks by priority and dependencies
507
+ */
508
+ sortHooks(hooks) {
509
+ const sorted = [];
510
+ const remaining = [...hooks];
511
+ while (remaining.length > 0) {
512
+ const ready = remaining.filter((hook) => hook.dependencies.every((dep) => sorted.some((s) => s.pluginId === dep)));
513
+ if (ready.length === 0) {
514
+ const pluginIds = remaining.map((hook) => hook.pluginId).join(", ");
515
+ console.warn(`[hooks] Hook dependency cycle or missing dependency detected among plugins: ${pluginIds}. Falling back to priority order.`);
516
+ remaining.sort((a, b) => a.priority - b.priority);
517
+ sorted.push(...remaining);
518
+ break;
519
+ }
520
+ ready.sort((a, b) => a.priority - b.priority);
521
+ const next = ready[0];
522
+ sorted.push(next);
523
+ remaining.splice(remaining.indexOf(next), 1);
524
+ }
525
+ return sorted;
526
+ }
527
+ /**
528
+ * Execute a hook with timeout
529
+ */
530
+ async executeWithTimeout(fn, timeout) {
531
+ let timer;
532
+ const timeoutPromise = new Promise((_, reject) => {
533
+ timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Hook timeout after ${timeout}ms`)), timeout);
534
+ });
535
+ try {
536
+ return await Promise.race([fn(), timeoutPromise]);
537
+ } finally {
538
+ if (timer) clearTimeout(timer);
539
+ }
540
+ }
541
+ /**
542
+ * Run plugin:install hooks
543
+ */
544
+ async runPluginInstall(pluginId) {
545
+ return this.runLifecycleHook("plugin:install", pluginId);
546
+ }
547
+ /**
548
+ * Run plugin:activate hooks
549
+ */
550
+ async runPluginActivate(pluginId) {
551
+ return this.runLifecycleHook("plugin:activate", pluginId);
552
+ }
553
+ /**
554
+ * Run plugin:deactivate hooks
555
+ */
556
+ async runPluginDeactivate(pluginId) {
557
+ return this.runLifecycleHook("plugin:deactivate", pluginId);
558
+ }
559
+ /**
560
+ * Run plugin:uninstall hooks
561
+ */
562
+ async runPluginUninstall(pluginId, deleteData) {
563
+ const hooks = this.getTypedHooks("plugin:uninstall");
564
+ const results = [];
565
+ const hook = hooks.find((h) => h.pluginId === pluginId);
566
+ if (!hook) return results;
567
+ const { handler } = hook;
568
+ const event = { deleteData };
569
+ const ctx = this.getContext(pluginId);
570
+ const start = Date.now();
571
+ try {
572
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
573
+ results.push({
574
+ success: true,
575
+ pluginId: hook.pluginId,
576
+ duration: Date.now() - start
577
+ });
578
+ } catch (error) {
579
+ results.push({
580
+ success: false,
581
+ error: error instanceof Error ? error : new Error(String(error)),
582
+ pluginId: hook.pluginId,
583
+ duration: Date.now() - start
584
+ });
585
+ }
586
+ return results;
587
+ }
588
+ async runLifecycleHook(hookName, pluginId) {
589
+ const hooks = this.getTypedHooks(hookName);
590
+ const results = [];
591
+ const hook = hooks.find((h) => h.pluginId === pluginId);
592
+ if (!hook) return results;
593
+ const { handler } = hook;
594
+ const event = {};
595
+ const ctx = this.getContext(pluginId);
596
+ const start = Date.now();
597
+ try {
598
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
599
+ results.push({
600
+ success: true,
601
+ pluginId: hook.pluginId,
602
+ duration: Date.now() - start
603
+ });
604
+ } catch (error) {
605
+ results.push({
606
+ success: false,
607
+ error: error instanceof Error ? error : new Error(String(error)),
608
+ pluginId: hook.pluginId,
609
+ duration: Date.now() - start
610
+ });
611
+ }
612
+ return results;
613
+ }
614
+ /**
615
+ * Run content:beforeSave hooks
616
+ * Returns modified content from the pipeline
617
+ */
618
+ async runContentBeforeSave(content, collection, isNew) {
619
+ const hooks = this.getTypedHooks("content:beforeSave");
620
+ const results = [];
621
+ let currentContent = content;
622
+ for (const hook of hooks) {
623
+ const { handler } = hook;
624
+ const event = {
625
+ content: currentContent,
626
+ collection,
627
+ isNew
628
+ };
629
+ const ctx = this.getContext(hook.pluginId);
630
+ const start = Date.now();
631
+ try {
632
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
633
+ if (result !== void 0) currentContent = result;
634
+ results.push({
635
+ success: true,
636
+ value: currentContent,
637
+ pluginId: hook.pluginId,
638
+ duration: Date.now() - start
639
+ });
640
+ } catch (error) {
641
+ results.push({
642
+ success: false,
643
+ error: error instanceof Error ? error : new Error(String(error)),
644
+ pluginId: hook.pluginId,
645
+ duration: Date.now() - start
646
+ });
647
+ if (hook.errorPolicy === "abort") throw error;
648
+ }
649
+ }
650
+ return {
651
+ content: currentContent,
652
+ results
653
+ };
654
+ }
655
+ /**
656
+ * Run content:afterSave hooks
657
+ */
658
+ async runContentAfterSave(content, collection, isNew, previousContent) {
659
+ const hooks = this.getTypedHooks("content:afterSave");
660
+ const results = [];
661
+ for (const hook of hooks) {
662
+ const { handler } = hook;
663
+ const event = {
664
+ content,
665
+ collection,
666
+ isNew,
667
+ ...previousContent ? { previousContent } : {}
668
+ };
669
+ const ctx = this.getContext(hook.pluginId);
670
+ const start = Date.now();
671
+ try {
672
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
673
+ results.push({
674
+ success: true,
675
+ pluginId: hook.pluginId,
676
+ duration: Date.now() - start
677
+ });
678
+ } catch (error) {
679
+ results.push({
680
+ success: false,
681
+ error: error instanceof Error ? error : new Error(String(error)),
682
+ pluginId: hook.pluginId,
683
+ duration: Date.now() - start
684
+ });
685
+ if (hook.errorPolicy === "abort") throw error;
686
+ }
687
+ }
688
+ return results;
689
+ }
690
+ /**
691
+ * Run content:beforeDelete hooks
692
+ * Returns whether deletion is allowed
693
+ */
694
+ async runContentBeforeDelete(id, collection) {
695
+ const hooks = this.getTypedHooks("content:beforeDelete");
696
+ const results = [];
697
+ let allowed = true;
698
+ for (const hook of hooks) {
699
+ const { handler } = hook;
700
+ const event = {
701
+ id,
702
+ collection,
703
+ permanent: false
704
+ };
705
+ const ctx = this.getContext(hook.pluginId);
706
+ const start = Date.now();
707
+ try {
708
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
709
+ if (result === false) allowed = false;
710
+ results.push({
711
+ success: true,
712
+ value: result !== false,
713
+ pluginId: hook.pluginId,
714
+ duration: Date.now() - start
715
+ });
716
+ } catch (error) {
717
+ results.push({
718
+ success: false,
719
+ error: error instanceof Error ? error : new Error(String(error)),
720
+ pluginId: hook.pluginId,
721
+ duration: Date.now() - start
722
+ });
723
+ if (hook.errorPolicy === "abort") throw error;
724
+ }
725
+ }
726
+ return {
727
+ allowed,
728
+ results
729
+ };
730
+ }
731
+ /**
732
+ * Run content:afterDelete hooks
733
+ */
734
+ async runContentAfterDelete(id, collection, permanent, previousContent) {
735
+ const hooks = this.getTypedHooks("content:afterDelete");
736
+ const results = [];
737
+ for (const hook of hooks) {
738
+ const { handler } = hook;
739
+ const event = {
740
+ id,
741
+ collection,
742
+ permanent,
743
+ ...previousContent ? { previousContent } : {}
744
+ };
745
+ const ctx = this.getContext(hook.pluginId);
746
+ const start = Date.now();
747
+ try {
748
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
749
+ results.push({
750
+ success: true,
751
+ pluginId: hook.pluginId,
752
+ duration: Date.now() - start
753
+ });
754
+ } catch (error) {
755
+ results.push({
756
+ success: false,
757
+ error: error instanceof Error ? error : new Error(String(error)),
758
+ pluginId: hook.pluginId,
759
+ duration: Date.now() - start
760
+ });
761
+ if (hook.errorPolicy === "abort") throw error;
762
+ }
763
+ }
764
+ return results;
765
+ }
766
+ /**
767
+ * Run content:afterPublish hooks (fire-and-forget).
768
+ */
769
+ async runContentAfterPublish(content, collection, previousContent) {
770
+ return this.runContentStateChangeHook("content:afterPublish", content, collection, previousContent);
771
+ }
772
+ /**
773
+ * Run content:afterUnpublish hooks (fire-and-forget).
774
+ */
775
+ async runContentAfterUnpublish(content, collection, previousContent) {
776
+ return this.runContentStateChangeHook("content:afterUnpublish", content, collection, previousContent);
777
+ }
778
+ /**
779
+ * Run content:afterRestore hooks (fire-and-forget).
780
+ */
781
+ async runContentAfterRestore(content, collection) {
782
+ return this.runContentStateChangeHook("content:afterRestore", content, collection);
783
+ }
784
+ /**
785
+ * Run content:afterSchedule hooks (fire-and-forget).
786
+ */
787
+ async runContentAfterSchedule(content, collection) {
788
+ return this.runContentStateChangeHook("content:afterSchedule", content, collection);
789
+ }
790
+ /**
791
+ * Run content:afterUnschedule hooks (fire-and-forget).
792
+ */
793
+ async runContentAfterUnschedule(content, collection) {
794
+ return this.runContentStateChangeHook("content:afterUnschedule", content, collection);
795
+ }
796
+ async runContentStateChangeHook(name, content, collection, previousContent) {
797
+ const hooks = this.getTypedHooks(name);
798
+ const results = [];
799
+ for (const hook of hooks) {
800
+ const { handler } = hook;
801
+ const event = {
802
+ content,
803
+ collection,
804
+ ...previousContent ? { previousContent } : {}
805
+ };
806
+ const ctx = this.getContext(hook.pluginId);
807
+ const start = Date.now();
808
+ try {
809
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
810
+ results.push({
811
+ success: true,
812
+ pluginId: hook.pluginId,
813
+ duration: Date.now() - start
814
+ });
815
+ } catch (error) {
816
+ results.push({
817
+ success: false,
818
+ error: error instanceof Error ? error : new Error(String(error)),
819
+ pluginId: hook.pluginId,
820
+ duration: Date.now() - start
821
+ });
822
+ if (hook.errorPolicy === "abort") throw error;
823
+ }
824
+ }
825
+ return results;
826
+ }
827
+ /**
828
+ * Run media:beforeUpload hooks
829
+ */
830
+ async runMediaBeforeUpload(file) {
831
+ const hooks = this.getTypedHooks("media:beforeUpload");
832
+ const results = [];
833
+ let currentFile = file;
834
+ for (const hook of hooks) {
835
+ const { handler } = hook;
836
+ const event = { file: currentFile };
837
+ const ctx = this.getContext(hook.pluginId);
838
+ const start = Date.now();
839
+ try {
840
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
841
+ if (result !== void 0) currentFile = result;
842
+ results.push({
843
+ success: true,
844
+ value: currentFile,
845
+ pluginId: hook.pluginId,
846
+ duration: Date.now() - start
847
+ });
848
+ } catch (error) {
849
+ results.push({
850
+ success: false,
851
+ error: error instanceof Error ? error : new Error(String(error)),
852
+ pluginId: hook.pluginId,
853
+ duration: Date.now() - start
854
+ });
855
+ if (hook.errorPolicy === "abort") throw error;
856
+ }
857
+ }
858
+ return {
859
+ file: currentFile,
860
+ results
861
+ };
862
+ }
863
+ /**
864
+ * Run media:afterUpload hooks
865
+ */
866
+ async runMediaAfterUpload(media) {
867
+ const hooks = this.getTypedHooks("media:afterUpload");
868
+ const results = [];
869
+ for (const hook of hooks) {
870
+ const { handler } = hook;
871
+ const event = { media };
872
+ const ctx = this.getContext(hook.pluginId);
873
+ const start = Date.now();
874
+ try {
875
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
876
+ results.push({
877
+ success: true,
878
+ pluginId: hook.pluginId,
879
+ duration: Date.now() - start
880
+ });
881
+ } catch (error) {
882
+ results.push({
883
+ success: false,
884
+ error: error instanceof Error ? error : new Error(String(error)),
885
+ pluginId: hook.pluginId,
886
+ duration: Date.now() - start
887
+ });
888
+ if (hook.errorPolicy === "abort") throw error;
889
+ }
890
+ }
891
+ return results;
892
+ }
893
+ /**
894
+ * Invoke the cron hook for a specific plugin.
895
+ *
896
+ * Unlike other hooks which broadcast to all plugins, the cron hook is
897
+ * dispatched only to the target plugin — the one that owns the task.
898
+ */
899
+ async invokeCronHook(pluginId, event) {
900
+ const hook = this.getTypedHooks("cron").find((h) => h.pluginId === pluginId);
901
+ if (!hook) return {
902
+ success: false,
903
+ error: /* @__PURE__ */ new Error(`Plugin "${pluginId}" has no cron hook registered`),
904
+ pluginId,
905
+ duration: 0
906
+ };
907
+ const { handler } = hook;
908
+ const ctx = this.getContext(pluginId);
909
+ const start = Date.now();
910
+ try {
911
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
912
+ return {
913
+ success: true,
914
+ pluginId,
915
+ duration: Date.now() - start
916
+ };
917
+ } catch (error) {
918
+ return {
919
+ success: false,
920
+ error: error instanceof Error ? error : new Error(String(error)),
921
+ pluginId,
922
+ duration: Date.now() - start
923
+ };
924
+ }
925
+ }
926
+ /**
927
+ * Run email:beforeSend hooks (middleware pipeline).
928
+ *
929
+ * Each handler receives the message and returns a modified message or
930
+ * `false` to cancel delivery. The pipeline chains message transformations —
931
+ * each handler receives the output of the previous one.
932
+ */
933
+ async runEmailBeforeSend(message, source) {
934
+ const hooks = this.getTypedHooks("email:beforeSend");
935
+ const results = [];
936
+ let currentMessage = message;
937
+ for (const hook of hooks) {
938
+ const { handler } = hook;
939
+ const event = {
940
+ message: { ...currentMessage },
941
+ source
942
+ };
943
+ const ctx = this.getContext(hook.pluginId);
944
+ const start = Date.now();
945
+ try {
946
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
947
+ if (result === false) {
948
+ results.push({
949
+ success: true,
950
+ value: false,
951
+ pluginId: hook.pluginId,
952
+ duration: Date.now() - start
953
+ });
954
+ return {
955
+ message: false,
956
+ results
957
+ };
958
+ }
959
+ if (result && typeof result === "object") currentMessage = result;
960
+ results.push({
961
+ success: true,
962
+ value: currentMessage,
963
+ pluginId: hook.pluginId,
964
+ duration: Date.now() - start
965
+ });
966
+ } catch (error) {
967
+ results.push({
968
+ success: false,
969
+ error: error instanceof Error ? error : new Error(String(error)),
970
+ pluginId: hook.pluginId,
971
+ duration: Date.now() - start
972
+ });
973
+ if (hook.errorPolicy === "abort") throw error;
974
+ }
975
+ }
976
+ return {
977
+ message: currentMessage,
978
+ results
979
+ };
980
+ }
981
+ /**
982
+ * Run email:afterSend hooks (fire-and-forget).
983
+ *
984
+ * Errors are logged but don't propagate — they don't affect the caller.
985
+ */
986
+ async runEmailAfterSend(message, source) {
987
+ const hooks = this.getTypedHooks("email:afterSend");
988
+ const results = [];
989
+ for (const hook of hooks) {
990
+ const { handler } = hook;
991
+ const event = {
992
+ message,
993
+ source
994
+ };
995
+ const ctx = this.getContext(hook.pluginId);
996
+ const start = Date.now();
997
+ try {
998
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
999
+ results.push({
1000
+ success: true,
1001
+ pluginId: hook.pluginId,
1002
+ duration: Date.now() - start
1003
+ });
1004
+ } catch (error) {
1005
+ console.error(`[email:afterSend] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1006
+ results.push({
1007
+ success: false,
1008
+ error: error instanceof Error ? error : new Error(String(error)),
1009
+ pluginId: hook.pluginId,
1010
+ duration: Date.now() - start
1011
+ });
1012
+ }
1013
+ }
1014
+ return results;
1015
+ }
1016
+ /**
1017
+ * Run comment:beforeCreate hooks (middleware pipeline).
1018
+ *
1019
+ * Each handler receives the event and returns a modified event or
1020
+ * `false` to reject the comment. The pipeline chains transformations —
1021
+ * each handler receives the output of the previous one.
1022
+ */
1023
+ async runCommentBeforeCreate(event) {
1024
+ const hooks = this.getTypedHooks("comment:beforeCreate");
1025
+ let currentEvent = event;
1026
+ for (const hook of hooks) {
1027
+ const { handler } = hook;
1028
+ const ctx = this.getContext(hook.pluginId);
1029
+ const start = Date.now();
1030
+ try {
1031
+ const result = await this.executeWithTimeout(() => handler({ ...currentEvent }, ctx), hook.timeout);
1032
+ if (result === false) return false;
1033
+ if (result && typeof result === "object") currentEvent = result;
1034
+ } catch (error) {
1035
+ console.error(`[comment:beforeCreate] Plugin "${hook.pluginId}" error (${Date.now() - start}ms):`, error instanceof Error ? error.message : error);
1036
+ if (hook.errorPolicy === "abort") throw error;
1037
+ }
1038
+ }
1039
+ return currentEvent;
1040
+ }
1041
+ /**
1042
+ * Run comment:afterCreate hooks (fire-and-forget).
1043
+ *
1044
+ * Errors are logged but don't propagate — they don't affect the caller.
1045
+ */
1046
+ async runCommentAfterCreate(event) {
1047
+ const hooks = this.getTypedHooks("comment:afterCreate");
1048
+ for (const hook of hooks) {
1049
+ const { handler } = hook;
1050
+ const ctx = this.getContext(hook.pluginId);
1051
+ try {
1052
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1053
+ } catch (error) {
1054
+ console.error(`[comment:afterCreate] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1055
+ }
1056
+ }
1057
+ }
1058
+ /**
1059
+ * Run comment:afterModerate hooks (fire-and-forget).
1060
+ *
1061
+ * Errors are logged but don't propagate — they don't affect the caller.
1062
+ */
1063
+ async runCommentAfterModerate(event) {
1064
+ const hooks = this.getTypedHooks("comment:afterModerate");
1065
+ for (const hook of hooks) {
1066
+ const { handler } = hook;
1067
+ const ctx = this.getContext(hook.pluginId);
1068
+ try {
1069
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1070
+ } catch (error) {
1071
+ console.error(`[comment:afterModerate] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1072
+ }
1073
+ }
1074
+ }
1075
+ /**
1076
+ * Run page:metadata hooks. Each handler returns contributions that are
1077
+ * merged by the metadata collector. Errors are logged but don't propagate.
1078
+ */
1079
+ async runPageMetadata(event) {
1080
+ const hooks = this.getTypedHooks("page:metadata");
1081
+ const results = [];
1082
+ for (const hook of hooks) {
1083
+ const { handler } = hook;
1084
+ const ctx = this.getContext(hook.pluginId);
1085
+ try {
1086
+ const result = await this.executeWithTimeout(() => Promise.resolve(handler(event, ctx)), hook.timeout);
1087
+ if (result != null) {
1088
+ const contributions = Array.isArray(result) ? result : [result];
1089
+ results.push({
1090
+ pluginId: hook.pluginId,
1091
+ contributions
1092
+ });
1093
+ }
1094
+ } catch (error) {
1095
+ console.error(`[page:metadata] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1096
+ }
1097
+ }
1098
+ return results;
1099
+ }
1100
+ /**
1101
+ * Run page:fragments hooks. Only trusted plugins should be registered
1102
+ * for this hook. Errors are logged but don't propagate.
1103
+ */
1104
+ async runPageFragments(event) {
1105
+ const hooks = this.getTypedHooks("page:fragments");
1106
+ const results = [];
1107
+ for (const hook of hooks) {
1108
+ const { handler } = hook;
1109
+ const ctx = this.getContext(hook.pluginId);
1110
+ try {
1111
+ const result = await this.executeWithTimeout(() => Promise.resolve(handler(event, ctx)), hook.timeout);
1112
+ if (result != null) {
1113
+ const contributions = Array.isArray(result) ? result : [result];
1114
+ results.push({
1115
+ pluginId: hook.pluginId,
1116
+ contributions
1117
+ });
1118
+ }
1119
+ } catch (error) {
1120
+ console.error(`[page:fragments] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1121
+ }
1122
+ }
1123
+ return results;
1124
+ }
1125
+ /**
1126
+ * Check if any hooks are registered for a given name
1127
+ */
1128
+ hasHooks(name) {
1129
+ const hooks = this.hooks.get(name);
1130
+ return hooks !== void 0 && hooks.length > 0;
1131
+ }
1132
+ /**
1133
+ * Get hook count for debugging
1134
+ */
1135
+ getHookCount(name) {
1136
+ return this.hooks.get(name)?.length || 0;
1137
+ }
1138
+ /**
1139
+ * Get all registered hook names
1140
+ */
1141
+ getRegisteredHooks() {
1142
+ return [...this.hooks.keys()];
1143
+ }
1144
+ /**
1145
+ * Returns hook names where at least one handler declared exclusive: true
1146
+ */
1147
+ getRegisteredExclusiveHooks() {
1148
+ return [...this.exclusiveHookNames];
1149
+ }
1150
+ /**
1151
+ * Check if a hook is exclusive
1152
+ */
1153
+ isExclusiveHook(name) {
1154
+ return this.exclusiveHookNames.has(name);
1155
+ }
1156
+ /**
1157
+ * Set the selected provider for an exclusive hook.
1158
+ * Called by PluginManager after resolution.
1159
+ */
1160
+ setExclusiveSelection(hookName, pluginId) {
1161
+ this.exclusiveSelections.set(hookName, pluginId);
1162
+ }
1163
+ /**
1164
+ * Clear the selected provider for an exclusive hook.
1165
+ */
1166
+ clearExclusiveSelection(hookName) {
1167
+ this.exclusiveSelections.delete(hookName);
1168
+ }
1169
+ /**
1170
+ * Get the selected provider for an exclusive hook (if any).
1171
+ */
1172
+ getExclusiveSelection(hookName) {
1173
+ return this.exclusiveSelections.get(hookName);
1174
+ }
1175
+ /**
1176
+ * Get all plugins that registered a handler for a given exclusive hook.
1177
+ */
1178
+ getExclusiveHookProviders(hookName) {
1179
+ return (this.hooks.get(hookName) ?? []).filter((h) => h.exclusive).map((h) => ({ pluginId: h.pluginId }));
1180
+ }
1181
+ /**
1182
+ * Get all plugins that registered a non-exclusive handler for a given hook,
1183
+ * preserving priority order. This partitions with getExclusiveHookProviders().
1184
+ */
1185
+ getHookProviders(hookName) {
1186
+ return (this.hooks.get(hookName) ?? []).filter((h) => !h.exclusive).map((h) => ({ pluginId: h.pluginId }));
1187
+ }
1188
+ /**
1189
+ * Invoke an exclusive hook — dispatch only to the selected provider.
1190
+ * Returns null if no provider is selected or if the selected hook
1191
+ * is not found in the pipeline.
1192
+ *
1193
+ * This is a generic dispatch used by the email pipeline and other
1194
+ * exclusive hook consumers. The handler type is unknown — callers
1195
+ * must know the expected signature.
1196
+ *
1197
+ * Errors are isolated: a failing handler returns an error result
1198
+ * instead of propagating the exception to the caller.
1199
+ */
1200
+ async invokeExclusiveHook(hookName, event) {
1201
+ const selectedPluginId = this.exclusiveSelections.get(hookName);
1202
+ if (!selectedPluginId) return null;
1203
+ const hook = (this.hooks.get(hookName) ?? []).find((h) => h.pluginId === selectedPluginId && h.exclusive);
1204
+ if (!hook) return null;
1205
+ const start = Date.now();
1206
+ try {
1207
+ const ctx = this.getContext(selectedPluginId);
1208
+ const handler = hook.handler;
1209
+ return {
1210
+ result: await this.executeWithTimeout(() => handler(event, ctx), hook.timeout),
1211
+ pluginId: selectedPluginId,
1212
+ duration: Date.now() - start
1213
+ };
1214
+ } catch (error) {
1215
+ return {
1216
+ result: void 0,
1217
+ pluginId: selectedPluginId,
1218
+ error: error instanceof Error ? error : new Error(String(error)),
1219
+ duration: Date.now() - start
1220
+ };
1221
+ }
1222
+ }
1223
+ };
1224
+ /**
1225
+ * Create a hook pipeline from plugins
1226
+ */
1227
+ function createHookPipeline(plugins, factoryOptions) {
1228
+ return new HookPipeline(plugins, factoryOptions);
1229
+ }
1230
+ /** Options table key prefix for exclusive hook selections */
1231
+ const EXCLUSIVE_HOOK_KEY_PREFIX = "dineway:exclusive_hook:";
1232
+ /**
1233
+ * Resolve exclusive hook selections.
1234
+ *
1235
+ * Shared algorithm used by both PluginManager and DinewayRuntime:
1236
+ * 1. If a DB selection exists and that plugin is active → keep it.
1237
+ * 2. If DB selection is stale (plugin inactive/gone) → clear it.
1238
+ * 3. If no selection and only one active provider → auto-select it.
1239
+ * 4. If preferred hints match an active provider → first match wins.
1240
+ * 5. If multiple providers and no hint → leave unselected (admin must choose).
1241
+ */
1242
+ async function resolveExclusiveHooks(opts) {
1243
+ const { pipeline, isActive, getOption, getOptions, setOption, deleteOption, preferredHints } = opts;
1244
+ const exclusiveHookNames = pipeline.getRegisteredExclusiveHooks();
1245
+ if (exclusiveHookNames.length === 0) return;
1246
+ let currentSelections;
1247
+ if (getOptions) try {
1248
+ currentSelections = await getOptions(exclusiveHookNames.map((hookName) => `${EXCLUSIVE_HOOK_KEY_PREFIX}${hookName}`));
1249
+ } catch {
1250
+ return;
1251
+ }
1252
+ for (const hookName of exclusiveHookNames) {
1253
+ const providers = pipeline.getExclusiveHookProviders(hookName);
1254
+ const activeProviderIds = new Set(providers.map((p) => p.pluginId).filter((id) => isActive(id)));
1255
+ const key = `${EXCLUSIVE_HOOK_KEY_PREFIX}${hookName}`;
1256
+ let currentSelection = null;
1257
+ if (currentSelections) currentSelection = currentSelections.get(key) ?? null;
1258
+ else try {
1259
+ currentSelection = await getOption(key);
1260
+ } catch {
1261
+ continue;
1262
+ }
1263
+ if (currentSelection && activeProviderIds.has(currentSelection)) {
1264
+ pipeline.setExclusiveSelection(hookName, currentSelection);
1265
+ continue;
1266
+ }
1267
+ if (currentSelection) try {
1268
+ await deleteOption(key);
1269
+ } catch {}
1270
+ if (activeProviderIds.size === 1) {
1271
+ const [onlyProvider] = activeProviderIds;
1272
+ try {
1273
+ await setOption(key, onlyProvider);
1274
+ } catch {}
1275
+ pipeline.setExclusiveSelection(hookName, onlyProvider);
1276
+ continue;
1277
+ }
1278
+ if (preferredHints) {
1279
+ let found = false;
1280
+ for (const [pluginId, hooks] of preferredHints) if (hooks.includes(hookName) && activeProviderIds.has(pluginId)) {
1281
+ try {
1282
+ await setOption(key, pluginId);
1283
+ } catch {}
1284
+ pipeline.setExclusiveSelection(hookName, pluginId);
1285
+ found = true;
1286
+ break;
1287
+ }
1288
+ if (found) continue;
1289
+ }
1290
+ pipeline.clearExclusiveSelection(hookName);
1291
+ }
1292
+ }
1293
+
322
1294
  //#endregion
323
1295
  //#region src/plugins/state.ts
324
1296
  function toPluginStatus(value) {
@@ -587,6 +1559,22 @@ async function handlePluginGet(db, configuredPlugins, sandboxedPluginEntries, pl
587
1559
  */
588
1560
  async function handlePluginEnable(db, configuredPlugins, sandboxedPluginEntries, pluginId) {
589
1561
  try {
1562
+ const routing = getContentStorageRuntime(db)?.config;
1563
+ if (routing && Object.keys(routing.rules).length) {
1564
+ const candidate = configuredPlugins.find((plugin) => plugin.id === pluginId);
1565
+ try {
1566
+ if (candidate) new HookPipeline([candidate], { db }).assertContentStorageHooks();
1567
+ else if (sandboxedPluginEntries.some((plugin) => plugin.id === pluginId)) throw new Error("Sandboxed plugins are not supported with content storage routing.");
1568
+ } catch {
1569
+ return {
1570
+ success: false,
1571
+ error: {
1572
+ code: "PLUGIN_INCOMPATIBLE",
1573
+ message: "This plugin does not declare safe retry support for content storage routing. Update the plugin before enabling it."
1574
+ }
1575
+ };
1576
+ }
1577
+ }
590
1578
  const stateRepo = new PluginStateRepository(db);
591
1579
  const plugin = configuredPlugins.find((p) => p.id === pluginId);
592
1580
  if (plugin) return {
@@ -1360,4 +2348,4 @@ function isCollectionSlug(value) {
1360
2348
  }
1361
2349
 
1362
2350
  //#endregion
1363
- export { selectActiveBriefingContextEntries as a, handlePluginGet as c, ContextRepository as d, parseSiteBriefingScope as i, handlePluginList as l, SiteBriefingError as n, handlePluginDisable as o, formatSiteBriefingText as r, handlePluginEnable as s, SiteBriefingAssembler as t, PluginStateRepository as u };
2351
+ export { selectActiveBriefingContextEntries as a, handlePluginGet as c, HookPipeline as d, createHookPipeline as f, parseSiteBriefingScope as i, handlePluginList as l, ContextRepository as m, SiteBriefingError as n, handlePluginDisable as o, resolveExclusiveHooks as p, formatSiteBriefingText as r, handlePluginEnable as s, SiteBriefingAssembler as t, PluginStateRepository as u };