emdash 0.40.0 → 0.41.0

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 (1258) hide show
  1. package/dist/action-token-CbKDcPJi.mjs +26 -0
  2. package/dist/action-token-CbKDcPJi.mjs.map +1 -0
  3. package/dist/activation-PtniBLt9.mjs +382 -0
  4. package/dist/activation-PtniBLt9.mjs.map +1 -0
  5. package/dist/adapters-C_Tf5x90.d.mts +171 -0
  6. package/dist/adapters-C_Tf5x90.d.mts.map +1 -0
  7. package/dist/allowed-origins-U1z4TdEZ.mjs +116 -0
  8. package/dist/allowed-origins-U1z4TdEZ.mjs.map +1 -0
  9. package/dist/api/route-utils.d.mts +4 -4
  10. package/dist/api/route-utils.mjs +46 -45
  11. package/dist/api/route-utils.mjs.map +1 -1
  12. package/dist/api/schemas/index.d.mts +2 -2
  13. package/dist/api/schemas/index.mjs +10 -10
  14. package/dist/api-CXwQkV_m.mjs +5122 -0
  15. package/dist/api-CXwQkV_m.mjs.map +1 -0
  16. package/dist/api-tokens-89WlohEN.mjs +166 -0
  17. package/dist/api-tokens-89WlohEN.mjs.map +1 -0
  18. package/dist/apply-Do3KNnUk.mjs +1659 -0
  19. package/dist/apply-Do3KNnUk.mjs.map +1 -0
  20. package/dist/approvals-CAX9Yw33.mjs +460 -0
  21. package/dist/approvals-CAX9Yw33.mjs.map +1 -0
  22. package/dist/artifact-fetch-B9W4CEST.mjs +659 -0
  23. package/dist/artifact-fetch-B9W4CEST.mjs.map +1 -0
  24. package/dist/astro/index.d.mts +14 -14
  25. package/dist/astro/index.mjs +26 -30
  26. package/dist/astro/index.mjs.map +1 -1
  27. package/dist/astro/middleware/auth.d.mts +12 -12
  28. package/dist/astro/middleware/auth.mjs +10 -10
  29. package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
  30. package/dist/astro/middleware/redirect.mjs +7 -7
  31. package/dist/astro/middleware/request-context.mjs +3 -3
  32. package/dist/astro/middleware/setup.mjs +1 -1
  33. package/dist/astro/middleware.d.mts +12 -12
  34. package/dist/astro/middleware.d.mts.map +1 -1
  35. package/dist/astro/middleware.mjs +110 -106
  36. package/dist/astro/middleware.mjs.map +1 -1
  37. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +14 -14
  38. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +14 -14
  39. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +6 -6
  40. package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
  41. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +7 -7
  42. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +17 -17
  43. package/dist/astro/routes/api/admin/byline-fields/index.mjs +17 -17
  44. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +17 -17
  45. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +23 -23
  46. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +23 -23
  47. package/dist/astro/routes/api/admin/bylines/index.mjs +23 -23
  48. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +18 -18
  49. package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -7
  50. package/dist/astro/routes/api/admin/comments/bulk.mjs +17 -17
  51. package/dist/astro/routes/api/admin/comments/counts.mjs +7 -7
  52. package/dist/astro/routes/api/admin/comments/index.mjs +17 -17
  53. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
  54. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
  55. package/dist/astro/routes/api/admin/media-usage/activation.mjs +20 -20
  56. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +22 -22
  57. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +22 -22
  58. package/dist/astro/routes/api/admin/media-usage/progress.mjs +25 -25
  59. package/dist/astro/routes/api/admin/media-usage/repair.mjs +31 -31
  60. package/dist/astro/routes/api/admin/media-usage/work/index.mjs +22 -22
  61. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +22 -22
  62. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
  63. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
  64. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +8 -8
  65. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +8 -8
  66. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +72 -68
  67. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  68. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +7 -7
  69. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +71 -67
  70. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +72 -68
  72. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +82 -78
  74. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  75. package/dist/astro/routes/api/admin/plugins/index.mjs +72 -68
  76. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  77. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +5 -5
  78. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -67
  79. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +81 -77
  81. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -67
  83. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +72 -68
  85. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +83 -79
  87. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +9 -9
  89. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +74 -70
  90. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  91. package/dist/astro/routes/api/admin/plugins/registry/publisher-handle.mjs +7 -7
  92. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +72 -68
  93. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -67
  95. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +6 -6
  97. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -67
  98. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  99. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +5 -5
  100. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -67
  101. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  102. package/dist/astro/routes/api/admin/transfer/_...path_.mjs +4 -4
  103. package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +40 -40
  104. package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +40 -40
  105. package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +42 -42
  106. package/dist/astro/routes/api/admin/transfer/capabilities.mjs +42 -42
  107. package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +42 -42
  108. package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +43 -43
  109. package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +43 -43
  110. package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +42 -42
  111. package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +43 -43
  112. package/dist/astro/routes/api/admin/transfer/exports/index.mjs +44 -44
  113. package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +42 -42
  114. package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +42 -42
  115. package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +44 -44
  116. package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +42 -42
  117. package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +44 -44
  118. package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +42 -42
  119. package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +42 -42
  120. package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +44 -44
  121. package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +42 -42
  122. package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +42 -42
  123. package/dist/astro/routes/api/admin/transfer/imports/index.mjs +44 -44
  124. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +5 -5
  125. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +4 -4
  126. package/dist/astro/routes/api/admin/users/_id_/index.mjs +15 -15
  127. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +6 -6
  128. package/dist/astro/routes/api/admin/users/index.mjs +14 -14
  129. package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
  130. package/dist/astro/routes/api/auth/invite/accept.mjs +4 -4
  131. package/dist/astro/routes/api/auth/invite/complete.mjs +18 -18
  132. package/dist/astro/routes/api/auth/invite/index.mjs +16 -16
  133. package/dist/astro/routes/api/auth/invite/register-options.mjs +17 -17
  134. package/dist/astro/routes/api/auth/logout.mjs +5 -5
  135. package/dist/astro/routes/api/auth/magic-link/send.mjs +18 -18
  136. package/dist/astro/routes/api/auth/magic-link/verify.mjs +14 -14
  137. package/dist/astro/routes/api/auth/me.mjs +15 -15
  138. package/dist/astro/routes/api/auth/mode.mjs +5 -5
  139. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  140. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  141. package/dist/astro/routes/api/auth/passkey/_id_.mjs +14 -14
  142. package/dist/astro/routes/api/auth/passkey/index.mjs +4 -4
  143. package/dist/astro/routes/api/auth/passkey/options.mjs +19 -19
  144. package/dist/astro/routes/api/auth/passkey/register/options.mjs +17 -17
  145. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +18 -18
  146. package/dist/astro/routes/api/auth/passkey/verify.mjs +18 -18
  147. package/dist/astro/routes/api/auth/signup/complete.mjs +18 -18
  148. package/dist/astro/routes/api/auth/signup/request.mjs +17 -17
  149. package/dist/astro/routes/api/auth/signup/verify.mjs +4 -4
  150. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
  151. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +18 -18
  152. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +5 -5
  153. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +17 -17
  154. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
  155. package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +17 -17
  156. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
  157. package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +11 -11
  158. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +31 -31
  159. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +17 -17
  160. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts +1 -2
  161. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts.map +1 -1
  162. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +42 -53
  163. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  164. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +34 -29
  165. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  166. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
  167. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +5 -5
  168. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +17 -17
  169. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +25 -24
  170. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  171. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +5 -5
  172. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +17 -17
  173. package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
  174. package/dist/astro/routes/api/content/_collection_/_id_.mjs +18 -18
  175. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  176. package/dist/astro/routes/api/content/_collection_/authors.mjs +5 -5
  177. package/dist/astro/routes/api/content/_collection_/index.mjs +15 -15
  178. package/dist/astro/routes/api/content/_collection_/trash.mjs +15 -15
  179. package/dist/astro/routes/api/dashboard.mjs +10 -9
  180. package/dist/astro/routes/api/dashboard.mjs.map +1 -1
  181. package/dist/astro/routes/api/dev/emails.mjs +5 -5
  182. package/dist/astro/routes/api/health.mjs +6 -6
  183. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  184. package/dist/astro/routes/api/import/probe.mjs +23 -23
  185. package/dist/astro/routes/api/import/wordpress/analyze.mjs +6 -6
  186. package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -13
  187. package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -16
  188. package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -12
  189. package/dist/astro/routes/api/import/wordpress/media.mjs +19 -19
  190. package/dist/astro/routes/api/import/wordpress/prepare.mjs +18 -18
  191. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -13
  192. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +28 -28
  193. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  194. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +23 -23
  195. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -13
  196. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +34 -34
  197. package/dist/astro/routes/api/manifest.mjs +6 -6
  198. package/dist/astro/routes/api/mcp.mjs +98 -118
  199. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  200. package/dist/astro/routes/api/media/_id_/confirm.mjs +19 -19
  201. package/dist/astro/routes/api/media/_id_/replace.mjs +16 -16
  202. package/dist/astro/routes/api/media/_id_/upload.mjs +9 -9
  203. package/dist/astro/routes/api/media/_id_/usage.mjs +33 -33
  204. package/dist/astro/routes/api/media/_id_.mjs +31 -31
  205. package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +6 -6
  206. package/dist/astro/routes/api/media/file/_...key_.mjs +9 -9
  207. package/dist/astro/routes/api/media/folders/_id_.mjs +16 -16
  208. package/dist/astro/routes/api/media/folders/index.mjs +16 -16
  209. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +5 -5
  210. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +5 -5
  211. package/dist/astro/routes/api/media/providers/index.mjs +5 -5
  212. package/dist/astro/routes/api/media/upload-url.mjs +18 -18
  213. package/dist/astro/routes/api/media.mjs +35 -35
  214. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +17 -17
  215. package/dist/astro/routes/api/menus/_name_/items.mjs +17 -17
  216. package/dist/astro/routes/api/menus/_name_/reorder.mjs +17 -17
  217. package/dist/astro/routes/api/menus/_name_/translations.mjs +17 -17
  218. package/dist/astro/routes/api/menus/_name_.mjs +17 -17
  219. package/dist/astro/routes/api/menus/index.mjs +17 -17
  220. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  221. package/dist/astro/routes/api/oauth/device/authorize.d.mts +2 -1
  222. package/dist/astro/routes/api/oauth/device/authorize.d.mts.map +1 -1
  223. package/dist/astro/routes/api/oauth/device/authorize.mjs +23 -9
  224. package/dist/astro/routes/api/oauth/device/authorize.mjs.map +1 -1
  225. package/dist/astro/routes/api/oauth/device/code.mjs +11 -11
  226. package/dist/astro/routes/api/oauth/device/token.mjs +10 -10
  227. package/dist/astro/routes/api/oauth/register.mjs +5 -5
  228. package/dist/astro/routes/api/oauth/token/refresh.mjs +8 -8
  229. package/dist/astro/routes/api/oauth/token/revoke.mjs +8 -8
  230. package/dist/astro/routes/api/oauth/token.mjs +8 -8
  231. package/dist/astro/routes/api/openapi.json.mjs +20 -20
  232. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +11 -11
  233. package/dist/astro/routes/api/redirects/404s/index.mjs +19 -19
  234. package/dist/astro/routes/api/redirects/404s/summary.mjs +19 -19
  235. package/dist/astro/routes/api/redirects/_id_.mjs +19 -19
  236. package/dist/astro/routes/api/redirects/index.mjs +19 -19
  237. package/dist/astro/routes/api/relations/_id_/index.mjs +34 -29
  238. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  239. package/dist/astro/routes/api/relations/index.mjs +36 -31
  240. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  241. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +5 -5
  242. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
  243. package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +71 -67
  244. package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs.map +1 -1
  245. package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +71 -67
  246. package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs.map +1 -1
  247. package/dist/astro/routes/api/schema/block-types/index.mjs +71 -67
  248. package/dist/astro/routes/api/schema/block-types/index.mjs.map +1 -1
  249. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -69
  250. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  251. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +71 -67
  252. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  253. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +71 -67
  254. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  255. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +71 -67
  256. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  257. package/dist/astro/routes/api/schema/collections/index.mjs +71 -67
  258. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  259. package/dist/astro/routes/api/schema/collections/reorder.mjs +71 -67
  260. package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
  261. package/dist/astro/routes/api/schema/index.mjs +16 -16
  262. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -67
  263. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  264. package/dist/astro/routes/api/schema/orphans/index.mjs +71 -67
  265. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  266. package/dist/astro/routes/api/search/enable.mjs +19 -19
  267. package/dist/astro/routes/api/search/index.mjs +18 -18
  268. package/dist/astro/routes/api/search/rebuild.mjs +19 -19
  269. package/dist/astro/routes/api/search/stats.mjs +9 -9
  270. package/dist/astro/routes/api/search/suggest.mjs +18 -18
  271. package/dist/astro/routes/api/sections/_slug_.mjs +18 -18
  272. package/dist/astro/routes/api/sections/index.mjs +18 -18
  273. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -7
  274. package/dist/astro/routes/api/settings/backups/archives/index.mjs +7 -7
  275. package/dist/astro/routes/api/settings/backups/export.mjs +7 -7
  276. package/dist/astro/routes/api/settings/backups/index.mjs +8 -8
  277. package/dist/astro/routes/api/settings/email.mjs +6 -6
  278. package/dist/astro/routes/api/settings.mjs +21 -21
  279. package/dist/astro/routes/api/setup/admin-verify.mjs +19 -19
  280. package/dist/astro/routes/api/setup/admin.mjs +18 -18
  281. package/dist/astro/routes/api/setup/dev-bypass.mjs +45 -39
  282. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  283. package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
  284. package/dist/astro/routes/api/setup/index.d.mts.map +1 -1
  285. package/dist/astro/routes/api/setup/index.mjs +80 -49
  286. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  287. package/dist/astro/routes/api/setup/status.mjs +6 -6
  288. package/dist/astro/routes/api/snapshot.mjs +9 -9
  289. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  290. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +23 -23
  291. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -23
  292. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +23 -23
  293. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +23 -23
  294. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +22 -22
  295. package/dist/astro/routes/api/taxonomies/_name_.mjs +23 -23
  296. package/dist/astro/routes/api/taxonomies/bulk-tag.mjs +36 -35
  297. package/dist/astro/routes/api/taxonomies/bulk-tag.mjs.map +1 -1
  298. package/dist/astro/routes/api/taxonomies/index.mjs +23 -23
  299. package/dist/astro/routes/api/themes/preview.mjs +6 -6
  300. package/dist/astro/routes/api/typegen.mjs +8 -8
  301. package/dist/astro/routes/api/visual-editing/action-token.mjs +6 -6
  302. package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +19 -19
  303. package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +4 -4
  304. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  305. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  306. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  307. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +16 -16
  308. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +19 -19
  309. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +19 -19
  310. package/dist/astro/routes/api/widget-areas/_name_.mjs +9 -9
  311. package/dist/astro/routes/api/widget-areas/index.mjs +19 -19
  312. package/dist/astro/routes/api/widget-components.mjs +5 -5
  313. package/dist/astro/routes/robots.txt.mjs +6 -6
  314. package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
  315. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  316. package/dist/astro/types.d.mts +28 -18
  317. package/dist/astro/types.d.mts.map +1 -1
  318. package/dist/audit-CrgmE9LE.mjs +127 -0
  319. package/dist/audit-CrgmE9LE.mjs.map +1 -0
  320. package/dist/auth/providers/github.d.mts +1 -1
  321. package/dist/auth/providers/google.d.mts +1 -1
  322. package/dist/authoritative-records-C2YzIdbu.mjs +5172 -0
  323. package/dist/authoritative-records-C2YzIdbu.mjs.map +1 -0
  324. package/dist/authorize-WgdKF8QY.mjs +49 -0
  325. package/dist/authorize-WgdKF8QY.mjs.map +1 -0
  326. package/dist/backup-Ck8_lMO3.mjs +246 -0
  327. package/dist/backup-Ck8_lMO3.mjs.map +1 -0
  328. package/dist/block-types-BQ90asVI.mjs +132 -0
  329. package/dist/block-types-BQ90asVI.mjs.map +1 -0
  330. package/dist/block-values-ACFqgB1D.mjs +175 -0
  331. package/dist/block-values-ACFqgB1D.mjs.map +1 -0
  332. package/dist/bundle-Db1iNMv_.mjs +667 -0
  333. package/dist/bundle-Db1iNMv_.mjs.map +1 -0
  334. package/dist/byline-BayaYGoj.mjs +909 -0
  335. package/dist/byline-BayaYGoj.mjs.map +1 -0
  336. package/dist/byline-fields-B8HH-35f.mjs +254 -0
  337. package/dist/byline-fields-B8HH-35f.mjs.map +1 -0
  338. package/dist/byline-fields-hMPjf6Eu.mjs +123 -0
  339. package/dist/byline-fields-hMPjf6Eu.mjs.map +1 -0
  340. package/dist/byline-registry-B_EK_TQf.mjs +406 -0
  341. package/dist/byline-registry-B_EK_TQf.mjs.map +1 -0
  342. package/dist/bylines-DFAaFXWi.mjs +214 -0
  343. package/dist/bylines-DFAaFXWi.mjs.map +1 -0
  344. package/dist/bylines-DkIxUxmr.mjs +232 -0
  345. package/dist/bylines-DkIxUxmr.mjs.map +1 -0
  346. package/dist/cache-DkvhQ8XE.mjs +108 -0
  347. package/dist/cache-DkvhQ8XE.mjs.map +1 -0
  348. package/dist/canonical-CcSuuTlH.mjs +174 -0
  349. package/dist/canonical-CcSuuTlH.mjs.map +1 -0
  350. package/dist/capture-triggers-DJEoOTOq.mjs +362 -0
  351. package/dist/capture-triggers-DJEoOTOq.mjs.map +1 -0
  352. package/dist/challenge-store-CvBl81AQ.mjs +51 -0
  353. package/dist/challenge-store-CvBl81AQ.mjs.map +1 -0
  354. package/dist/checksum-CClweQzI.mjs +162 -0
  355. package/dist/checksum-CClweQzI.mjs.map +1 -0
  356. package/dist/chrome-tags-D5caJwwp.mjs +24 -0
  357. package/dist/chrome-tags-D5caJwwp.mjs.map +1 -0
  358. package/dist/chunks-DwBaj8aT.mjs +25 -0
  359. package/dist/chunks-DwBaj8aT.mjs.map +1 -0
  360. package/dist/cli/index.mjs +374 -761
  361. package/dist/cli/index.mjs.map +1 -1
  362. package/dist/client/cf-access.d.mts +1 -1
  363. package/dist/client/index.d.mts +18 -18
  364. package/dist/client/index.mjs +2 -2
  365. package/dist/collection-deletion-CLCdXsnV.mjs +436 -0
  366. package/dist/collection-deletion-CLCdXsnV.mjs.map +1 -0
  367. package/dist/collection-deletion-processor-hNw8x01F.mjs +217 -0
  368. package/dist/collection-deletion-processor-hNw8x01F.mjs.map +1 -0
  369. package/dist/collection-slugs-cache-CUuiduLq.mjs +85 -0
  370. package/dist/collection-slugs-cache-CUuiduLq.mjs.map +1 -0
  371. package/dist/comment-D2uvL63j.mjs +313 -0
  372. package/dist/comment-D2uvL63j.mjs.map +1 -0
  373. package/dist/comment-reaction-DevUuzg4.mjs +85 -0
  374. package/dist/comment-reaction-DevUuzg4.mjs.map +1 -0
  375. package/dist/comments-Cq0s7_hO.mjs +195 -0
  376. package/dist/comments-Cq0s7_hO.mjs.map +1 -0
  377. package/dist/comments-M4EDYAHw.mjs +99 -0
  378. package/dist/comments-M4EDYAHw.mjs.map +1 -0
  379. package/dist/components-CuIGwXMs.mjs +108 -0
  380. package/dist/components-CuIGwXMs.mjs.map +1 -0
  381. package/dist/config-52Ea5IWt.d.mts +39 -0
  382. package/dist/config-52Ea5IWt.d.mts.map +1 -0
  383. package/dist/config-CCz3xOLc.mjs +242 -0
  384. package/dist/config-CCz3xOLc.mjs.map +1 -0
  385. package/dist/config-D3d5Qudq.d.mts +6669 -0
  386. package/dist/config-D3d5Qudq.d.mts.map +1 -0
  387. package/dist/content-CbnufDsM.mjs +2018 -0
  388. package/dist/content-CbnufDsM.mjs.map +1 -0
  389. package/dist/content-list-query-D_7B1FE5.d.mts +26 -0
  390. package/dist/content-list-query-D_7B1FE5.d.mts.map +1 -0
  391. package/dist/content-policy-CYu6K1KB.mjs +46 -0
  392. package/dist/content-policy-CYu6K1KB.mjs.map +1 -0
  393. package/dist/content-repair-DlDUgFGp.mjs +442 -0
  394. package/dist/content-repair-DlDUgFGp.mjs.map +1 -0
  395. package/dist/context-CGQLA1-a.mjs +1922 -0
  396. package/dist/context-CGQLA1-a.mjs.map +1 -0
  397. package/dist/cron-c4D5C5Fx.mjs +284 -0
  398. package/dist/cron-c4D5C5Fx.mjs.map +1 -0
  399. package/dist/dashboard-CBq9kmOn.mjs +151 -0
  400. package/dist/dashboard-CBq9kmOn.mjs.map +1 -0
  401. package/dist/db/index.d.mts +3 -3
  402. package/dist/db/index.mjs +1 -1
  403. package/dist/db/libsql-migrations.d.mts +1 -1
  404. package/dist/db/libsql-migrations.mjs +4 -4
  405. package/dist/db/libsql.d.mts +1 -1
  406. package/dist/db/postgres-migrations.d.mts +1 -1
  407. package/dist/db/postgres-migrations.mjs +4 -4
  408. package/dist/db/postgres.d.mts +1 -1
  409. package/dist/db/sqlite-migrations.d.mts +1 -1
  410. package/dist/db/sqlite-migrations.mjs +4 -4
  411. package/dist/db/sqlite.d.mts +1 -1
  412. package/dist/db/sqlite.mjs +1 -1
  413. package/dist/default-DPsys51U.mjs +81 -0
  414. package/dist/default-DPsys51U.mjs.map +1 -0
  415. package/dist/deferred-tasks-CZ7rzBdo.d.mts +9 -0
  416. package/dist/deferred-tasks-CZ7rzBdo.d.mts.map +1 -0
  417. package/dist/dev-typegen-HRxwLRcT.mjs +29 -0
  418. package/dist/dev-typegen-HRxwLRcT.mjs.map +1 -0
  419. package/dist/device-flow-OcSqE9uY.mjs +521 -0
  420. package/dist/device-flow-OcSqE9uY.mjs.map +1 -0
  421. package/dist/digest-DVZ--cE9.mjs +194 -0
  422. package/dist/digest-DVZ--cE9.mjs.map +1 -0
  423. package/dist/direct-executor-DyjAqkpT.mjs +104 -0
  424. package/dist/direct-executor-DyjAqkpT.mjs.map +1 -0
  425. package/dist/dist-FPR93_xf.mjs +810 -0
  426. package/dist/dist-FPR93_xf.mjs.map +1 -0
  427. package/dist/email-console-DyQIgEnz.mjs +50 -0
  428. package/dist/email-console-DyQIgEnz.mjs.map +1 -0
  429. package/dist/email-locale-BYb16rVd.mjs +25 -0
  430. package/dist/email-locale-BYb16rVd.mjs.map +1 -0
  431. package/dist/emdash-runtime-CrzxJFmF.mjs +4214 -0
  432. package/dist/emdash-runtime-CrzxJFmF.mjs.map +1 -0
  433. package/dist/enrich-DBtCncE2.mjs +194 -0
  434. package/dist/enrich-DBtCncE2.mjs.map +1 -0
  435. package/dist/entry-lock-BN5y4YbO.d.mts +4481 -0
  436. package/dist/entry-lock-BN5y4YbO.d.mts.map +1 -0
  437. package/dist/entry-lock-BaRBHCsH.mjs +1173 -0
  438. package/dist/entry-lock-BaRBHCsH.mjs.map +1 -0
  439. package/dist/entry-lock-C6NcnZPV.mjs +163 -0
  440. package/dist/entry-lock-C6NcnZPV.mjs.map +1 -0
  441. package/dist/entry-locks-BTyQLdbC.mjs +167 -0
  442. package/dist/entry-locks-BTyQLdbC.mjs.map +1 -0
  443. package/dist/error-BfsNNrIE.mjs +90 -0
  444. package/dist/error-BfsNNrIE.mjs.map +1 -0
  445. package/dist/errors-BN1QAnEY.mjs +460 -0
  446. package/dist/errors-BN1QAnEY.mjs.map +1 -0
  447. package/dist/errors-Bt3goF8I.mjs +120 -0
  448. package/dist/errors-Bt3goF8I.mjs.map +1 -0
  449. package/dist/escape-BveidMa2.mjs +9 -0
  450. package/dist/escape-BveidMa2.mjs.map +1 -0
  451. package/dist/fence-Bb_IbCxI.mjs +162 -0
  452. package/dist/fence-Bb_IbCxI.mjs.map +1 -0
  453. package/dist/field-defs-cache-CsZctvbu.mjs +77 -0
  454. package/dist/field-defs-cache-CsZctvbu.mjs.map +1 -0
  455. package/dist/field-map-6m9rF49t.mjs +83 -0
  456. package/dist/field-map-6m9rF49t.mjs.map +1 -0
  457. package/dist/focal-point-CZ3d1wK5.mjs +23 -0
  458. package/dist/focal-point-CZ3d1wK5.mjs.map +1 -0
  459. package/dist/fts-manager-CCaZTp8y.mjs +443 -0
  460. package/dist/fts-manager-CCaZTp8y.mjs.map +1 -0
  461. package/dist/gc-xowRjczI.mjs +75 -0
  462. package/dist/gc-xowRjczI.mjs.map +1 -0
  463. package/dist/hash-COVK27Pc.mjs +37 -0
  464. package/dist/hash-COVK27Pc.mjs.map +1 -0
  465. package/dist/hook-result-CYSk0XFe.d.mts +31 -0
  466. package/dist/hook-result-CYSk0XFe.d.mts.map +1 -0
  467. package/dist/hreflang-CChPV7jx.mjs +105 -0
  468. package/dist/hreflang-CChPV7jx.mjs.map +1 -0
  469. package/dist/hreflang-DRslq3QI.d.mts +50 -0
  470. package/dist/hreflang-DRslq3QI.d.mts.map +1 -0
  471. package/dist/http-route-dispatch-CAdp2onn.mjs +339 -0
  472. package/dist/http-route-dispatch-CAdp2onn.mjs.map +1 -0
  473. package/dist/identity-NVTOOQyq.mjs +35 -0
  474. package/dist/identity-NVTOOQyq.mjs.map +1 -0
  475. package/dist/import-wpSO2N0x.mjs +2020 -0
  476. package/dist/import-wpSO2N0x.mjs.map +1 -0
  477. package/dist/index-CDs2wq4X.d.mts +623 -0
  478. package/dist/index-CDs2wq4X.d.mts.map +1 -0
  479. package/dist/index.d.mts +24 -24
  480. package/dist/index.mjs +103 -101
  481. package/dist/install-finalization-D9R9R-W8.mjs +58 -0
  482. package/dist/install-finalization-D9R9R-W8.mjs.map +1 -0
  483. package/dist/keys-Bck6LBfF.mjs +61 -0
  484. package/dist/keys-Bck6LBfF.mjs.map +1 -0
  485. package/dist/kinds-CYmRESWj.mjs +974 -0
  486. package/dist/kinds-CYmRESWj.mjs.map +1 -0
  487. package/dist/lifecycle-C815ZQfV.mjs +25 -0
  488. package/dist/lifecycle-C815ZQfV.mjs.map +1 -0
  489. package/dist/load-D99axixL.mjs +28 -0
  490. package/dist/load-D99axixL.mjs.map +1 -0
  491. package/dist/loader-CrRPfkHS.mjs +1197 -0
  492. package/dist/loader-CrRPfkHS.mjs.map +1 -0
  493. package/dist/loops-DMKlygqX.mjs +203 -0
  494. package/dist/loops-DMKlygqX.mjs.map +1 -0
  495. package/dist/manifest-builder-BQzCHNgB.mjs +189 -0
  496. package/dist/manifest-builder-BQzCHNgB.mjs.map +1 -0
  497. package/dist/manifest-schema-Ci2gmd0u.mjs +492 -0
  498. package/dist/manifest-schema-Ci2gmd0u.mjs.map +1 -0
  499. package/dist/media/image-endpoint.mjs +1 -1
  500. package/dist/media/index.d.mts +1 -1
  501. package/dist/media/index.mjs +4 -4
  502. package/dist/media/local-runtime.d.mts +14 -14
  503. package/dist/media/local-runtime.mjs +6 -6
  504. package/dist/media-BUQePMxP.mjs +373 -0
  505. package/dist/media-BUQePMxP.mjs.map +1 -0
  506. package/dist/media-DH8ibNlY.mjs +294 -0
  507. package/dist/media-DH8ibNlY.mjs.map +1 -0
  508. package/dist/media-OEIQ3bVc.mjs +408 -0
  509. package/dist/media-OEIQ3bVc.mjs.map +1 -0
  510. package/dist/media-allowlist-pYtaBA95.mjs +44 -0
  511. package/dist/media-allowlist-pYtaBA95.mjs.map +1 -0
  512. package/dist/media-folders-Bf8_s4de.mjs +210 -0
  513. package/dist/media-folders-Bf8_s4de.mjs.map +1 -0
  514. package/dist/media-url-C6klEuNd.mjs +43 -0
  515. package/dist/media-url-C6klEuNd.mjs.map +1 -0
  516. package/dist/media-usage-D7Y64m6v.mjs +1629 -0
  517. package/dist/media-usage-D7Y64m6v.mjs.map +1 -0
  518. package/dist/media-usage-activation-DrqbmgLA.mjs +78 -0
  519. package/dist/media-usage-activation-DrqbmgLA.mjs.map +1 -0
  520. package/dist/media-usage-work-DommYhYA.mjs +152 -0
  521. package/dist/media-usage-work-DommYhYA.mjs.map +1 -0
  522. package/dist/media-usage-work-HU63hNDu.mjs +586 -0
  523. package/dist/media-usage-work-HU63hNDu.mjs.map +1 -0
  524. package/dist/menus-BQfusWEC.mjs +3608 -0
  525. package/dist/menus-BQfusWEC.mjs.map +1 -0
  526. package/dist/menus-BtwjQt5s.mjs +753 -0
  527. package/dist/menus-BtwjQt5s.mjs.map +1 -0
  528. package/dist/menus-p_M1V7J_.mjs +139 -0
  529. package/dist/menus-p_M1V7J_.mjs.map +1 -0
  530. package/dist/migrations/index.d.mts +1 -1
  531. package/dist/migrations/index.mjs +3 -3
  532. package/dist/mime-C94qBG-P.mjs +36 -0
  533. package/dist/mime-C94qBG-P.mjs.map +1 -0
  534. package/dist/mode-DpYW3w6U.mjs +23 -0
  535. package/dist/mode-DpYW3w6U.mjs.map +1 -0
  536. package/dist/node-sqlite-compat-pWFw0lcc.mjs +46 -0
  537. package/dist/node-sqlite-compat-pWFw0lcc.mjs.map +1 -0
  538. package/dist/normalize-DduyxBjf.mjs +191 -0
  539. package/dist/normalize-DduyxBjf.mjs.map +1 -0
  540. package/dist/oauth-authorization-DAXsH1H9.mjs +274 -0
  541. package/dist/oauth-authorization-DAXsH1H9.mjs.map +1 -0
  542. package/dist/oauth-clients-DENiDQri.mjs +266 -0
  543. package/dist/oauth-clients-DENiDQri.mjs.map +1 -0
  544. package/dist/oauth-state-store-y8mEYVq9.mjs +50 -0
  545. package/dist/oauth-state-store-y8mEYVq9.mjs.map +1 -0
  546. package/dist/oauth-user-lookup-CtTYAy-O.mjs +26 -0
  547. package/dist/oauth-user-lookup-CtTYAy-O.mjs.map +1 -0
  548. package/dist/object-cache/memory.d.mts +1 -1
  549. package/dist/options-BYa1FgIM.d.mts +81 -0
  550. package/dist/options-BYa1FgIM.d.mts.map +1 -0
  551. package/dist/page/index.d.mts +2 -2
  552. package/dist/page/index.mjs +5 -5
  553. package/dist/parse-CORGGhHf.mjs +81 -0
  554. package/dist/parse-CORGGhHf.mjs.map +1 -0
  555. package/dist/parse-avNM1xWV.d.mts +168 -0
  556. package/dist/parse-avNM1xWV.d.mts.map +1 -0
  557. package/dist/passkey-config-Dih5YeIS.mjs +46 -0
  558. package/dist/passkey-config-Dih5YeIS.mjs.map +1 -0
  559. package/dist/paths-d51RFm8M.mjs +77 -0
  560. package/dist/paths-d51RFm8M.mjs.map +1 -0
  561. package/dist/patterns-CoqlXUvk.mjs +145 -0
  562. package/dist/patterns-CoqlXUvk.mjs.map +1 -0
  563. package/dist/placeholder-D2aksPMF.d.mts +306 -0
  564. package/dist/placeholder-D2aksPMF.d.mts.map +1 -0
  565. package/dist/plan-DqeZKuaR.mjs +135 -0
  566. package/dist/plan-DqeZKuaR.mjs.map +1 -0
  567. package/dist/plugin-test-runtime.d.mts +14 -14
  568. package/dist/plugin-test-runtime.mjs +110 -107
  569. package/dist/plugin-types.d.mts +2 -2
  570. package/dist/plugin-utils.d.mts +12 -12
  571. package/dist/plugins/adapt-sandbox-entry.d.mts +12 -12
  572. package/dist/plugins/adapt-sandbox-entry.mjs +3 -3
  573. package/dist/plugins/host.d.mts +5 -5
  574. package/dist/plugins/host.mjs +42 -41
  575. package/dist/plugins-Bb7oqjQA.mjs +277 -0
  576. package/dist/plugins-Bb7oqjQA.mjs.map +1 -0
  577. package/dist/policy-BcEqut3n.mjs +45 -0
  578. package/dist/policy-BcEqut3n.mjs.map +1 -0
  579. package/dist/portable-text-DXE8ymtD.mjs +307 -0
  580. package/dist/portable-text-DXE8ymtD.mjs.map +1 -0
  581. package/dist/preview-DEDWbwA_.mjs +107 -0
  582. package/dist/preview-DEDWbwA_.mjs.map +1 -0
  583. package/dist/protocol-BJbTzvwl.d.mts +61 -0
  584. package/dist/protocol-BJbTzvwl.d.mts.map +1 -0
  585. package/dist/public-submission-D9c9S14m.mjs +250 -0
  586. package/dist/public-submission-D9c9S14m.mjs.map +1 -0
  587. package/dist/public-url-CIRe-2T6.mjs +101 -0
  588. package/dist/public-url-CIRe-2T6.mjs.map +1 -0
  589. package/dist/query-BzifXlPS.mjs +1156 -0
  590. package/dist/query-BzifXlPS.mjs.map +1 -0
  591. package/dist/query-OzMJ6vJP.mjs +41 -0
  592. package/dist/query-OzMJ6vJP.mjs.map +1 -0
  593. package/dist/rate-limit-Csp60Vik.mjs +120 -0
  594. package/dist/rate-limit-Csp60Vik.mjs.map +1 -0
  595. package/dist/receipt-B-aU4hpJ.mjs +43 -0
  596. package/dist/receipt-B-aU4hpJ.mjs.map +1 -0
  597. package/dist/redirect-CDSw1sU3.mjs +17 -0
  598. package/dist/redirect-CDSw1sU3.mjs.map +1 -0
  599. package/dist/redirect-D1ArbO85.mjs +411 -0
  600. package/dist/redirect-D1ArbO85.mjs.map +1 -0
  601. package/dist/redirects-BjTwDTsV.mjs +148 -0
  602. package/dist/redirects-BjTwDTsV.mjs.map +1 -0
  603. package/dist/redirects-Ck50kH3n.mjs +446 -0
  604. package/dist/redirects-Ck50kH3n.mjs.map +1 -0
  605. package/dist/registry/testing.mjs +3 -3
  606. package/dist/registry-CFcNCayZ.mjs +6754 -0
  607. package/dist/registry-CFcNCayZ.mjs.map +1 -0
  608. package/dist/relations-Cfaa1fDl.mjs +776 -0
  609. package/dist/relations-Cfaa1fDl.mjs.map +1 -0
  610. package/dist/request-cache-iHRlHx1d.mjs +104 -0
  611. package/dist/request-cache-iHRlHx1d.mjs.map +1 -0
  612. package/dist/request-context.d.mts +1 -1
  613. package/dist/request-meta-D47mqyev.mjs +141 -0
  614. package/dist/request-meta-D47mqyev.mjs.map +1 -0
  615. package/dist/resolve-BPE8sMvx.mjs +99 -0
  616. package/dist/resolve-BPE8sMvx.mjs.map +1 -0
  617. package/dist/resolve-C0s1E_fH.mjs +199 -0
  618. package/dist/resolve-C0s1E_fH.mjs.map +1 -0
  619. package/dist/revision-j1p4-bOj.mjs +302 -0
  620. package/dist/revision-j1p4-bOj.mjs.map +1 -0
  621. package/dist/route-wire-C9PJV9aL.mjs +197 -0
  622. package/dist/route-wire-C9PJV9aL.mjs.map +1 -0
  623. package/dist/routes-lyYw0mMf.mjs +272 -0
  624. package/dist/routes-lyYw0mMf.mjs.map +1 -0
  625. package/dist/runner-B3eyB9Gb.mjs +6121 -0
  626. package/dist/runner-B3eyB9Gb.mjs.map +1 -0
  627. package/dist/runner-DoYH2Jcu.d.mts +68 -0
  628. package/dist/runner-DoYH2Jcu.d.mts.map +1 -0
  629. package/dist/runtime.d.mts +13 -13
  630. package/dist/runtime.mjs +3 -3
  631. package/dist/schema-BAayK46S.mjs +13 -0
  632. package/dist/schema-BAayK46S.mjs.map +1 -0
  633. package/dist/schema-Gqcl-8G4.mjs +815 -0
  634. package/dist/schema-Gqcl-8G4.mjs.map +1 -0
  635. package/dist/scopes-BqPOKoKf.mjs +34 -0
  636. package/dist/scopes-BqPOKoKf.mjs.map +1 -0
  637. package/dist/search-YJKPIEV6.mjs +448 -0
  638. package/dist/search-YJKPIEV6.mjs.map +1 -0
  639. package/dist/sections-BR_e-wK5.mjs +346 -0
  640. package/dist/sections-BR_e-wK5.mjs.map +1 -0
  641. package/dist/seed/index.d.mts +2 -2
  642. package/dist/seed/index.mjs +37 -31
  643. package/dist/seo/index.d.mts +3 -3
  644. package/dist/seo/index.mjs +22 -21
  645. package/dist/seo/index.mjs.map +1 -1
  646. package/dist/seo-Dsj8hy3j.mjs +114 -0
  647. package/dist/seo-Dsj8hy3j.mjs.map +1 -0
  648. package/dist/seo-XvH4LNNp.mjs +133 -0
  649. package/dist/seo-XvH4LNNp.mjs.map +1 -0
  650. package/dist/service-BsVG05gS.mjs +150 -0
  651. package/dist/service-BsVG05gS.mjs.map +1 -0
  652. package/dist/session-user-DgKbYrlj.mjs +51 -0
  653. package/dist/session-user-DgKbYrlj.mjs.map +1 -0
  654. package/dist/settings-CNPUntkh.mjs +51 -0
  655. package/dist/settings-CNPUntkh.mjs.map +1 -0
  656. package/dist/settings-D5EHi0Tk.mjs +439 -0
  657. package/dist/settings-D5EHi0Tk.mjs.map +1 -0
  658. package/dist/settings-DSfE7wOa.mjs +61 -0
  659. package/dist/settings-DSfE7wOa.mjs.map +1 -0
  660. package/dist/setup-complete-B8W8sJ9v.mjs +26 -0
  661. package/dist/setup-complete-B8W8sJ9v.mjs.map +1 -0
  662. package/dist/setup-nonce-DnSBP260.mjs +25 -0
  663. package/dist/setup-nonce-DnSBP260.mjs.map +1 -0
  664. package/dist/site-settings-NGzdrt7O.mjs +50 -0
  665. package/dist/site-settings-NGzdrt7O.mjs.map +1 -0
  666. package/dist/site-url-D6JB7tLW.mjs +16 -0
  667. package/dist/site-url-D6JB7tLW.mjs.map +1 -0
  668. package/dist/snapshot-CdcwwWAf.mjs +414 -0
  669. package/dist/snapshot-CdcwwWAf.mjs.map +1 -0
  670. package/dist/ssrf-Dv0_tRpo.mjs +406 -0
  671. package/dist/ssrf-Dv0_tRpo.mjs.map +1 -0
  672. package/dist/stage-CUjhED3P.mjs +662 -0
  673. package/dist/stage-CUjhED3P.mjs.map +1 -0
  674. package/dist/staged-C36IWXff.mjs +659 -0
  675. package/dist/staged-C36IWXff.mjs.map +1 -0
  676. package/dist/state-CKouMCSY.mjs +153 -0
  677. package/dist/state-CKouMCSY.mjs.map +1 -0
  678. package/dist/status-lzyj4Uu7.mjs +30 -0
  679. package/dist/status-lzyj4Uu7.mjs.map +1 -0
  680. package/dist/storage/local.d.mts +1 -1
  681. package/dist/storage/local.mjs +1 -1
  682. package/dist/storage/s3.d.mts +1 -1
  683. package/dist/storage/s3.mjs +1 -1
  684. package/dist/storage-query-B-cWcTjJ.d.mts +1594 -0
  685. package/dist/storage-query-B-cWcTjJ.d.mts.map +1 -0
  686. package/dist/tar-DsTXX6ch.mjs +449 -0
  687. package/dist/tar-DsTXX6ch.mjs.map +1 -0
  688. package/dist/target-DLQCwp_Z.mjs +27 -0
  689. package/dist/target-DLQCwp_Z.mjs.map +1 -0
  690. package/dist/taxonomies-BlAjr4BL.mjs +697 -0
  691. package/dist/taxonomies-BlAjr4BL.mjs.map +1 -0
  692. package/dist/taxonomies-Byyo7LOZ.mjs +939 -0
  693. package/dist/taxonomies-Byyo7LOZ.mjs.map +1 -0
  694. package/dist/taxonomy-CKDwM61Y.mjs +525 -0
  695. package/dist/taxonomy-CKDwM61Y.mjs.map +1 -0
  696. package/dist/tokens-BojXlk49.mjs +171 -0
  697. package/dist/tokens-BojXlk49.mjs.map +1 -0
  698. package/dist/transaction-DLPQWik1.mjs +29 -0
  699. package/dist/transaction-DLPQWik1.mjs.map +1 -0
  700. package/dist/transfer-XSTh2BCr.mjs +8706 -0
  701. package/dist/transfer-XSTh2BCr.mjs.map +1 -0
  702. package/dist/transfer-download-DkoCDA9d.mjs +33 -0
  703. package/dist/transfer-download-DkoCDA9d.mjs.map +1 -0
  704. package/dist/transfer-iQ26J-RT.mjs +166 -0
  705. package/dist/transfer-iQ26J-RT.mjs.map +1 -0
  706. package/dist/transformations-C7RQabKQ.mjs +196 -0
  707. package/dist/transformations-C7RQabKQ.mjs.map +1 -0
  708. package/dist/transport-D3RulfD6.mjs +136 -0
  709. package/dist/transport-D3RulfD6.mjs.map +1 -0
  710. package/dist/transport-DhlZlf4D.d.mts +42 -0
  711. package/dist/transport-DhlZlf4D.d.mts.map +1 -0
  712. package/dist/trusted-proxy-B6ECOZJc.mjs +51 -0
  713. package/dist/trusted-proxy-B6ECOZJc.mjs.map +1 -0
  714. package/dist/turnstile-lqUiY7lP.mjs +53 -0
  715. package/dist/turnstile-lqUiY7lP.mjs.map +1 -0
  716. package/dist/types-4Dn9bZhu.mjs +77 -0
  717. package/dist/types-4Dn9bZhu.mjs.map +1 -0
  718. package/dist/types-5LSo7PPx.d.mts +85 -0
  719. package/dist/types-5LSo7PPx.d.mts.map +1 -0
  720. package/dist/types-BQ3hwYJT.d.mts +896 -0
  721. package/dist/types-BQ3hwYJT.d.mts.map +1 -0
  722. package/dist/types-BYEk7qo3.d.mts +198 -0
  723. package/dist/types-BYEk7qo3.d.mts.map +1 -0
  724. package/dist/types-CJKsWVFR.mjs +199 -0
  725. package/dist/types-CJKsWVFR.mjs.map +1 -0
  726. package/dist/types-Ca_w8mmY.d.mts +363 -0
  727. package/dist/types-Ca_w8mmY.d.mts.map +1 -0
  728. package/dist/types-CkE41ZAG.mjs +18 -0
  729. package/dist/types-CkE41ZAG.mjs.map +1 -0
  730. package/dist/types-D0aJW2uR.d.mts +1641 -0
  731. package/dist/types-D0aJW2uR.d.mts.map +1 -0
  732. package/dist/types-DbpN4Qto.d.mts +372 -0
  733. package/dist/types-DbpN4Qto.d.mts.map +1 -0
  734. package/dist/types-ILDI1sdY.mjs +16 -0
  735. package/dist/types-ILDI1sdY.mjs.map +1 -0
  736. package/dist/types-OC5c-edM.mjs +22 -0
  737. package/dist/types-OC5c-edM.mjs.map +1 -0
  738. package/dist/types-aOOxRSx6.mjs +103 -0
  739. package/dist/types-aOOxRSx6.mjs.map +1 -0
  740. package/dist/types-m1WbUffD.d.mts +198 -0
  741. package/dist/types-m1WbUffD.d.mts.map +1 -0
  742. package/dist/types-uxLoPBio.d.mts +124 -0
  743. package/dist/types-uxLoPBio.d.mts.map +1 -0
  744. package/dist/types-we5uR-tV.d.mts +287 -0
  745. package/dist/types-we5uR-tV.d.mts.map +1 -0
  746. package/dist/upload-attempts-DduMy6B0.mjs +32 -0
  747. package/dist/upload-attempts-DduMy6B0.mjs.map +1 -0
  748. package/dist/url-pattern-B3EwxAAk.mjs +33 -0
  749. package/dist/url-pattern-B3EwxAAk.mjs.map +1 -0
  750. package/dist/user-ElwQjTQT.mjs +171 -0
  751. package/dist/user-ElwQjTQT.mjs.map +1 -0
  752. package/dist/utils-BlAXmfOG.mjs +439 -0
  753. package/dist/utils-BlAXmfOG.mjs.map +1 -0
  754. package/dist/validate-CH0X5b2c.d.mts +468 -0
  755. package/dist/validate-CH0X5b2c.d.mts.map +1 -0
  756. package/dist/validate-CfgRpcjA.mjs +492 -0
  757. package/dist/validate-CfgRpcjA.mjs.map +1 -0
  758. package/dist/validation-DvYJtv4k.mjs +218 -0
  759. package/dist/validation-DvYJtv4k.mjs.map +1 -0
  760. package/dist/version-DgYjhTud.mjs +9 -0
  761. package/dist/version-DgYjhTud.mjs.map +1 -0
  762. package/dist/version-Dq71scUb.mjs +7 -0
  763. package/dist/version-Dq71scUb.mjs.map +1 -0
  764. package/dist/widgets-ChFIj0be.mjs +126 -0
  765. package/dist/widgets-ChFIj0be.mjs.map +1 -0
  766. package/dist/wxr-taxonomies-CBZMp2YX.mjs +372 -0
  767. package/dist/wxr-taxonomies-CBZMp2YX.mjs.map +1 -0
  768. package/dist/wxr-taxonomies-DlKDpWN1.d.mts +34 -0
  769. package/dist/wxr-taxonomies-DlKDpWN1.d.mts.map +1 -0
  770. package/dist/zod-generator-DmTKI-Ig.mjs +426 -0
  771. package/dist/zod-generator-DmTKI-Ig.mjs.map +1 -0
  772. package/package.json +7 -6
  773. package/src/api/handlers/content.ts +593 -16
  774. package/src/api/handlers/device-flow.ts +74 -21
  775. package/src/api/handlers/index.ts +1 -0
  776. package/src/api/handlers/manifest.ts +79 -5
  777. package/src/api/handlers/media-upload.ts +17 -71
  778. package/src/api/handlers/media.ts +97 -3
  779. package/src/api/handlers/relations.ts +638 -157
  780. package/src/api/handlers/revision.ts +30 -0
  781. package/src/api/handlers/schema.ts +403 -1
  782. package/src/api/handlers/snapshot.ts +257 -3
  783. package/src/api/handlers/staged-references.ts +142 -0
  784. package/src/api/handlers/validate-references.ts +146 -0
  785. package/src/api/schemas/content.ts +13 -0
  786. package/src/api/schemas/relations.ts +54 -44
  787. package/src/api/schemas/schema.ts +14 -0
  788. package/src/astro/integration/routes.ts +15 -19
  789. package/src/astro/integration/vite-config.ts +10 -4
  790. package/src/astro/middleware.ts +1 -0
  791. package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/children.ts +11 -54
  792. package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
  793. package/src/astro/routes/api/oauth/device/authorize.ts +33 -4
  794. package/src/astro/routes/api/relations/index.ts +4 -4
  795. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +6 -2
  796. package/src/astro/routes/api/setup/index.ts +66 -23
  797. package/src/astro/routes/api/snapshot.ts +2 -1
  798. package/src/astro/types.ts +10 -0
  799. package/src/cleanup.ts +10 -0
  800. package/src/cli/commands/export-seed.ts +510 -89
  801. package/src/components/Columns.astro +3 -1
  802. package/src/components/Cover.astro +3 -1
  803. package/src/components/WidgetArea.astro +3 -2
  804. package/src/database/migrations/086_relations_structural.ts +197 -0
  805. package/src/database/migrations/087_reference_field_relations.ts +407 -0
  806. package/src/database/migrations/runner.ts +4 -0
  807. package/src/database/reference-backfill.ts +141 -0
  808. package/src/database/repositories/content.ts +43 -8
  809. package/src/database/repositories/media.ts +40 -1
  810. package/src/database/repositories/redirect.ts +17 -34
  811. package/src/database/repositories/relation.ts +620 -208
  812. package/src/database/repositories/revision.ts +16 -0
  813. package/src/database/repositories/types.ts +38 -0
  814. package/src/database/transaction.ts +12 -1
  815. package/src/database/types.ts +14 -5
  816. package/src/emdash-runtime.ts +114 -11
  817. package/src/index.ts +11 -0
  818. package/src/loader.ts +169 -22
  819. package/src/mcp/server.ts +13 -48
  820. package/src/query.ts +455 -25
  821. package/src/references/field-map.ts +115 -0
  822. package/src/references/resolve.ts +160 -0
  823. package/src/references/staged.ts +117 -0
  824. package/src/references/types.ts +16 -0
  825. package/src/registry/artifact-fetch.ts +45 -271
  826. package/src/schema/registry.ts +99 -24
  827. package/src/schema/types.ts +58 -0
  828. package/src/schema/zod-generator.ts +67 -1
  829. package/src/seed/apply.ts +841 -103
  830. package/src/seed/types.ts +36 -2
  831. package/src/seed/validate.ts +78 -2
  832. package/src/transfer/analyze/unique-keys.ts +3 -12
  833. package/src/transfer/analyze/validate.ts +65 -39
  834. package/src/transfer/analyze/values.ts +12 -1
  835. package/src/transfer/export/readers.ts +12 -8
  836. package/src/transfer/format/columns.ts +26 -6
  837. package/src/transfer/format/kinds.ts +21 -5
  838. package/src/transfer/import/context.ts +8 -1
  839. package/src/transfer/ops/package-index.ts +1 -1
  840. package/dist/action-token-DYwe4Pk0.mjs +0 -26
  841. package/dist/action-token-DYwe4Pk0.mjs.map +0 -1
  842. package/dist/activation-LOkDM5WT.mjs +0 -382
  843. package/dist/activation-LOkDM5WT.mjs.map +0 -1
  844. package/dist/adapters-B64LbYcB.d.mts +0 -171
  845. package/dist/adapters-B64LbYcB.d.mts.map +0 -1
  846. package/dist/allowed-origins-CHB8oZNM.mjs +0 -116
  847. package/dist/allowed-origins-CHB8oZNM.mjs.map +0 -1
  848. package/dist/api-cFFZpyS0.mjs +0 -4718
  849. package/dist/api-cFFZpyS0.mjs.map +0 -1
  850. package/dist/api-tokens-s4i4aUp_.mjs +0 -166
  851. package/dist/api-tokens-s4i4aUp_.mjs.map +0 -1
  852. package/dist/apply-CoT603H3.mjs +0 -1163
  853. package/dist/apply-CoT603H3.mjs.map +0 -1
  854. package/dist/approvals-CqMfNxak.mjs +0 -460
  855. package/dist/approvals-CqMfNxak.mjs.map +0 -1
  856. package/dist/artifact-fetch-DZMOGZ3-.mjs +0 -818
  857. package/dist/artifact-fetch-DZMOGZ3-.mjs.map +0 -1
  858. package/dist/astro/routes/api/relations/_id_/translations.d.mts +0 -8
  859. package/dist/astro/routes/api/relations/_id_/translations.d.mts.map +0 -1
  860. package/dist/astro/routes/api/relations/_id_/translations.mjs +0 -47
  861. package/dist/astro/routes/api/relations/_id_/translations.mjs.map +0 -1
  862. package/dist/audit-RfCugiSB.mjs +0 -127
  863. package/dist/audit-RfCugiSB.mjs.map +0 -1
  864. package/dist/authoritative-records-CoJvBXAD.mjs +0 -5172
  865. package/dist/authoritative-records-CoJvBXAD.mjs.map +0 -1
  866. package/dist/authorize-seCifOMJ.mjs +0 -49
  867. package/dist/authorize-seCifOMJ.mjs.map +0 -1
  868. package/dist/backup-CBu0LrXf.mjs +0 -246
  869. package/dist/backup-CBu0LrXf.mjs.map +0 -1
  870. package/dist/block-type-registry-DUI_3KxT.mjs +0 -6709
  871. package/dist/block-type-registry-DUI_3KxT.mjs.map +0 -1
  872. package/dist/block-types-BmZmLmAD.mjs +0 -132
  873. package/dist/block-types-BmZmLmAD.mjs.map +0 -1
  874. package/dist/block-values-C_VIPr5t.mjs +0 -175
  875. package/dist/block-values-C_VIPr5t.mjs.map +0 -1
  876. package/dist/byline-DYmkXqvo.mjs +0 -909
  877. package/dist/byline-DYmkXqvo.mjs.map +0 -1
  878. package/dist/byline-fields-D28AT-Fh.mjs +0 -123
  879. package/dist/byline-fields-D28AT-Fh.mjs.map +0 -1
  880. package/dist/byline-registry-gnKscbQX.mjs +0 -406
  881. package/dist/byline-registry-gnKscbQX.mjs.map +0 -1
  882. package/dist/bylines-BPwJqoYH.mjs +0 -232
  883. package/dist/bylines-BPwJqoYH.mjs.map +0 -1
  884. package/dist/bylines-ukLaYpVZ.mjs +0 -214
  885. package/dist/bylines-ukLaYpVZ.mjs.map +0 -1
  886. package/dist/cache-m7UEkRFV.mjs +0 -108
  887. package/dist/cache-m7UEkRFV.mjs.map +0 -1
  888. package/dist/canonical-YhEQezjg.mjs +0 -174
  889. package/dist/canonical-YhEQezjg.mjs.map +0 -1
  890. package/dist/capture-triggers-kJyl_yyM.mjs +0 -362
  891. package/dist/capture-triggers-kJyl_yyM.mjs.map +0 -1
  892. package/dist/challenge-store-ppU6Uv13.mjs +0 -51
  893. package/dist/challenge-store-ppU6Uv13.mjs.map +0 -1
  894. package/dist/checksum-B2IINIlN.mjs +0 -162
  895. package/dist/checksum-B2IINIlN.mjs.map +0 -1
  896. package/dist/chrome-tags-DApCQSIk.mjs +0 -24
  897. package/dist/chrome-tags-DApCQSIk.mjs.map +0 -1
  898. package/dist/chunks-Dms7Uxbt.mjs +0 -25
  899. package/dist/chunks-Dms7Uxbt.mjs.map +0 -1
  900. package/dist/collection-deletion-BIm28mo3.mjs +0 -436
  901. package/dist/collection-deletion-BIm28mo3.mjs.map +0 -1
  902. package/dist/collection-deletion-processor-Br6rxs3u.mjs +0 -217
  903. package/dist/collection-deletion-processor-Br6rxs3u.mjs.map +0 -1
  904. package/dist/collection-slugs-cache-CjGk__zp.mjs +0 -85
  905. package/dist/collection-slugs-cache-CjGk__zp.mjs.map +0 -1
  906. package/dist/comment-CrBl22OF.mjs +0 -313
  907. package/dist/comment-CrBl22OF.mjs.map +0 -1
  908. package/dist/comment-reaction-JEQ2Fpd8.mjs +0 -85
  909. package/dist/comment-reaction-JEQ2Fpd8.mjs.map +0 -1
  910. package/dist/comments-2ah9du9y.mjs +0 -195
  911. package/dist/comments-2ah9du9y.mjs.map +0 -1
  912. package/dist/comments-fHZ8ON9O.mjs +0 -99
  913. package/dist/comments-fHZ8ON9O.mjs.map +0 -1
  914. package/dist/components-CXbq7CSM.mjs +0 -108
  915. package/dist/components-CXbq7CSM.mjs.map +0 -1
  916. package/dist/config-5ii2haYu.d.mts +0 -6528
  917. package/dist/config-5ii2haYu.d.mts.map +0 -1
  918. package/dist/config-IhybvkIQ.mjs +0 -242
  919. package/dist/config-IhybvkIQ.mjs.map +0 -1
  920. package/dist/config-Py43JK9r.d.mts +0 -39
  921. package/dist/config-Py43JK9r.d.mts.map +0 -1
  922. package/dist/content-DFaIEDj9.mjs +0 -2281
  923. package/dist/content-DFaIEDj9.mjs.map +0 -1
  924. package/dist/content-list-query-Dra4Dalc.d.mts +0 -26
  925. package/dist/content-list-query-Dra4Dalc.d.mts.map +0 -1
  926. package/dist/content-policy-DFNw91-d.mjs +0 -46
  927. package/dist/content-policy-DFNw91-d.mjs.map +0 -1
  928. package/dist/content-repair-Q8IUrpLL.mjs +0 -442
  929. package/dist/content-repair-Q8IUrpLL.mjs.map +0 -1
  930. package/dist/context-BeGccdUX.mjs +0 -1921
  931. package/dist/context-BeGccdUX.mjs.map +0 -1
  932. package/dist/cron-7DCJwPXq.mjs +0 -284
  933. package/dist/cron-7DCJwPXq.mjs.map +0 -1
  934. package/dist/dashboard-DjrB-xxZ.mjs +0 -151
  935. package/dist/dashboard-DjrB-xxZ.mjs.map +0 -1
  936. package/dist/default-DQ6vsviu.mjs +0 -81
  937. package/dist/default-DQ6vsviu.mjs.map +0 -1
  938. package/dist/deferred-tasks-BPxXUB4x.d.mts +0 -9
  939. package/dist/deferred-tasks-BPxXUB4x.d.mts.map +0 -1
  940. package/dist/dev-typegen-CZaPLl3V.mjs +0 -29
  941. package/dist/dev-typegen-CZaPLl3V.mjs.map +0 -1
  942. package/dist/device-flow-CRd6DXmW.mjs +0 -466
  943. package/dist/device-flow-CRd6DXmW.mjs.map +0 -1
  944. package/dist/digest-BarSh-pN.mjs +0 -194
  945. package/dist/digest-BarSh-pN.mjs.map +0 -1
  946. package/dist/direct-executor-BmuFJJZV.mjs +0 -104
  947. package/dist/direct-executor-BmuFJJZV.mjs.map +0 -1
  948. package/dist/dist-BNwANFJR.mjs +0 -810
  949. package/dist/dist-BNwANFJR.mjs.map +0 -1
  950. package/dist/email-console-bJn3ctqA.mjs +0 -50
  951. package/dist/email-console-bJn3ctqA.mjs.map +0 -1
  952. package/dist/email-locale-CN6WAMx0.mjs +0 -25
  953. package/dist/email-locale-CN6WAMx0.mjs.map +0 -1
  954. package/dist/emdash-runtime-DAjghyEG.mjs +0 -4186
  955. package/dist/emdash-runtime-DAjghyEG.mjs.map +0 -1
  956. package/dist/enrich-Dl3kZ-lP.mjs +0 -194
  957. package/dist/enrich-Dl3kZ-lP.mjs.map +0 -1
  958. package/dist/entry-lock-BJYdBfXb.mjs +0 -1097
  959. package/dist/entry-lock-BJYdBfXb.mjs.map +0 -1
  960. package/dist/entry-lock-DHQOxN7R.mjs +0 -163
  961. package/dist/entry-lock-DHQOxN7R.mjs.map +0 -1
  962. package/dist/entry-lock-DVhCt49A.d.mts +0 -4368
  963. package/dist/entry-lock-DVhCt49A.d.mts.map +0 -1
  964. package/dist/entry-locks-D0foLdjQ.mjs +0 -167
  965. package/dist/entry-locks-D0foLdjQ.mjs.map +0 -1
  966. package/dist/error-CfvOHP0M.mjs +0 -90
  967. package/dist/error-CfvOHP0M.mjs.map +0 -1
  968. package/dist/errors-BF0_LFhW.mjs +0 -460
  969. package/dist/errors-BF0_LFhW.mjs.map +0 -1
  970. package/dist/errors-DgE1zJGG.mjs +0 -120
  971. package/dist/errors-DgE1zJGG.mjs.map +0 -1
  972. package/dist/escape-CuaZhZvL.mjs +0 -9
  973. package/dist/escape-CuaZhZvL.mjs.map +0 -1
  974. package/dist/fence-CMDXJYc_.mjs +0 -162
  975. package/dist/fence-CMDXJYc_.mjs.map +0 -1
  976. package/dist/field-defs-cache-HIgBbqZZ.mjs +0 -77
  977. package/dist/field-defs-cache-HIgBbqZZ.mjs.map +0 -1
  978. package/dist/focal-point-Gr34o-4o.mjs +0 -23
  979. package/dist/focal-point-Gr34o-4o.mjs.map +0 -1
  980. package/dist/fts-manager-S-K0laoS.mjs +0 -443
  981. package/dist/fts-manager-S-K0laoS.mjs.map +0 -1
  982. package/dist/gc-DjKY0Ay1.mjs +0 -75
  983. package/dist/gc-DjKY0Ay1.mjs.map +0 -1
  984. package/dist/hash-SDAW6zC-.mjs +0 -37
  985. package/dist/hash-SDAW6zC-.mjs.map +0 -1
  986. package/dist/hook-result-B5bXDgS2.d.mts +0 -31
  987. package/dist/hook-result-B5bXDgS2.d.mts.map +0 -1
  988. package/dist/hreflang-D5uNnsGJ.d.mts +0 -50
  989. package/dist/hreflang-D5uNnsGJ.d.mts.map +0 -1
  990. package/dist/hreflang-DMFBL2eb.mjs +0 -105
  991. package/dist/hreflang-DMFBL2eb.mjs.map +0 -1
  992. package/dist/http-route-dispatch-BitqzwMy.mjs +0 -339
  993. package/dist/http-route-dispatch-BitqzwMy.mjs.map +0 -1
  994. package/dist/identity-IyNWwXr6.mjs +0 -35
  995. package/dist/identity-IyNWwXr6.mjs.map +0 -1
  996. package/dist/import-C3JZplWq.mjs +0 -2020
  997. package/dist/import-C3JZplWq.mjs.map +0 -1
  998. package/dist/index-D-hdtLe8.d.mts +0 -623
  999. package/dist/index-D-hdtLe8.d.mts.map +0 -1
  1000. package/dist/install-finalization-DfM1fj5x.mjs +0 -58
  1001. package/dist/install-finalization-DfM1fj5x.mjs.map +0 -1
  1002. package/dist/keys-yxLm5l35.mjs +0 -61
  1003. package/dist/keys-yxLm5l35.mjs.map +0 -1
  1004. package/dist/kinds-CRu_T5T5.mjs +0 -961
  1005. package/dist/kinds-CRu_T5T5.mjs.map +0 -1
  1006. package/dist/lifecycle-BzeGPeQ-.mjs +0 -25
  1007. package/dist/lifecycle-BzeGPeQ-.mjs.map +0 -1
  1008. package/dist/load-XgJiE6_3.mjs +0 -28
  1009. package/dist/load-XgJiE6_3.mjs.map +0 -1
  1010. package/dist/loader-BzqeR1ZN.mjs +0 -1086
  1011. package/dist/loader-BzqeR1ZN.mjs.map +0 -1
  1012. package/dist/loops-BQSzv5Zn.mjs +0 -203
  1013. package/dist/loops-BQSzv5Zn.mjs.map +0 -1
  1014. package/dist/manifest-builder-B8zR-73J.mjs +0 -189
  1015. package/dist/manifest-builder-B8zR-73J.mjs.map +0 -1
  1016. package/dist/manifest-schema-CY3zng_M.mjs +0 -492
  1017. package/dist/manifest-schema-CY3zng_M.mjs.map +0 -1
  1018. package/dist/media-Pu1L6xir.mjs +0 -408
  1019. package/dist/media-Pu1L6xir.mjs.map +0 -1
  1020. package/dist/media-Qp5S3eH3.mjs +0 -355
  1021. package/dist/media-Qp5S3eH3.mjs.map +0 -1
  1022. package/dist/media-allowlist-BSoa9Vvm.mjs +0 -44
  1023. package/dist/media-allowlist-BSoa9Vvm.mjs.map +0 -1
  1024. package/dist/media-folders-BE0oo2eX.mjs +0 -210
  1025. package/dist/media-folders-BE0oo2eX.mjs.map +0 -1
  1026. package/dist/media-h7tOiDLj.mjs +0 -221
  1027. package/dist/media-h7tOiDLj.mjs.map +0 -1
  1028. package/dist/media-url-jArBpzIG.mjs +0 -43
  1029. package/dist/media-url-jArBpzIG.mjs.map +0 -1
  1030. package/dist/media-usage-My-Vi-ex.mjs +0 -1629
  1031. package/dist/media-usage-My-Vi-ex.mjs.map +0 -1
  1032. package/dist/media-usage-activation-HKp7zk7W.mjs +0 -78
  1033. package/dist/media-usage-activation-HKp7zk7W.mjs.map +0 -1
  1034. package/dist/media-usage-work-C2OZLCAd.mjs +0 -586
  1035. package/dist/media-usage-work-C2OZLCAd.mjs.map +0 -1
  1036. package/dist/media-usage-work-DwUNbgvS.mjs +0 -152
  1037. package/dist/media-usage-work-DwUNbgvS.mjs.map +0 -1
  1038. package/dist/menus-BM7BPLOb.mjs +0 -139
  1039. package/dist/menus-BM7BPLOb.mjs.map +0 -1
  1040. package/dist/menus-ITeAbcIF.mjs +0 -753
  1041. package/dist/menus-ITeAbcIF.mjs.map +0 -1
  1042. package/dist/menus-TsSGmSR4.mjs +0 -3608
  1043. package/dist/menus-TsSGmSR4.mjs.map +0 -1
  1044. package/dist/mime-ChLqYwDk.mjs +0 -36
  1045. package/dist/mime-ChLqYwDk.mjs.map +0 -1
  1046. package/dist/mode-CCuKXUci.mjs +0 -23
  1047. package/dist/mode-CCuKXUci.mjs.map +0 -1
  1048. package/dist/node-sqlite-compat-CONMsl-x.mjs +0 -46
  1049. package/dist/node-sqlite-compat-CONMsl-x.mjs.map +0 -1
  1050. package/dist/normalize-CO2P8-iE.mjs +0 -191
  1051. package/dist/normalize-CO2P8-iE.mjs.map +0 -1
  1052. package/dist/oauth-authorization-DlMIL5_h.mjs +0 -274
  1053. package/dist/oauth-authorization-DlMIL5_h.mjs.map +0 -1
  1054. package/dist/oauth-clients-Djq9r_KP.mjs +0 -266
  1055. package/dist/oauth-clients-Djq9r_KP.mjs.map +0 -1
  1056. package/dist/oauth-state-store-BbjnZXNC.mjs +0 -50
  1057. package/dist/oauth-state-store-BbjnZXNC.mjs.map +0 -1
  1058. package/dist/oauth-user-lookup-vue9a64A.mjs +0 -26
  1059. package/dist/oauth-user-lookup-vue9a64A.mjs.map +0 -1
  1060. package/dist/options-SQCHQCPH.d.mts +0 -81
  1061. package/dist/options-SQCHQCPH.d.mts.map +0 -1
  1062. package/dist/parse-CVgO-Qai.d.mts +0 -168
  1063. package/dist/parse-CVgO-Qai.d.mts.map +0 -1
  1064. package/dist/parse-DY6OD1j_.mjs +0 -81
  1065. package/dist/parse-DY6OD1j_.mjs.map +0 -1
  1066. package/dist/passkey-config-X_H8128a.mjs +0 -46
  1067. package/dist/passkey-config-X_H8128a.mjs.map +0 -1
  1068. package/dist/paths-JxokKIbr.mjs +0 -77
  1069. package/dist/paths-JxokKIbr.mjs.map +0 -1
  1070. package/dist/patterns-BhAvqO0S.mjs +0 -145
  1071. package/dist/patterns-BhAvqO0S.mjs.map +0 -1
  1072. package/dist/placeholder-MSEd8gty.d.mts +0 -306
  1073. package/dist/placeholder-MSEd8gty.d.mts.map +0 -1
  1074. package/dist/plan-xjcWrAah.mjs +0 -135
  1075. package/dist/plan-xjcWrAah.mjs.map +0 -1
  1076. package/dist/plugins-DUXUt8B9.mjs +0 -277
  1077. package/dist/plugins-DUXUt8B9.mjs.map +0 -1
  1078. package/dist/policy-CUvwAARc.mjs +0 -45
  1079. package/dist/policy-CUvwAARc.mjs.map +0 -1
  1080. package/dist/portable-text-5O_ZGUjB.mjs +0 -307
  1081. package/dist/portable-text-5O_ZGUjB.mjs.map +0 -1
  1082. package/dist/preview-CIUcPYr6.mjs +0 -107
  1083. package/dist/preview-CIUcPYr6.mjs.map +0 -1
  1084. package/dist/protocol-B97DZaFr.d.mts +0 -61
  1085. package/dist/protocol-B97DZaFr.d.mts.map +0 -1
  1086. package/dist/public-submission-BFBUrqst.mjs +0 -250
  1087. package/dist/public-submission-BFBUrqst.mjs.map +0 -1
  1088. package/dist/public-url-Bn7U0D7-.mjs +0 -101
  1089. package/dist/public-url-Bn7U0D7-.mjs.map +0 -1
  1090. package/dist/query-B48peoRT.mjs +0 -890
  1091. package/dist/query-B48peoRT.mjs.map +0 -1
  1092. package/dist/query-C4IH0uhR.mjs +0 -41
  1093. package/dist/query-C4IH0uhR.mjs.map +0 -1
  1094. package/dist/rate-limit-BZ6nybgc.mjs +0 -120
  1095. package/dist/rate-limit-BZ6nybgc.mjs.map +0 -1
  1096. package/dist/receipt-B4wJj5Jq.mjs +0 -43
  1097. package/dist/receipt-B4wJj5Jq.mjs.map +0 -1
  1098. package/dist/redirect-Cd1E7VUt.mjs +0 -17
  1099. package/dist/redirect-Cd1E7VUt.mjs.map +0 -1
  1100. package/dist/redirect-iJf5fltD.mjs +0 -415
  1101. package/dist/redirect-iJf5fltD.mjs.map +0 -1
  1102. package/dist/redirects-CYu1u1aK.mjs +0 -446
  1103. package/dist/redirects-CYu1u1aK.mjs.map +0 -1
  1104. package/dist/redirects-Cv9apQKj.mjs +0 -148
  1105. package/dist/redirects-Cv9apQKj.mjs.map +0 -1
  1106. package/dist/relation-M4NUCb0b.mjs +0 -334
  1107. package/dist/relation-M4NUCb0b.mjs.map +0 -1
  1108. package/dist/relations-CCif47Oq.mjs +0 -403
  1109. package/dist/relations-CCif47Oq.mjs.map +0 -1
  1110. package/dist/relations-CK9CYUyr.mjs +0 -310
  1111. package/dist/relations-CK9CYUyr.mjs.map +0 -1
  1112. package/dist/request-cache-DzLYKm_x.mjs +0 -104
  1113. package/dist/request-cache-DzLYKm_x.mjs.map +0 -1
  1114. package/dist/request-meta-sZXt3sRo.mjs +0 -141
  1115. package/dist/request-meta-sZXt3sRo.mjs.map +0 -1
  1116. package/dist/resolve-2WbQsCvT.mjs +0 -199
  1117. package/dist/resolve-2WbQsCvT.mjs.map +0 -1
  1118. package/dist/route-wire--1hLuACz.mjs +0 -197
  1119. package/dist/route-wire--1hLuACz.mjs.map +0 -1
  1120. package/dist/routes-CUsM40Cc.mjs +0 -272
  1121. package/dist/routes-CUsM40Cc.mjs.map +0 -1
  1122. package/dist/runner-1y4J9fJB.mjs +0 -5742
  1123. package/dist/runner-1y4J9fJB.mjs.map +0 -1
  1124. package/dist/runner-D5_LzKXI.d.mts +0 -68
  1125. package/dist/runner-D5_LzKXI.d.mts.map +0 -1
  1126. package/dist/schema-BABiRdsH.mjs +0 -13
  1127. package/dist/schema-BABiRdsH.mjs.map +0 -1
  1128. package/dist/schema-Du3MzCG0.mjs +0 -446
  1129. package/dist/schema-Du3MzCG0.mjs.map +0 -1
  1130. package/dist/scopes-Dbk-ElhT.mjs +0 -34
  1131. package/dist/scopes-Dbk-ElhT.mjs.map +0 -1
  1132. package/dist/search-Bt1PL1jf.mjs +0 -448
  1133. package/dist/search-Bt1PL1jf.mjs.map +0 -1
  1134. package/dist/sections-Ddptx_o9.mjs +0 -346
  1135. package/dist/sections-Ddptx_o9.mjs.map +0 -1
  1136. package/dist/seo-CZT2oLtT.mjs +0 -114
  1137. package/dist/seo-CZT2oLtT.mjs.map +0 -1
  1138. package/dist/seo-D5w3-Azy.mjs +0 -133
  1139. package/dist/seo-D5w3-Azy.mjs.map +0 -1
  1140. package/dist/service-DuykXPyW.mjs +0 -150
  1141. package/dist/service-DuykXPyW.mjs.map +0 -1
  1142. package/dist/session-user-BhaVp8w0.mjs +0 -51
  1143. package/dist/session-user-BhaVp8w0.mjs.map +0 -1
  1144. package/dist/settings-2xNYr90o.mjs +0 -51
  1145. package/dist/settings-2xNYr90o.mjs.map +0 -1
  1146. package/dist/settings-CgjRWGW9.mjs +0 -439
  1147. package/dist/settings-CgjRWGW9.mjs.map +0 -1
  1148. package/dist/settings-DYidIB26.mjs +0 -61
  1149. package/dist/settings-DYidIB26.mjs.map +0 -1
  1150. package/dist/setup-complete-bOogcHWG.mjs +0 -26
  1151. package/dist/setup-complete-bOogcHWG.mjs.map +0 -1
  1152. package/dist/setup-nonce-0EGuKM4s.mjs +0 -25
  1153. package/dist/setup-nonce-0EGuKM4s.mjs.map +0 -1
  1154. package/dist/site-settings-DOgRUoFX.mjs +0 -50
  1155. package/dist/site-settings-DOgRUoFX.mjs.map +0 -1
  1156. package/dist/site-url-BU_bbxwj.mjs +0 -16
  1157. package/dist/site-url-BU_bbxwj.mjs.map +0 -1
  1158. package/dist/snapshot-CugwUqKQ.mjs +0 -237
  1159. package/dist/snapshot-CugwUqKQ.mjs.map +0 -1
  1160. package/dist/ssrf-CJUnJymJ.mjs +0 -406
  1161. package/dist/ssrf-CJUnJymJ.mjs.map +0 -1
  1162. package/dist/stage-DgrBz_du.mjs +0 -662
  1163. package/dist/stage-DgrBz_du.mjs.map +0 -1
  1164. package/dist/state-DDiPySSG.mjs +0 -153
  1165. package/dist/state-DDiPySSG.mjs.map +0 -1
  1166. package/dist/status-DZKIG4a9.mjs +0 -30
  1167. package/dist/status-DZKIG4a9.mjs.map +0 -1
  1168. package/dist/storage-query-Bdv7A62k.d.mts +0 -1576
  1169. package/dist/storage-query-Bdv7A62k.d.mts.map +0 -1
  1170. package/dist/tar-_1AgTYFu.mjs +0 -449
  1171. package/dist/tar-_1AgTYFu.mjs.map +0 -1
  1172. package/dist/target-_7pn2Gbg.mjs +0 -27
  1173. package/dist/target-_7pn2Gbg.mjs.map +0 -1
  1174. package/dist/taxonomies-C1IwNe8Q.mjs +0 -697
  1175. package/dist/taxonomies-C1IwNe8Q.mjs.map +0 -1
  1176. package/dist/taxonomies-C_XMoRcX.mjs +0 -939
  1177. package/dist/taxonomies-C_XMoRcX.mjs.map +0 -1
  1178. package/dist/taxonomy-C3Fu1YeH.mjs +0 -525
  1179. package/dist/taxonomy-C3Fu1YeH.mjs.map +0 -1
  1180. package/dist/tokens-u78jETkX.mjs +0 -171
  1181. package/dist/tokens-u78jETkX.mjs.map +0 -1
  1182. package/dist/transaction-BcJO4Tmc.mjs +0 -29
  1183. package/dist/transaction-BcJO4Tmc.mjs.map +0 -1
  1184. package/dist/transfer-BhUCrgDc.mjs +0 -8675
  1185. package/dist/transfer-BhUCrgDc.mjs.map +0 -1
  1186. package/dist/transfer-DIGvR9Af.mjs +0 -166
  1187. package/dist/transfer-DIGvR9Af.mjs.map +0 -1
  1188. package/dist/transfer-download-Pml7RMio.mjs +0 -33
  1189. package/dist/transfer-download-Pml7RMio.mjs.map +0 -1
  1190. package/dist/transformations-9gfpwY65.mjs +0 -196
  1191. package/dist/transformations-9gfpwY65.mjs.map +0 -1
  1192. package/dist/transport-BIfH7_hx.d.mts +0 -42
  1193. package/dist/transport-BIfH7_hx.d.mts.map +0 -1
  1194. package/dist/transport-DKWIq53q.mjs +0 -136
  1195. package/dist/transport-DKWIq53q.mjs.map +0 -1
  1196. package/dist/trusted-proxy-tKiVtyTD.mjs +0 -51
  1197. package/dist/trusted-proxy-tKiVtyTD.mjs.map +0 -1
  1198. package/dist/turnstile-DpsoyOfg.mjs +0 -53
  1199. package/dist/turnstile-DpsoyOfg.mjs.map +0 -1
  1200. package/dist/types-B4sUC2p1.d.mts +0 -198
  1201. package/dist/types-B4sUC2p1.d.mts.map +0 -1
  1202. package/dist/types-B7Lmsh1E.d.mts +0 -887
  1203. package/dist/types-B7Lmsh1E.d.mts.map +0 -1
  1204. package/dist/types-BZakh7Ym.mjs +0 -22
  1205. package/dist/types-BZakh7Ym.mjs.map +0 -1
  1206. package/dist/types-B_CppEmv.d.mts +0 -264
  1207. package/dist/types-B_CppEmv.d.mts.map +0 -1
  1208. package/dist/types-BcrBrE6-.mjs +0 -159
  1209. package/dist/types-BcrBrE6-.mjs.map +0 -1
  1210. package/dist/types-BkUg2yHx.mjs +0 -92
  1211. package/dist/types-BkUg2yHx.mjs.map +0 -1
  1212. package/dist/types-CAZgq9fO.d.mts +0 -124
  1213. package/dist/types-CAZgq9fO.d.mts.map +0 -1
  1214. package/dist/types-Cd-O03VG.d.mts +0 -363
  1215. package/dist/types-Cd-O03VG.d.mts.map +0 -1
  1216. package/dist/types-Cr-Kg-3D.d.mts +0 -1641
  1217. package/dist/types-Cr-Kg-3D.d.mts.map +0 -1
  1218. package/dist/types-D2fvWd1i.d.mts +0 -359
  1219. package/dist/types-D2fvWd1i.d.mts.map +0 -1
  1220. package/dist/types-D7HUsguf.mjs +0 -77
  1221. package/dist/types-D7HUsguf.mjs.map +0 -1
  1222. package/dist/types-DA1Te3Oy.d.mts +0 -198
  1223. package/dist/types-DA1Te3Oy.d.mts.map +0 -1
  1224. package/dist/types-DhV6Q5bP.mjs +0 -18
  1225. package/dist/types-DhV6Q5bP.mjs.map +0 -1
  1226. package/dist/types-DnnVSl6Y.d.mts +0 -85
  1227. package/dist/types-DnnVSl6Y.d.mts.map +0 -1
  1228. package/dist/types-VT4-BugW.mjs +0 -16
  1229. package/dist/types-VT4-BugW.mjs.map +0 -1
  1230. package/dist/upload-attempts-B68ZGNu9.mjs +0 -32
  1231. package/dist/upload-attempts-B68ZGNu9.mjs.map +0 -1
  1232. package/dist/url-pattern-CCeZMGOh.mjs +0 -33
  1233. package/dist/url-pattern-CCeZMGOh.mjs.map +0 -1
  1234. package/dist/user-DDSL-sGw.mjs +0 -171
  1235. package/dist/user-DDSL-sGw.mjs.map +0 -1
  1236. package/dist/utils-DdhmO9w9.mjs +0 -439
  1237. package/dist/utils-DdhmO9w9.mjs.map +0 -1
  1238. package/dist/validate-CHosPEhs.mjs +0 -453
  1239. package/dist/validate-CHosPEhs.mjs.map +0 -1
  1240. package/dist/validate-CM79QXYE.d.mts +0 -432
  1241. package/dist/validate-CM79QXYE.d.mts.map +0 -1
  1242. package/dist/validation-BFecQczG.mjs +0 -218
  1243. package/dist/validation-BFecQczG.mjs.map +0 -1
  1244. package/dist/version-BRZXVifl.mjs +0 -9
  1245. package/dist/version-BRZXVifl.mjs.map +0 -1
  1246. package/dist/version-DUQDHgrf.mjs +0 -7
  1247. package/dist/version-DUQDHgrf.mjs.map +0 -1
  1248. package/dist/widgets-WdV72brA.mjs +0 -126
  1249. package/dist/widgets-WdV72brA.mjs.map +0 -1
  1250. package/dist/wxr-taxonomies-BHTdqkmZ.d.mts +0 -34
  1251. package/dist/wxr-taxonomies-BHTdqkmZ.d.mts.map +0 -1
  1252. package/dist/wxr-taxonomies-DP6ESgMN.mjs +0 -372
  1253. package/dist/wxr-taxonomies-DP6ESgMN.mjs.map +0 -1
  1254. package/dist/zod-generator-D6uE4WiS.mjs +0 -389
  1255. package/dist/zod-generator-D6uE4WiS.mjs.map +0 -1
  1256. package/src/astro/routes/api/relations/[id]/translations.ts +0 -33
  1257. /package/dist/{api-tokens-CE1ECIg0.mjs → api-tokens-FaG1zPsj.mjs} +0 -0
  1258. /package/dist/{ssrf-DpBH7aOt.mjs → ssrf-DZOt8Qof.mjs} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-OC5c-edM.mjs","names":[],"sources":["../src/plugins/types.ts"],"sourcesContent":["/**\n * Plugin System Types v2\n *\n * New plugin API with:\n * - Single unified context shape for all hooks and routes\n * - Paginated storage queries (no async iterators)\n * - Unified KV API (replaces settings + options)\n * - Explicit ctx.http and ctx.log\n *\n */\n\nimport type { Permission } from \"@emdash-cms/auth\";\nimport type { ConfirmDialog, Element, PluginUiContext } from \"@emdash-cms/blocks\";\n// The plugin capability vocabulary, the legacy-rename map, and the manifest\n// shape are authored once in @emdash-cms/plugin-types and shared between core\n// (the manifest reader at install/runtime) and @emdash-cms/plugin-cli (the\n// manifest writer at bundle/publish time).\n//\n// We import-and-re-export here so existing internal callers keep working\n// (e.g. `import { PluginCapability } from \"../plugins/types.js\"`).\nimport {\n\tCAPABILITY_RENAMES,\n\tcapabilitiesToDeclaredAccess,\n\tdeclaredAccessToCapabilities,\n\tisDeprecatedCapability,\n\tnormalizeCapabilities,\n\tnormalizeCapability,\n\ttype CurrentPluginCapability,\n\ttype DeclaredAccess,\n\ttype DeprecatedPluginCapability,\n\ttype ManifestHookEntry,\n\ttype ManifestMcpTool,\n\ttype ManifestRouteEntry,\n\ttype PluginMcpManifestConfig,\n\ttype PluginCapability,\n\ttype PluginEditorDraftAccess,\n\ttype PluginEditorDraftFieldSelector,\n\ttype PluginFormData,\n\ttype PluginRouteBodyMode,\n\ttype PluginRouteQuery,\n\ttype PluginRouteRequest,\n\ttype PluginStorageConfig,\n\ttype RouteOptions,\n\ttype StorageCollectionConfig,\n} from \"@emdash-cms/plugin-types\";\nimport type { JSX } from \"astro/jsx-runtime\";\nimport type { z } from \"astro/zod\";\n// =============================================================================\n// Core Types\n// =============================================================================\n\nimport type { ContentFieldFilters } from \"../content-list-query.js\";\nimport type { FieldType, FieldValidation, FieldWidgetOptions } from \"../schema/types.js\";\n\nexport type {\n\tContentFieldFilterScalar,\n\tContentFieldFilterValue,\n\tContentFieldFilters,\n\tContentFieldInFilter,\n\tContentFieldRangeFilter,\n} from \"../content-list-query.js\";\n\nexport {\n\tCAPABILITY_RENAMES,\n\tcapabilitiesToDeclaredAccess,\n\tdeclaredAccessToCapabilities,\n\tisDeprecatedCapability,\n\tnormalizeCapabilities,\n\tnormalizeCapability,\n\ttype CurrentPluginCapability,\n\ttype DeclaredAccess,\n\ttype DeprecatedPluginCapability,\n\ttype ManifestHookEntry,\n\ttype ManifestMcpTool,\n\ttype ManifestRouteEntry,\n\ttype PluginMcpManifestConfig,\n\ttype PluginCapability,\n\ttype PluginEditorDraftAccess,\n\ttype PluginEditorDraftFieldSelector,\n\ttype PluginStorageConfig,\n\ttype StorageCollectionConfig,\n};\n\nexport const PLUGIN_CAPABILITY_IMPLICATIONS: ReadonlyArray<\n\treadonly [PluginCapability, PluginCapability]\n> = [\n\t[\"content:write\", \"content:read\"],\n\t[\"content:revisions:read\", \"content:read\"],\n\t[\"taxonomies:write\", \"taxonomies:read\"],\n\t[\"content:publish\", \"content:read\"],\n\t[\"media:write\", \"media:read\"],\n\t[\"comments:moderate\", \"comments:read\"],\n\t[\"redirects:write\", \"redirects:read\"],\n\t[\"network:request:unrestricted\", \"network:request\"],\n];\n\nexport function normalizePluginCapabilities(\n\tcapabilities: readonly PluginCapability[],\n): PluginCapability[];\nexport function normalizePluginCapabilities(capabilities: readonly string[]): string[];\nexport function normalizePluginCapabilities(capabilities: readonly string[]): string[] {\n\tconst normalized = new Set(normalizeCapabilities(capabilities));\n\tfor (const [granted, implied] of PLUGIN_CAPABILITY_IMPLICATIONS) {\n\t\tif (normalized.has(granted)) normalized.add(implied);\n\t}\n\treturn [...normalized];\n}\n\n// =============================================================================\n// Storage Types\n// =============================================================================\n//\n// `StorageCollectionConfig` and `PluginStorageConfig` are re-exported above\n// from `@emdash-cms/plugin-types`. The manifest carries these shapes\n// verbatim; both this package (reader) and plugin-cli (writer) agree on\n// the same types via the shared package.\n\n/**\n * Query filter operators\n */\nexport interface RangeFilter {\n\tgt?: number | string;\n\tgte?: number | string;\n\tlt?: number | string;\n\tlte?: number | string;\n}\n\nexport interface InFilter {\n\tin: Array<string | number>;\n}\n\nexport interface StartsWithFilter {\n\tstartsWith: string;\n}\n\n/**\n * Where clause value types\n */\nexport type WhereValue =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| RangeFilter\n\t| InFilter\n\t| StartsWithFilter;\n\n/**\n * Where clause for storage queries\n */\nexport type WhereClause = Record<string, WhereValue>;\n\n/**\n * Query options for storage.query()\n */\nexport interface QueryOptions {\n\twhere?: WhereClause;\n\torderBy?: Record<string, \"asc\" | \"desc\">;\n\t/** Default 50, max 100 */\n\tlimit?: number;\n\tcursor?: string;\n}\n\n/**\n * Paginated result (used by storage.query, content.list, media.list)\n */\nexport interface PaginatedResult<T> {\n\titems: T[];\n\tcursor?: string;\n\thasMore: boolean;\n}\n\nexport interface VersionedValue<T = unknown> {\n\tvalue: T;\n\t/** Opaque host revision, valid only for the key from which it was read. */\n\trevision: string;\n}\n\nexport type ConditionalWriteResult = { applied: true; revision: string } | { applied: false };\n\nexport interface ConditionalDeleteResult {\n\tapplied: boolean;\n}\n\n/**\n * A single per-field integer delta for {@link StorageCollection.updateIf}.\n *\n * `inc`/`dec` values must be safe integers, enforced at runtime with\n * `Number.isSafeInteger` (which also rejects `NaN`/`Infinity`), because a TS\n * `number` cannot forbid float literals. Deltas are applied entirely in-SQL\n * over the stored value with `COALESCE(<value>, 0) ± n`, so a delta on a\n * missing or JSON-`null` field starts from `0` (never corrupts the document).\n *\n * `updateIf` does NOT clamp: a `dec` can drive a field negative when the\n * `where` guard doesn't cover the delta magnitude (e.g. stock `2` with\n * `where: { stock: { gte: 1 } }` and `delta: { stock: { dec: 3 } }` → `-1`,\n * `applied: true`). The guard is the caller's responsibility — pair a `dec: k`\n * with a `gte: k` guard to prevent underflow.\n */\nexport type NumericDelta = { inc: number } | { dec: number };\n\n/**\n * Arguments to {@link StorageCollection.updateIf}.\n *\n * `where` reuses the {@link QueryOptions} `WhereClause` verbatim — the guard is\n * evaluated in-SQL with the same numeric-correct, total comparisons as\n * `query()`. An empty `where: {}` emits no guard, i.e. it matches the row\n * unconditionally (update-if-row-exists) — a footgun in the no-oversell case,\n * where a real predicate (e.g. `{ stock: { gte: 1 } }`) is what you want.\n *\n * At least one of `set` / `delta` must be present (a runtime error is thrown\n * otherwise). A field may not appear in both `set` and `delta` in the same\n * call. `set` and `delta` are separate arguments (not a union) so a wholesale\n * value that happens to look like `{ inc: 5 }` is never mistaken for a delta.\n */\nexport interface UpdateIfArgs<T> {\n\t/**\n\t * Guard evaluated in-SQL; identical semantics to `query({ where })`. An\n\t * empty `{}` means \"match the row unconditionally (no guard)\".\n\t */\n\twhere: WhereClause;\n\t/** Wholesale field values merged into the stored JSON document. */\n\tset?: Partial<T>;\n\t/** Per-field integer deltas applied in-SQL (`COALESCE(base, 0) ± n`). */\n\tdelta?: { [K in keyof T]?: NumericDelta };\n}\n\n/**\n * Result of {@link StorageCollection.updateIf}.\n *\n * `applied: false` intentionally conflates \"row absent\" and \"guard failed\": a\n * single-statement guarded `UPDATE` cannot distinguish them, and the caller\n * should not need to. `updateIf` is update-only — it never inserts a missing\n * row.\n */\nexport type UpdateIfResult<T> = { applied: true; data: T } | { applied: false };\n\n/**\n * Storage collection interface - the API exposed to plugins\n * No async iterators - all operations return promises with pagination\n */\nexport interface StorageCollection<T = unknown> {\n\t// Basic CRUD\n\tget(id: string): Promise<T | null>;\n\tput(id: string, data: T): Promise<void>;\n\tdelete(id: string): Promise<boolean>;\n\texists(id: string): Promise<boolean>;\n\t/** A stored JSON null returns an envelope with value: null; only an absent row returns null. */\n\tgetVersioned(id: string): Promise<VersionedValue<T> | null>;\n\t/** A null expected revision creates only when absent. Errors reject; conflicts return applied: false. */\n\tcompareAndSet(\n\t\tid: string,\n\t\texpectedRevision: string | null,\n\t\tdata: T,\n\t): Promise<ConditionalWriteResult>;\n\tcompareAndDelete(id: string, expectedRevision: string): Promise<ConditionalDeleteResult>;\n\n\t// Batch operations\n\tgetMany(ids: string[]): Promise<Map<string, T>>;\n\tputMany(items: Array<{ id: string; data: T }>): Promise<void>;\n\tdeleteMany(ids: string[]): Promise<number>;\n\n\t// Query - always paginated\n\tquery(options?: QueryOptions): Promise<PaginatedResult<{ id: string; data: T }>>;\n\tcount(where?: WhereClause): Promise<number>;\n\n\t// Conditional write (single-statement, atomic per row).\n\t/**\n\t * Predicate-guarded atomic update. Applies `set`/`delta` to the row `id`\n\t * only if it exists and the `where` guard matches, in a single guarded\n\t * `UPDATE … RETURNING`. This is the no-oversell primitive: the guard and the\n\t * arithmetic live in one statement, so N concurrent guarded decrements\n\t * serialize correctly. `applied: false` means the row was absent OR the\n\t * guard failed (the two are intentionally indistinguishable). Non-object\n\t * documents, invalid counters and unsafe arithmetic results also fail the\n\t * guard. Never inserts.\n\t *\n\t * Serialization failures and deadlocks throw `StorageSerializationError`.\n\t * Retry the write with a bounded policy; restart an explicit transaction\n\t * before retrying its operations.\n\t */\n\tupdateIf(id: string, args: UpdateIfArgs<T>): Promise<UpdateIfResult<T>>;\n}\n\n/**\n * Plugin storage context - typed based on declared collections\n */\nexport type PluginStorage<T extends PluginStorageConfig> = {\n\t[K in keyof T]: StorageCollection;\n};\n\n// =============================================================================\n// Context APIs\n// =============================================================================\n\n/**\n * Plugin-scoped key-value state.\n *\n * Convention:\n * - `state:*` - Internal plugin state (not shown to users)\n * - `cache:*` - Reusable computed or remote data\n *\n * The `settings:*` namespace remains a compatibility alias through EmDash\n * 0.x. New code uses `PluginContext.settings` for user configuration.\n */\nexport interface KVAccess {\n\tget<T>(key: string): Promise<T | null>;\n\tgetVersioned<T>(key: string): Promise<VersionedValue<T> | null>;\n\t/** A null expected revision creates only when absent. Errors reject; conflicts return applied: false. */\n\tcompareAndSet(\n\t\tkey: string,\n\t\texpectedRevision: string | null,\n\t\tvalue: unknown,\n\t): Promise<ConditionalWriteResult>;\n\tcompareAndDelete(key: string, expectedRevision: string): Promise<ConditionalDeleteResult>;\n\tset(key: string, value: unknown): Promise<void>;\n\tdelete(key: string): Promise<boolean>;\n\tlist(prefix?: string): Promise<Array<{ key: string; value: unknown }>>;\n}\n\n/** Plugin settings. Fields declared as `secret` in `admin.settingsSchema` are encrypted. */\nexport interface SettingsAccess {\n\tget<T>(key: string): Promise<T | null>;\n\tgetVersioned<T>(key: string): Promise<VersionedValue<T> | null>;\n\tcompareAndSet(\n\t\tkey: string,\n\t\texpectedRevision: string | null,\n\t\tvalue: unknown,\n\t): Promise<ConditionalWriteResult>;\n\tcompareAndDelete(key: string, expectedRevision: string): Promise<ConditionalDeleteResult>;\n\tset(key: string, value: unknown): Promise<void>;\n\tdelete(key: string): Promise<boolean>;\n\tlist(prefix?: string): Promise<Array<{ key: string; value: unknown }>>;\n}\n\n/**\n * SEO metadata for a content item, as stored in the core SEO panel.\n *\n * Only present on items in collections with `has_seo = 1`. For collections\n * without SEO enabled, `ContentItem.seo` is `undefined`.\n */\nexport interface ContentItemSeo {\n\ttitle: string | null;\n\tdescription: string | null;\n\timage: string | null;\n\tcanonical: string | null;\n\tnoIndex: boolean;\n}\n\n/**\n * SEO input accepted by content write operations.\n *\n * All fields are optional — only fields that are present overwrite existing\n * values. An empty object is treated as a no-op.\n */\nexport interface ContentItemSeoInput {\n\ttitle?: string | null;\n\tdescription?: string | null;\n\timage?: string | null;\n\tcanonical?: string | null;\n\tnoIndex?: boolean;\n}\n\n/**\n * Content item returned from content API\n */\nexport interface ContentItem {\n\tid: string;\n\ttype: string;\n\tslug: string | null;\n\tstatus: string;\n\tlocale: string | null;\n\tdata: Record<string, unknown>;\n\t/**\n\t * SEO metadata, populated when the collection has SEO enabled\n\t * (`has_seo = 1`). `undefined` for non-SEO collections.\n\t */\n\tseo?: ContentItemSeo;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tpublishedAt: string | null;\n\t/** Scheduled publication time, if set (e.g. scheduled items or scheduled draft changes). */\n\tscheduledAt?: string | null;\n\tauthorId?: string | null;\n\ttranslationGroup?: string | null;\n\tliveRevisionId?: string | null;\n\tdraftRevisionId?: string | null;\n\tversion?: number;\n}\n\nexport interface ContentTranslationSummary {\n\tid: string;\n\tlocale: string | null;\n\tslug: string | null;\n\tstatus: string;\n\tupdatedAt: string;\n}\n\nexport interface ContentRevisionInfo {\n\tid: string;\n\tcollection: string;\n\tentryId: string;\n\tdata: Record<string, unknown>;\n\tcreatedAt: string;\n}\n\nexport interface FieldSchemaInfo {\n\tslug: string;\n\tlabel: string;\n\ttype: FieldType;\n\trequired: boolean;\n\tunique: boolean;\n\tdefault?: unknown;\n\tvalidation?: FieldValidation;\n\twidget?: string;\n\toptions?: FieldWidgetOptions;\n\tsearchable: boolean;\n\tindexed: boolean;\n\ttranslatable: boolean;\n\tsortOrder: number;\n}\n\nexport interface CollectionSchemaInfo {\n\tslug: string;\n\tlabel: string;\n\tlabelSingular: string | null;\n\tdescription: string | null;\n\tsupports: string[];\n\thasSeo: boolean;\n\ttitleField: string | null;\n\tdateField: string | null;\n\turlPattern: string | null;\n\troutable: boolean;\n\thidden: boolean;\n\tfields: FieldSchemaInfo[];\n}\n\nexport interface SchemaAccess {\n\tlistCollections(): Promise<CollectionSchemaInfo[]>;\n\tgetCollection(slug: string): Promise<CollectionSchemaInfo | null>;\n}\n\nexport interface ContentListWhere {\n\t/** Exact match on `status` (e.g. `\"published\"`, `\"draft\"`). */\n\tstatus?: string;\n\t/** Exact match on `locale` (e.g. `\"en\"`, `\"fr-CA\"`). */\n\tlocale?: string;\n\t/** AND-combined filters over custom fields explicitly marked as indexed. */\n\tfieldFilters?: ContentFieldFilters;\n}\n\n/**\n * Content list options\n */\nexport interface ContentListOptions {\n\tlimit?: number;\n\tcursor?: string;\n\torderBy?: Record<string, \"asc\" | \"desc\">;\n\twhere?: ContentListWhere;\n}\n\n/**\n * Input accepted by `content.create` / `content.update`.\n *\n * Most entries are field slugs mapped to their values. The reserved `seo`\n * key is extracted and routed to the core SEO panel (the `_emdash_seo`\n * table), matching the shape accepted by the REST API. Passing `seo` for a\n * collection that does not have SEO enabled throws a validation error.\n */\nexport type ContentWriteInput = Record<string, unknown> & {\n\tseo?: ContentItemSeoInput;\n};\n\n/** Options accepted by `content.create`. */\nexport interface ContentCreateOptions {\n\t/** Locale for the new content row. Defaults to the configured site locale, then `en`. */\n\tlocale?: string;\n\t/** Existing row in the same collection whose translation group the new row joins. */\n\ttranslationOf?: string;\n}\n\nexport type PluginContentCreateCallback = (\n\tpluginId: string,\n\tcollection: string,\n\tdata: ContentWriteInput,\n\toptions?: ContentCreateOptions & {\n\t\t/** Save-hook origin supplied by sandbox transports to prevent hook re-entry. */\n\t\toriginHook?: \"content:beforeSave\" | \"content:afterSave\";\n\t\tsandboxOrigin?: true;\n\t},\n) => Promise<ContentItem>;\n\n/**\n * Taxonomy definition returned from the taxonomy API (e.g. \"category\", \"tag\").\n */\nexport interface TaxonomyDefInfo {\n\tname: string;\n\tlabel: string;\n\tlabelSingular: string | null;\n\thierarchical: boolean;\n\t/** Collections this taxonomy is attached to (e.g. `[\"posts\"]`). */\n\tcollections: string[];\n\tlocale: string;\n}\n\n/**\n * Taxonomy term returned from the taxonomy API. Flat shape — for hierarchical\n * taxonomies the tree is reconstructed via `parentId` (which stores the\n * parent's locale-agnostic `translationGroup`).\n */\nexport interface TaxonomyTermInfo {\n\tid: string;\n\t/** Taxonomy name this term belongs to (e.g. \"category\"). */\n\ttaxonomy: string;\n\tslug: string;\n\tlabel: string;\n\tparentId: string | null;\n\t/** Term metadata as edited in the admin (`description` etc.). */\n\tdata: Record<string, unknown> | null;\n\tlocale: string;\n\ttranslationGroup: string | null;\n}\n\n/**\n * Options accepted by taxonomy read operations. Omitting `locale` returns\n * rows for every locale.\n */\nexport interface TaxonomyReadOptions {\n\tlocale?: string;\n}\n\nexport interface TaxonomyTermCreateInput {\n\tlabel: string;\n\tslug?: string;\n\tparentId?: string | null;\n\tdescription?: string;\n\tlocale?: string;\n\ttranslationOf?: string;\n}\n\n/**\n * Content access interface - capability-gated\n */\nexport interface ContentAccess {\n\t// Read operations (requires read:content)\n\tget(collection: string, id: string): Promise<ContentItem | null>;\n\tlist(collection: string, options?: ContentListOptions): Promise<PaginatedResult<ContentItem>>;\n\tgetTranslations?(\n\t\tcollection: string,\n\t\tid: string,\n\t): Promise<{ translationGroup: string; translations: ContentTranslationSummary[] }>;\n\tgetPublicUrl?(collection: string, id: string): Promise<string | null>;\n\tlistRevisions?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions?: { limit?: number },\n\t): Promise<ContentRevisionInfo[]>;\n\tgetRevision?(\n\t\tcollection: string,\n\t\tid: string,\n\t\trevisionId: string,\n\t): Promise<ContentRevisionInfo | null>;\n\n\t// Write operations (requires write:content) - optional on interface\n\tcreate?(\n\t\tcollection: string,\n\t\tdata: ContentWriteInput,\n\t\toptions?: ContentCreateOptions,\n\t): Promise<ContentItem>;\n\tupdate?(collection: string, id: string, data: ContentWriteInput): Promise<ContentItem>;\n\tdelete?(collection: string, id: string): Promise<boolean>;\n\tgetVersioned?(collection: string, id: string): Promise<VersionedContentItem | null>;\n\tpublish?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tunpublish?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tschedule?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { scheduledAt: string; _rev: string },\n\t): Promise<VersionedContentItem>;\n\tunschedule?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tgetTrashedVersioned?(collection: string, id: string): Promise<VersionedContentItem | null>;\n\trestore?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n}\n\nexport interface VersionedContentItem {\n\titem: ContentItem;\n\t_rev: string;\n}\n\nexport interface ContentPublicationAccess extends ContentAccess {\n\tgetVersioned(collection: string, id: string): Promise<VersionedContentItem | null>;\n\tpublish(collection: string, id: string, options: { _rev: string }): Promise<VersionedContentItem>;\n\tunpublish(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tschedule(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { scheduledAt: string; _rev: string },\n\t): Promise<VersionedContentItem>;\n\tunschedule(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n}\n\nexport interface ContentRestoreAccess {\n\tgetTrashedVersioned(collection: string, id: string): Promise<VersionedContentItem | null>;\n\trestore(collection: string, id: string, options: { _rev: string }): Promise<VersionedContentItem>;\n}\n\n/**\n * Taxonomy access interface — capability-gated on `taxonomies:read`.\n */\nexport interface TaxonomyAccess {\n\t/** List taxonomy definitions. */\n\tgetAll(options?: TaxonomyReadOptions): Promise<TaxonomyDefInfo[]>;\n\t/** All terms of a taxonomy, ordered by label. */\n\tgetTerms(taxonomy: string, options?: TaxonomyReadOptions): Promise<TaxonomyTermInfo[]>;\n\t/** Terms assigned to a content entry, optionally scoped to one taxonomy. */\n\tgetEntryTerms(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\toptions?: TaxonomyReadOptions & { taxonomy?: string },\n\t): Promise<TaxonomyTermInfo[]>;\n\tcreateTerm?(taxonomy: string, input: TaxonomyTermCreateInput): Promise<TaxonomyTermInfo>;\n\taddEntryTerms?(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n\tremoveEntryTerms?(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n}\n\n/** Taxonomy mutations available with `taxonomies:write`. */\nexport interface TaxonomyAccessWithWrite extends TaxonomyAccess {\n\tcreateTerm(taxonomy: string, input: TaxonomyTermCreateInput): Promise<TaxonomyTermInfo>;\n\taddEntryTerms(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n\tremoveEntryTerms(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n}\n\nexport type RedirectStatus = 301 | 302 | 307 | 308 | 410 | 451;\n\nexport interface RedirectInfo {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\ttype: RedirectStatus;\n\tisPattern: boolean;\n\tenabled: boolean;\n\thits: number;\n\tlastHitAt: string | null;\n\tgroupName: string | null;\n\tauto: boolean;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface VersionedRedirect {\n\tredirect: RedirectInfo;\n\t/** Opaque host revision. Pass it back unchanged for update or delete. */\n\t_rev: string;\n}\n\nexport interface RedirectListOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tsearch?: string;\n\tgroup?: string;\n\tenabled?: boolean;\n\tauto?: boolean;\n}\n\nexport interface RedirectCreateInput {\n\tsource: string;\n\tdestination?: string;\n\ttype?: RedirectStatus;\n\tenabled?: boolean;\n\tgroupName?: string | null;\n}\n\nexport interface RedirectUpdateInput {\n\tsource?: string;\n\tdestination?: string;\n\ttype?: RedirectStatus;\n\tenabled?: boolean;\n\tgroupName?: string | null;\n}\n\nexport interface RedirectAccess {\n\tlist(options?: RedirectListOptions): Promise<PaginatedResult<RedirectInfo>>;\n\tget(id: string): Promise<VersionedRedirect | null>;\n\tcreate?(input: RedirectCreateInput): Promise<VersionedRedirect>;\n\tupdate?(id: string, input: RedirectUpdateInput & { _rev: string }): Promise<VersionedRedirect>;\n\tdelete?(id: string, options: { _rev: string }): Promise<boolean>;\n}\n\nexport interface RedirectAccessWithWrite extends RedirectAccess {\n\tcreate(input: RedirectCreateInput): Promise<VersionedRedirect>;\n\tupdate(id: string, input: RedirectUpdateInput & { _rev: string }): Promise<VersionedRedirect>;\n\tdelete(id: string, options: { _rev: string }): Promise<boolean>;\n}\n\n/**\n * Full content access with write operations\n */\nexport interface ContentAccessWithWrite extends ContentAccess {\n\tcreate(\n\t\tcollection: string,\n\t\tdata: ContentWriteInput,\n\t\toptions?: ContentCreateOptions,\n\t): Promise<ContentItem>;\n\tupdate(collection: string, id: string, data: ContentWriteInput): Promise<ContentItem>;\n\tdelete(collection: string, id: string): Promise<boolean>;\n}\n\n/**\n * Media item returned from media API\n */\nexport interface MediaItem {\n\tid: string;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number | null;\n\turl: string;\n\tcreatedAt: string;\n\twidth?: number | null;\n\theight?: number | null;\n\talt?: string | null;\n\tcaption?: string | null;\n\tfocalX?: number | null;\n\tfocalY?: number | null;\n\tblurhash?: string | null;\n\tdominantColor?: string | null;\n\tfolderId?: string | null;\n\tstatus?: \"ready\";\n}\n\nexport interface MediaBytes {\n\tbytes: Uint8Array;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number;\n\tcontentHash?: string;\n}\n\nexport interface MediaMetadataPatch {\n\talt?: string | null;\n\tcaption?: string | null;\n\tfocalX?: number | null;\n\tfocalY?: number | null;\n}\n\n/**\n * Media list options\n */\nexport interface MediaListOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tmimeType?: string; // Filter by mime type prefix, e.g., \"image/\"\n}\n\n/**\n * Media access interface - capability-gated\n */\nexport interface MediaAccess {\n\t// Read operations (requires read:media)\n\tget(id: string): Promise<MediaItem | null>;\n\tlist(options?: MediaListOptions): Promise<PaginatedResult<MediaItem>>;\n\t/** Read ready media bytes, bounded by the caller's limit and the host maximum. */\n\treadBytes?(id: string, options?: { maxBytes?: number }): Promise<MediaBytes>;\n\t/** Change only alt text, caption, or the complete focal-point pair. */\n\tupdateMetadata?(id: string, patch: MediaMetadataPatch): Promise<MediaItem>;\n\n\t// Write operations (requires write:media) - optional on interface\n\tgetUploadUrl?(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t): Promise<{ uploadUrl: string; mediaId: string }>;\n\t/**\n\t * Upload media bytes directly. Preferred in sandboxed mode where\n\t * plugins cannot make external requests to a presigned URL.\n\t * Returns the created media item.\n\t */\n\tupload?(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t\tbytes: ArrayBuffer,\n\t): Promise<{ mediaId: string; storageKey: string; url: string }>;\n\tdelete?(id: string): Promise<boolean>;\n}\n\n/**\n * Full media access with write operations\n */\nexport interface MediaAccessWithWrite extends MediaAccess {\n\tgetUploadUrl(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t): Promise<{ uploadUrl: string; mediaId: string }>;\n\tupload(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t\tbytes: ArrayBuffer,\n\t): Promise<{ mediaId: string; storageKey: string; url: string }>;\n\tdelete(id: string): Promise<boolean>;\n}\n\n/**\n * HTTP client interface - requires network:request capability\n */\nexport interface HttpAccess {\n\t/**\n\t * Fetch an allowed external URL and return a buffered response.\n\t * Decoded request and response bodies are each limited to 8 MiB.\n\t */\n\tfetch(url: string, init?: RequestInit): Promise<Response>;\n}\n\n/**\n * Logger interface - always available\n */\nexport interface LogAccess {\n\tdebug(message: string, data?: unknown): void;\n\tinfo(message: string, data?: unknown): void;\n\twarn(message: string, data?: unknown): void;\n\terror(message: string, data?: unknown): void;\n}\n\n// =============================================================================\n// Site & User Access\n// =============================================================================\n\n/**\n * Site information available to all plugins\n */\nexport interface SiteInfo {\n\t/** Site name (from settings) */\n\tname: string;\n\t/** Site URL (from settings or request) */\n\turl: string;\n\t/** Site locale (from settings, defaults to \"en\") */\n\tlocale: string;\n\t/**\n\t * Astro's `trailingSlash` routing policy, from the host's Astro config.\n\t * Plugins that build absolute URLs (sitemap, canonical, hreflang) should\n\t * honor this so the URLs they emit match what the site serves. `createSiteInfo`\n\t * always populates it (defaulting to `\"ignore\"`, Astro's default); it is\n\t * optional on the type so pre-existing `SiteInfo` construction stays valid.\n\t */\n\ttrailingSlash?: \"always\" | \"never\" | \"ignore\";\n}\n\n/**\n * Read-only user information exposed to plugins.\n * Sensitive fields (password hashes, sessions, passkeys) are excluded.\n */\nexport interface UserInfo {\n\tid: string;\n\temail: string;\n\tname: string | null;\n\trole: number;\n\tcreatedAt: string;\n}\n\n/**\n * User access interface - requires read:users capability\n */\nexport interface UserAccess {\n\t/** Get a user by ID */\n\tget(id: string): Promise<UserInfo | null>;\n\t/** Get a user by email */\n\tgetByEmail(email: string): Promise<UserInfo | null>;\n\t/** List users with optional filters */\n\tlist(opts?: { role?: number; limit?: number; cursor?: string }): Promise<{\n\t\titems: UserInfo[];\n\t\tnextCursor?: string;\n\t}>;\n}\n\nexport type PluginCommentStatus = \"approved\" | \"pending\" | \"spam\";\n\n/** Comment data exposed by the explicit personal-data `comments:read` capability. */\nexport interface PluginComment {\n\tid: string;\n\tcollection: string;\n\tcontentId: string;\n\tparentId: string | null;\n\tauthorName: string;\n\tauthorEmail: string;\n\tbody: string;\n\tstatus: PluginCommentStatus;\n\tipHash: string | null;\n\tuserAgent: string | null;\n\tmoderationMetadata: Record<string, unknown> | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface CommentListOptions {\n\tstatus?: PluginCommentStatus;\n\tcollection?: string;\n\tcontentId?: string;\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface CommentCountOptions {\n\tstatus?: PluginCommentStatus;\n\tcollection?: string;\n\tcontentId?: string;\n}\n\nexport interface CommentAccess {\n\tget(id: string): Promise<PluginComment | null>;\n\tlist(options?: CommentListOptions): Promise<PaginatedResult<PluginComment>>;\n\tcount(options?: CommentCountOptions): Promise<number>;\n\tsetStatus?(\n\t\tid: string,\n\t\tstatus: PluginCommentStatus,\n\t\toptions: { expectedStatus: PluginCommentStatus },\n\t): Promise<PluginComment>;\n}\n\n// =============================================================================\n// Plugin Context\n// =============================================================================\n\n/**\n * The unified plugin context - same shape for all hooks and routes\n */\nexport interface PluginContext<TStorage extends PluginStorageConfig = PluginStorageConfig> {\n\t/** Plugin metadata */\n\tplugin: {\n\t\tid: string;\n\t\tversion: string;\n\t};\n\n\t/** Storage collections - only if plugin declares storage */\n\tstorage: PluginStorage<TStorage>;\n\n\t/** Key-value store for internal state */\n\tkv: KVAccess;\n\n\t/** Plugin settings. Secret schema fields are encrypted by the host. */\n\tsettings: SettingsAccess;\n\n\t/** Content access - only if read:content or write:content capability */\n\tcontent?: ContentAccess | ContentAccessWithWrite;\n\t/** Schema discovery - only if schema:read capability */\n\tschema?: SchemaAccess;\n\n\t/** Taxonomy access - only if a taxonomy capability is declared. */\n\ttaxonomies?: TaxonomyAccess | TaxonomyAccessWithWrite;\n\n\t/** Redirect access - only if redirects:read or redirects:write capability */\n\tredirects?: RedirectAccess | RedirectAccessWithWrite;\n\n\t/** Media access - only if read:media or write:media capability */\n\tmedia?: MediaAccess | MediaAccessWithWrite;\n\n\t/** HTTP client - only if network:request capability */\n\thttp?: HttpAccess;\n\n\t/** Logger - always available */\n\tlog: LogAccess;\n\n\t/** Site information - always available */\n\tsite: SiteInfo;\n\n\t/** URL helper - generates absolute URLs from paths. Always available. */\n\turl(path: string): string;\n\n\t/** User access - only if read:users capability */\n\tusers?: UserAccess;\n\n\t/** Comment access — only if comments:read or comments:moderate is declared. */\n\tcomments?: CommentAccess;\n\n\t/** Cron task scheduling - always available, scoped to plugin */\n\tcron?: CronAccess;\n\n\t/** Email access - only if email:send capability and a provider is configured */\n\temail?: EmailAccess;\n}\n\n// =============================================================================\n// Cron Types\n// =============================================================================\n\n/**\n * Cron access interface �� always available on plugin context, scoped to plugin.\n */\nexport interface CronAccess {\n\t/** Schedule a recurring or one-shot task */\n\tschedule(name: string, opts: { schedule: string; data?: Record<string, unknown> }): Promise<void>;\n\t/** Cancel a scheduled task */\n\tcancel(name: string): Promise<void>;\n\t/** List this plugin's scheduled tasks */\n\tlist(): Promise<CronTaskInfo[]>;\n}\n\n/**\n * Task info returned from CronAccess.list()\n */\nexport interface CronTaskInfo {\n\tname: string;\n\tschedule: string;\n\tnextRunAt: string;\n\tlastRunAt: string | null;\n}\n\n/**\n * Event passed to the `cron` hook handler\n */\nexport interface CronEvent {\n\tname: string;\n\tdata?: Record<string, unknown>;\n\tscheduledAt: string;\n}\n\n/**\n * Cron hook handler type\n */\nexport type CronHandler = (event: CronEvent, ctx: PluginContext) => Promise<void>;\n\n// =============================================================================\n// Email Types\n// =============================================================================\n\n/**\n * Email access interface — requires `email:send` capability.\n * Undefined when no `email:deliver` provider is configured.\n *\n * Related capabilities:\n * - `email:send` — grants ctx.email (this interface)\n * - `email:provide` — allows registering the `email:deliver` exclusive hook\n * - `email:intercept` — allows registering `email:beforeSend` / `email:afterSend` hooks\n */\nexport interface EmailAccess {\n\tsend(message: EmailMessage): Promise<void>;\n}\n\n/**\n * Email message shape\n */\nexport interface EmailMessage {\n\tto: string;\n\t/** Additional visible recipients. */\n\tcc?: string[];\n\t/** Address that replies go to instead of the sender. */\n\treplyTo?: string;\n\tsubject: string;\n\ttext: string;\n\thtml?: string;\n}\n\n/**\n * Event passed to email:beforeSend hooks (middleware — transform, validate, cancel)\n */\nexport interface EmailBeforeSendEvent {\n\tmessage: EmailMessage;\n\t/** Where the email originated — \"system\" for auth emails, plugin ID for plugin emails */\n\tsource: string;\n}\n\n/**\n * Event passed to email:deliver hook (exclusive — exactly one provider delivers)\n */\nexport interface EmailDeliverEvent {\n\tmessage: EmailMessage;\n\tsource: string;\n}\n\n/**\n * Event passed to email:afterSend hooks (logging, analytics, fire-and-forget)\n */\nexport interface EmailAfterSendEvent {\n\tmessage: EmailMessage;\n\tsource: string;\n}\n\n/**\n * Handler type for email:beforeSend hooks.\n * Returns modified message, or false to cancel delivery.\n */\nexport type EmailBeforeSendHandler = (\n\tevent: EmailBeforeSendEvent,\n\tctx: PluginContext,\n) => Promise<EmailMessage | false>;\n\n/**\n * Handler type for email:deliver hooks (exclusive provider).\n */\nexport type EmailDeliverHandler = (event: EmailDeliverEvent, ctx: PluginContext) => Promise<void>;\n\n/**\n * Handler type for email:afterSend hooks (fire-and-forget).\n */\nexport type EmailAfterSendHandler = (\n\tevent: EmailAfterSendEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\n// =============================================================================\n// Comment Types\n// =============================================================================\n\n/**\n * Collection comment settings (read from _emdash_collections)\n */\nexport interface CollectionCommentSettings {\n\tcommentsEnabled: boolean;\n\tcommentsModeration: \"all\" | \"first_time\" | \"none\";\n\tcommentsClosedAfterDays: number;\n\tcommentsAutoApproveUsers: boolean;\n}\n\n/**\n * Event passed to comment:beforeCreate hooks (middleware — transform, enrich, reject)\n */\nexport interface CommentBeforeCreateEvent {\n\tcomment: {\n\t\tcollection: string;\n\t\tcontentId: string;\n\t\tparentId: string | null;\n\t\tauthorName: string;\n\t\tauthorEmail: string;\n\t\tauthorUserId: string | null;\n\t\tbody: string;\n\t\tipHash: string | null;\n\t\tuserAgent: string | null;\n\t};\n\t/** Metadata bag — plugins can attach signals for the moderator */\n\tmetadata: Record<string, unknown>;\n}\n\n/**\n * Event passed to comment:moderate hook (exclusive — decides initial status)\n */\nexport interface CommentModerateEvent {\n\tcomment: CommentBeforeCreateEvent[\"comment\"];\n\tmetadata: Record<string, unknown>;\n\tcollectionSettings: CollectionCommentSettings;\n\t/** Number of prior approved comments from this email address */\n\tpriorApprovedCount: number;\n}\n\n/**\n * Moderation decision returned by the comment:moderate handler\n */\nexport interface ModerationDecision {\n\tstatus: \"approved\" | \"pending\" | \"spam\";\n\t/** Optional reason for admin visibility */\n\treason?: string;\n}\n\n/**\n * Stored comment shape (full record with id, status, timestamps)\n */\nexport interface StoredComment {\n\tid: string;\n\tcollection: string;\n\tcontentId: string;\n\tparentId: string | null;\n\tauthorName: string;\n\tauthorEmail: string;\n\tauthorUserId: string | null;\n\tbody: string;\n\tstatus: string;\n\tmoderationMetadata: Record<string, unknown> | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/**\n * Event passed to comment:afterCreate hooks (fire-and-forget)\n */\nexport interface CommentAfterCreateEvent {\n\tcomment: StoredComment;\n\tmetadata: Record<string, unknown>;\n\t/** The content item the comment is on */\n\tcontent: { id: string; collection: string; slug: string; title?: string };\n\t/** The content author (for notifications) */\n\tcontentAuthor?: { id: string; name: string | null; email: string };\n}\n\n/**\n * Event passed to comment:afterModerate hooks (fire-and-forget, admin status change)\n */\nexport interface CommentAfterModerateEvent {\n\tcomment: StoredComment;\n\tpreviousStatus: string;\n\tnewStatus: string;\n\t/** The admin who moderated */\n\tmoderator: { id: string; name: string | null };\n\t/** Identifies whether an administrator or a plugin initiated the transition. */\n\torigin?: { source: \"admin\"; userId: string } | { source: \"plugin\"; pluginId: string };\n}\n\n/**\n * Handler type for comment:beforeCreate hooks.\n * Returns modified event, or false to reject the comment.\n */\nexport type CommentBeforeCreateHandler = (\n\tevent: CommentBeforeCreateEvent,\n\tctx: PluginContext,\n) => Promise<CommentBeforeCreateEvent | false | void>;\n\n/**\n * Handler type for comment:moderate hook (exclusive provider).\n */\nexport type CommentModerateHandler = (\n\tevent: CommentModerateEvent,\n\tctx: PluginContext,\n) => Promise<ModerationDecision>;\n\n/**\n * Handler type for comment:afterCreate hooks (fire-and-forget).\n */\nexport type CommentAfterCreateHandler = (\n\tevent: CommentAfterCreateEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\n/**\n * Handler type for comment:afterModerate hooks (fire-and-forget).\n */\nexport type CommentAfterModerateHandler = (\n\tevent: CommentAfterModerateEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\n// =============================================================================\n// Hook Types\n// =============================================================================\n\n/**\n * Hook configuration\n */\nexport interface HookConfig<THandler> {\n\t/** Explicit ordering - lower numbers run first (default: 100) */\n\tpriority?: number;\n\t/** Max execution time in ms (default: 5000) */\n\ttimeout?: number;\n\t/** Run after these plugins */\n\tdependencies?: string[];\n\t/** Error handling policy */\n\terrorPolicy?: \"continue\" | \"abort\";\n\t/**\n\t * Mark this hook as exclusive — only one plugin can be the active provider.\n\t * Exclusive hooks skip the priority pipeline and dispatch only to the\n\t * admin-selected provider. Used for email:deliver, search, image optimization, etc.\n\t */\n\texclusive?: boolean;\n\t/** The hook handler */\n\thandler: THandler;\n}\n\n/**\n * Acting user that triggered a content hook. Present for authenticated\n * saves; absent for unauthenticated or internal writes.\n */\nexport interface ActorInfo {\n\treadonly id: string;\n\treadonly role: number;\n\treadonly source?: \"api\" | \"mcp\" | \"visual-editor\";\n}\n\nexport type ContentActionOrigin =\n\t| { source: \"api\" | \"mcp\" | \"visual-editor\" }\n\t| { source: \"plugin\"; pluginId: string }\n\t| { source: \"scheduler\" }\n\t| { source: \"system\" };\n\nexport type ContentPolicyDecision = void | { cancel: true; reason: string };\n\n/**\n * Content hook event\n */\nexport interface ContentHookEvent {\n\tcontent: Record<string, unknown>;\n\tcollection: string;\n\tisNew: boolean;\n\t/**\n\t * ID of the existing item on `content:beforeSave` for an update. Absent on\n\t * creates, where the ID is assigned when the save completes, and on\n\t * `content:afterSave`, where `content.id` carries it.\n\t */\n\tid?: string;\n\t/**\n\t * The acting user for this save. Carries the same authenticated identity\n\t * used to set the revision author, so plugins (e.g. audit logs) can record\n\t * who made the change.\n\t */\n\tactor?: ActorInfo;\n}\n\n/**\n * Content delete hook event\n */\nexport interface ContentDeleteEvent {\n\tid: string;\n\tcollection: string;\n\t/** `true` when the content is permanently deleted (not just trashed). */\n\tpermanent: boolean;\n}\n\n/**\n * Content state-change hook event (fired after publish, unpublish, restore,\n * schedule, or unschedule).\n */\nexport interface ContentStateChangeEvent {\n\tcontent: Record<string, unknown>;\n\tcollection: string;\n}\n\n/**\n * Content publish/unpublish hook event.\n */\nexport type ContentPublishStateChangeEvent = ContentStateChangeEvent;\n\n/**\n * Content restore hook event.\n */\nexport type ContentRestoreStateChangeEvent = ContentStateChangeEvent;\n\n/**\n * Content schedule/unschedule hook event.\n */\nexport type ContentScheduleStateChangeEvent = ContentStateChangeEvent;\n\nexport interface ContentPolicyEvent extends ContentStateChangeEvent {\n\torigin: ContentActionOrigin;\n\tactor?: ActorInfo;\n}\n\nexport interface ContentSchedulePolicyEvent extends ContentPolicyEvent {\n\tscheduledAt: string;\n}\n\n/**\n * Media hook event\n */\nexport interface MediaUploadEvent {\n\tfile: { name: string; type: string; size: number };\n}\n\n/**\n * Media after upload event\n */\nexport interface MediaAfterUploadEvent {\n\tmedia: MediaItem;\n}\n\n/**\n * Lifecycle hook event\n */\nexport interface LifecycleEvent {\n\t// Empty for install/activate/deactivate\n}\n\n/**\n * Uninstall hook event\n */\nexport interface UninstallEvent {\n\tdeleteData: boolean;\n}\n\n// Hook handler types - all receive (event, ctx) with unified context\nexport type ContentBeforeSaveHandler = (\n\tevent: ContentHookEvent,\n\tctx: PluginContext,\n) => Promise<Record<string, unknown> | void>;\n\nexport type ContentAfterSaveHandler = (\n\tevent: ContentHookEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentBeforeDeleteHandler = (\n\tevent: ContentDeleteEvent,\n\tctx: PluginContext,\n) => Promise<boolean | void>;\n\nexport type ContentAfterDeleteHandler = (\n\tevent: ContentDeleteEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentBeforePublishHandler = (\n\tevent: ContentPolicyEvent,\n\tctx: PluginContext,\n) => Promise<ContentPolicyDecision>;\n\nexport type ContentBeforeScheduleHandler = (\n\tevent: ContentSchedulePolicyEvent,\n\tctx: PluginContext,\n) => Promise<ContentPolicyDecision>;\n\nexport type ContentBeforeUnpublishHandler = (\n\tevent: ContentPolicyEvent,\n\tctx: PluginContext,\n) => Promise<ContentPolicyDecision>;\n\nexport type ContentAfterPublishHandler = (\n\tevent: ContentPublishStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterUnpublishHandler = (\n\tevent: ContentPublishStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterRestoreHandler = (\n\tevent: ContentRestoreStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterScheduleHandler = (\n\tevent: ContentScheduleStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterUnscheduleHandler = (\n\tevent: ContentScheduleStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type MediaBeforeUploadHandler = (\n\tevent: MediaUploadEvent,\n\tctx: PluginContext,\n) => Promise<{ name: string; type: string; size: number } | void>;\n\nexport type MediaAfterUploadHandler = (\n\tevent: MediaAfterUploadEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type LifecycleHandler = (event: LifecycleEvent, ctx: PluginContext) => Promise<void>;\n\nexport type UninstallHandler = (event: UninstallEvent, ctx: PluginContext) => Promise<void>;\n\n// =============================================================================\n// Public Page Contribution Types\n// =============================================================================\n\n/** Placement targets for page fragment contributions */\nexport type PagePlacement = \"head\" | \"body:start\" | \"body:end\";\n\n/**\n * A single breadcrumb trail item. Used by `PublicPageContext.breadcrumbs`\n * so themes can publish breadcrumb trails that SEO plugins consume.\n */\nexport interface BreadcrumbItem {\n\t/** Display name for this crumb (e.g. \"Home\", \"Blog\", \"My Post\"). */\n\tname: string;\n\t/** Absolute or root-relative URL for this crumb. */\n\turl: string;\n}\n\n/**\n * Describes the page being rendered. Passed to page hooks so plugins\n * can decide what to contribute without fetching content themselves.\n */\nexport interface PublicPageContext {\n\turl: string;\n\tpath: string;\n\tlocale: string | null;\n\tkind: \"content\" | \"custom\";\n\tpageType: string;\n\t/** Full document title for the rendered page */\n\ttitle: string | null;\n\t/** Page-only title for OG/Twitter/JSON-LD headline output */\n\tpageTitle?: string | null;\n\tdescription: string | null;\n\tcanonical: string | null;\n\timage: string | null;\n\tcontent?: {\n\t\tcollection: string;\n\t\tid: string;\n\t\tslug: string | null;\n\t};\n\t/** SEO meta for base metadata generation in EmDashHead */\n\tseo?: {\n\t\togTitle?: string | null;\n\t\togDescription?: string | null;\n\t\togImage?: string | null;\n\t\trobots?: string | null;\n\t};\n\t/** Article metadata for Open Graph article: tags */\n\tarticleMeta?: {\n\t\tpublishedTime?: string | null;\n\t\tmodifiedTime?: string | null;\n\t\tauthor?: string | null;\n\t};\n\t/** Site name for structured data and og:site_name */\n\tsiteName?: string;\n\t/**\n\t * Optional breadcrumb trail for this page, root first. When set,\n\t * SEO plugins should use this verbatim rather than deriving a trail\n\t * from `path`. Themes typically populate this at the point they\n\t * build the context (e.g. from a content hierarchy walk, taxonomy\n\t * lookup, or per-`pageType` routing logic).\n\t *\n\t * Semantics for consumers:\n\t * - `undefined` — theme has no opinion; consumer falls back to\n\t * its own derivation.\n\t * - `[]` — this page has no breadcrumbs (e.g. homepage); consumer\n\t * should skip `BreadcrumbList` emission entirely.\n\t * - Non-empty array — used verbatim for `BreadcrumbList` output.\n\t */\n\tbreadcrumbs?: BreadcrumbItem[];\n\t/** Public-facing site URL (origin) for structured data */\n\tsiteUrl?: string;\n}\n\n// ── page:metadata ───────────────────────────────────────────────\n\nexport interface PageMetadataEvent {\n\tpage: PublicPageContext;\n}\n\n/**\n * Allowed rel values for link contributions.\n * This is a security-critical allowlist -- sandboxed plugins can only inject\n * link tags with these rel values. Adding \"stylesheet\", \"prefetch\", \"prerender\"\n * etc. would allow sandboxed plugins to inject external resources.\n */\nexport type PageMetadataLinkRel =\n\t| \"canonical\"\n\t| \"alternate\"\n\t| \"author\"\n\t| \"license\"\n\t| \"nlweb\"\n\t| \"site.standard.document\";\n\nexport type PageMetadataContribution =\n\t| { kind: \"meta\"; name: string; content: string; key?: string }\n\t| { kind: \"property\"; property: string; content: string; key?: string }\n\t| { kind: \"link\"; rel: PageMetadataLinkRel; href: string; hreflang?: string; key?: string }\n\t| {\n\t\t\tkind: \"jsonld\";\n\t\t\tid?: string;\n\t\t\tgraph: Record<string, unknown> | Array<Record<string, unknown>>;\n\t };\n\nexport type PageMetadataHandler = (\n\tevent: PageMetadataEvent,\n\tctx: PluginContext,\n) =>\n\t| PageMetadataContribution\n\t| PageMetadataContribution[]\n\t| null\n\t| Promise<PageMetadataContribution | PageMetadataContribution[] | null>;\n\n// ── page:fragments (trusted-only) ──────────────────────────────\n\nexport interface PageFragmentEvent {\n\tpage: PublicPageContext;\n}\n\nexport type PageFragmentContribution =\n\t| {\n\t\t\tkind: \"external-script\";\n\t\t\tplacement: PagePlacement;\n\t\t\tsrc: string;\n\t\t\tasync?: boolean;\n\t\t\tdefer?: boolean;\n\t\t\tattributes?: Record<string, string>;\n\t\t\tkey?: string;\n\t }\n\t| {\n\t\t\tkind: \"inline-script\";\n\t\t\tplacement: PagePlacement;\n\t\t\tcode: string;\n\t\t\tattributes?: Record<string, string>;\n\t\t\tkey?: string;\n\t }\n\t| {\n\t\t\tkind: \"html\";\n\t\t\tplacement: PagePlacement;\n\t\t\thtml: string;\n\t\t\tkey?: string;\n\t };\n\nexport type PageFragmentHandler = (\n\tevent: PageFragmentEvent,\n\tctx: PluginContext,\n) =>\n\t| PageFragmentContribution\n\t| PageFragmentContribution[]\n\t| null\n\t| Promise<PageFragmentContribution | PageFragmentContribution[] | null>;\n\n/**\n * Plugin hooks definition\n */\nexport interface PluginHooks {\n\t// Lifecycle hooks\n\t\"plugin:install\"?: HookConfig<LifecycleHandler> | LifecycleHandler;\n\t\"plugin:activate\"?: HookConfig<LifecycleHandler> | LifecycleHandler;\n\t\"plugin:deactivate\"?: HookConfig<LifecycleHandler> | LifecycleHandler;\n\t\"plugin:uninstall\"?: HookConfig<UninstallHandler> | UninstallHandler;\n\n\t// Content hooks\n\t\"content:beforeSave\"?: HookConfig<ContentBeforeSaveHandler> | ContentBeforeSaveHandler;\n\t\"content:afterSave\"?: HookConfig<ContentAfterSaveHandler> | ContentAfterSaveHandler;\n\t\"content:beforeDelete\"?: HookConfig<ContentBeforeDeleteHandler> | ContentBeforeDeleteHandler;\n\t\"content:afterDelete\"?: HookConfig<ContentAfterDeleteHandler> | ContentAfterDeleteHandler;\n\t\"content:beforePublish\"?: HookConfig<ContentBeforePublishHandler> | ContentBeforePublishHandler;\n\t\"content:beforeSchedule\"?:\n\t\t| HookConfig<ContentBeforeScheduleHandler>\n\t\t| ContentBeforeScheduleHandler;\n\t\"content:beforeUnpublish\"?:\n\t\t| HookConfig<ContentBeforeUnpublishHandler>\n\t\t| ContentBeforeUnpublishHandler;\n\t\"content:afterPublish\"?: HookConfig<ContentAfterPublishHandler> | ContentAfterPublishHandler;\n\t\"content:afterUnpublish\"?:\n\t\t| HookConfig<ContentAfterUnpublishHandler>\n\t\t| ContentAfterUnpublishHandler;\n\t\"content:afterRestore\"?: HookConfig<ContentAfterRestoreHandler> | ContentAfterRestoreHandler;\n\t\"content:afterSchedule\"?: HookConfig<ContentAfterScheduleHandler> | ContentAfterScheduleHandler;\n\t\"content:afterUnschedule\"?:\n\t\t| HookConfig<ContentAfterUnscheduleHandler>\n\t\t| ContentAfterUnscheduleHandler;\n\n\t// Media hooks\n\t\"media:beforeUpload\"?: HookConfig<MediaBeforeUploadHandler> | MediaBeforeUploadHandler;\n\t\"media:afterUpload\"?: HookConfig<MediaAfterUploadHandler> | MediaAfterUploadHandler;\n\n\t// Cron hook\n\tcron?: HookConfig<CronHandler> | CronHandler;\n\n\t// Email hooks\n\t\"email:beforeSend\"?: HookConfig<EmailBeforeSendHandler> | EmailBeforeSendHandler;\n\t\"email:deliver\"?: HookConfig<EmailDeliverHandler> | EmailDeliverHandler;\n\t\"email:afterSend\"?: HookConfig<EmailAfterSendHandler> | EmailAfterSendHandler;\n\n\t// Comment hooks\n\t\"comment:beforeCreate\"?: HookConfig<CommentBeforeCreateHandler> | CommentBeforeCreateHandler;\n\t\"comment:moderate\"?: HookConfig<CommentModerateHandler> | CommentModerateHandler;\n\t\"comment:afterCreate\"?: HookConfig<CommentAfterCreateHandler> | CommentAfterCreateHandler;\n\t\"comment:afterModerate\"?: HookConfig<CommentAfterModerateHandler> | CommentAfterModerateHandler;\n\n\t// Public page hooks\n\t\"page:metadata\"?: HookConfig<PageMetadataHandler> | PageMetadataHandler;\n\t\"page:fragments\"?: HookConfig<PageFragmentHandler> | PageFragmentHandler;\n}\n\n/**\n * Hook names\n */\n/**\n * Hook name in a manifest. Core's exhaustive union of recognised hook names,\n * derived from the `PluginHooks` registry. The serialised manifest carries\n * these as opaque strings; this stricter type is only used for type-checking\n * inside core. `ManifestHookEntry` is re-exported from\n * `@emdash-cms/plugin-types` near the top of this file.\n */\nexport type HookName = keyof PluginHooks;\n\n/**\n * Resolved hook with normalized config\n */\nexport interface ResolvedHook<THandler> {\n\tpriority: number;\n\ttimeout: number;\n\tdependencies: string[];\n\terrorPolicy: \"continue\" | \"abort\";\n\t/** Whether this hook is exclusive (provider pattern) */\n\texclusive: boolean;\n\thandler: THandler;\n\tpluginId: string;\n}\n\n// =============================================================================\n// Request Metadata Types\n// =============================================================================\n\n/**\n * Geographic location information derived from the request.\n * Available when running on Cloudflare Workers (via the `cf` object).\n */\nexport interface GeoInfo {\n\tcountry: string | null;\n\tregion: string | null;\n\tcity: string | null;\n}\n\n/**\n * Normalized request metadata available to plugin route handlers.\n * Extracted from request headers and platform-specific properties.\n */\nexport interface RequestMeta {\n\tip: string | null;\n\tuserAgent: string | null;\n\treferer: string | null;\n\tgeo: GeoInfo | null;\n}\n\n// =============================================================================\n// Route Types\n// =============================================================================\n\n/**\n * Route handler context extends plugin context with request-specific data\n */\nexport interface RouteContext<TInput = unknown> extends PluginContext {\n\t/** Validated input from request body */\n\tinput: TInput;\n\t/** Original request */\n\trequest: Request;\n\t/** Normalized request metadata (IP, user agent, geo) */\n\trequestMeta: RequestMeta;\n\t/** Host-attested context for a validated Block Kit request. */\n\tui?: PluginUiContext;\n\t/**\n\t * Authenticated caller, if the route is private. The host has already\n\t * authenticated and authorized this user before dispatch, so the value\n\t * is trustworthy — unlike a user id read from the request body.\n\t *\n\t * `undefined` for public routes (which skip auth entirely) and for\n\t * token-authed requests where no user is bound to the token.\n\t *\n\t * Not gated by the `users:read` capability: this is the caller's own\n\t * identity for the current request, not a user directory lookup.\n\t */\n\tuser?: UserInfo;\n}\n\n/**\n * Route definition\n */\nexport interface PluginRoute<TInput = unknown> extends Omit<RouteOptions, \"request\"> {\n\t/** Zod schema for input validation */\n\tinput?: z.ZodType<TInput>;\n\t/**\n\t * Mark this route as publicly accessible (no authentication required).\n\t * Public routes skip session/token auth and CSRF checks.\n\t */\n\tpublic?: boolean;\n\t/** RBAC permission required to invoke the route. Legacy routes default to plugins:manage. */\n\tpermission?: Permission;\n\t/**\n\t * `Cache-Control` header value for successful GET responses, e.g.\n\t * `\"public, max-age=60, stale-while-revalidate=300\"`. Only honored on\n\t * routes that are also `public: true` — authenticated responses always\n\t * keep the default `private, no-store`. Errors are never cached.\n\t */\n\tcacheControl?: string;\n\t/** Bounded request parsing and incoming-header declaration. */\n\trequest?: PluginRouteRequest;\n\t/** Route handler */\n\thandler: { bivarianceHack(ctx: RouteContext<TInput>): Promise<unknown> }[\"bivarianceHack\"];\n}\n\nexport type PluginRouteInput<TMode extends PluginRouteBodyMode> = TMode extends \"none\"\n\t? PluginRouteQuery\n\t: TMode extends \"text\"\n\t\t? string\n\t\t: TMode extends \"bytes\"\n\t\t\t? Uint8Array\n\t\t\t: TMode extends \"form-data\"\n\t\t\t\t? PluginFormData\n\t\t\t\t: unknown;\n\nexport type PluginRouteDefinition<TMode extends PluginRouteBodyMode = PluginRouteBodyMode> = Omit<\n\tPluginRoute<PluginRouteInput<TMode>>,\n\t\"request\"\n> & {\n\trequest: PluginRouteRequest & { body: TMode };\n};\n\nexport interface PluginMcpToolDefinition {\n\tdescription: string;\n\troute: string;\n\tinput: z.ZodType;\n\toutput?: z.ZodType;\n\tdestructive?: boolean;\n}\n\nexport interface PluginMcpConfig {\n\ttools: Record<string, PluginMcpToolDefinition>;\n}\n\n// =============================================================================\n// Plugin Definition\n// =============================================================================\n\n/**\n * Admin page definition\n */\nexport interface PluginAdminPage {\n\tpath: string;\n\tlabel: string;\n\ticon?: string;\n}\n\n/**\n * Dashboard widget definition\n */\nexport interface PluginDashboardWidget {\n\tid: string;\n\tsize?: \"full\" | \"half\" | \"third\";\n\ttitle?: string;\n}\n\nexport interface PluginEditorPanel {\n\tid: string;\n\ttitle: string;\n\troute: string;\n\tcollections?: string[];\n\torder?: number;\n\tdraft?: PluginEditorDraftAccess;\n}\n\nexport interface PluginEditorAction {\n\tid: string;\n\tlabel: string;\n\troute: string;\n\tplacement: \"toolbar\" | \"overflow\";\n\tcollections?: string[];\n\tstyle?: \"default\" | \"danger\";\n\tconfirm?: ConfirmDialog;\n\tdraft?: PluginEditorDraftAccess;\n}\n\n/**\n * Settings field types (for admin UI generation)\n */\nexport type SettingFieldType =\n\t| \"string\"\n\t| \"number\"\n\t| \"boolean\"\n\t| \"select\"\n\t| \"secret\"\n\t| \"url\"\n\t| \"email\";\n\nexport interface BaseSettingField {\n\ttype: SettingFieldType;\n\tlabel: string;\n\tdescription?: string;\n}\n\nexport interface StringSettingField extends BaseSettingField {\n\ttype: \"string\";\n\tdefault?: string;\n\tmultiline?: boolean;\n}\n\nexport interface NumberSettingField extends BaseSettingField {\n\ttype: \"number\";\n\tdefault?: number;\n\tmin?: number;\n\tmax?: number;\n}\n\nexport interface BooleanSettingField extends BaseSettingField {\n\ttype: \"boolean\";\n\tdefault?: boolean;\n}\n\nexport interface SelectSettingField extends BaseSettingField {\n\ttype: \"select\";\n\toptions: Array<{ value: string; label: string }>;\n\tdefault?: string;\n}\n\nexport interface SecretSettingField extends BaseSettingField {\n\ttype: \"secret\";\n}\n\nexport interface UrlSettingField extends BaseSettingField {\n\ttype: \"url\";\n\tdefault?: string;\n\tplaceholder?: string;\n}\n\nexport interface EmailSettingField extends BaseSettingField {\n\ttype: \"email\";\n\tdefault?: string;\n\tplaceholder?: string;\n}\n\nexport type SettingField =\n\t| StringSettingField\n\t| NumberSettingField\n\t| BooleanSettingField\n\t| SelectSettingField\n\t| SecretSettingField\n\t| UrlSettingField\n\t| EmailSettingField;\n\n/**\n * Block Kit element for block editing fields.\n * This is the `Element` discriminated union from `@emdash-cms/blocks`.\n * Plugin authors should use `@emdash-cms/blocks` builder functions to create these.\n */\nexport type PortableTextBlockField = Element;\n\n/**\n * Configuration for a Portable Text block type contributed by a plugin\n */\nexport interface PortableTextBlockConfig {\n\t/** Block type name (must match the `_type` in Portable Text) */\n\ttype: string;\n\t/** Human-readable label shown in slash commands and modals */\n\tlabel: string;\n\t/** Icon key (e.g., \"video\", \"code\", \"link\", \"link-external\") */\n\ticon?: string;\n\t/** Description shown in slash command menu */\n\tdescription?: string;\n\t/** Placeholder text for the URL input */\n\tplaceholder?: string;\n\t/** Block Kit form fields for the editing UI. If declared, replaces the simple URL input. */\n\tfields?: PortableTextBlockField[];\n\t/**\n\t * Optional. Display category in the slash menu. Defaults to \"Embeds\".\n\t *\n\t * Plugin authors should pick a meaningful category that reflects what the\n\t * block actually is — e.g. \"Sections\", \"Marketing\", \"Media\", \"Embeds\",\n\t * \"Layout\". Blocks with the same category are grouped together in the\n\t * editor's slash menu.\n\t */\n\tcategory?: string;\n}\n\n/**\n * Configuration for a field widget type contributed by a plugin.\n * A field widget provides a custom editing UI for a schema field.\n * The field references the widget via `widget: \"pluginId:widgetName\"`.\n */\nexport interface FieldWidgetConfig {\n\t/** Widget name (without plugin ID prefix) */\n\tname: string;\n\t/** Human-readable label for the admin UI */\n\tlabel: string;\n\t/** Which field types this widget can edit (e.g., [\"json\", \"string\"]) */\n\tfieldTypes: FieldType[];\n\t/** Block Kit elements for sandboxed rendering. Omit for trusted plugins using React. */\n\telements?: Element[];\n}\n\n/**\n * Admin configuration\n */\nexport interface PluginAdminConfig {\n\t/** Module specifier for admin UI exports (e.g., \"@emdash-cms/plugin-audit-log/admin\") */\n\tentry?: string;\n\t/** Settings schema for auto-generated UI */\n\tsettingsSchema?: Record<string, SettingField>;\n\t/** Admin pages */\n\tpages?: PluginAdminPage[];\n\t/** Dashboard widgets */\n\twidgets?: PluginDashboardWidget[];\n\t/** Saved-entry Block Kit panels. */\n\teditorPanels?: PluginEditorPanel[];\n\t/** Saved-entry host-rendered actions. */\n\teditorActions?: PluginEditorAction[];\n\t/** Portable Text block types this plugin provides */\n\tportableTextBlocks?: PortableTextBlockConfig[];\n\t/** Field widget types this plugin provides */\n\tfieldWidgets?: FieldWidgetConfig[];\n}\n\n/**\n * Plugin definition - input to definePlugin()\n */\nexport interface PluginDefinition<TStorage extends PluginStorageConfig = PluginStorageConfig> {\n\t/** Unique plugin identifier */\n\tid: string;\n\t/** Plugin version (semver) */\n\tversion: string;\n\n\t/** Declared capabilities */\n\tcapabilities?: PluginCapability[];\n\n\t/** Allowed hosts for network:request (wildcards supported: *.example.com) */\n\tallowedHosts?: string[];\n\n\t/** Storage collections with indexes */\n\tstorage?: TStorage;\n\n\t/** Hooks */\n\thooks?: PluginHooks;\n\n\t/** API routes */\n\troutes?: Record<string, PluginRoute>;\n\n\t/** Routes explicitly exposed as agent-callable MCP tools. */\n\tmcp?: PluginMcpConfig;\n\n\t/** Admin UI configuration */\n\tadmin?: PluginAdminConfig;\n}\n\n/**\n * Resolved plugin - after definePlugin() processing\n */\nexport interface ResolvedPlugin<TStorage extends PluginStorageConfig = PluginStorageConfig> {\n\tid: string;\n\tversion: string;\n\tcapabilities: PluginCapability[];\n\tallowedHosts: string[];\n\tstorage: TStorage;\n\thooks: ResolvedPluginHooks;\n\troutes: Record<string, PluginRoute>;\n\tmcp?: PluginMcpConfig;\n\tadmin: PluginAdminConfig;\n}\n\n/**\n * Resolved hooks with normalized config\n */\nexport interface ResolvedPluginHooks {\n\t\"plugin:install\"?: ResolvedHook<LifecycleHandler>;\n\t\"plugin:activate\"?: ResolvedHook<LifecycleHandler>;\n\t\"plugin:deactivate\"?: ResolvedHook<LifecycleHandler>;\n\t\"plugin:uninstall\"?: ResolvedHook<UninstallHandler>;\n\t\"content:beforeSave\"?: ResolvedHook<ContentBeforeSaveHandler>;\n\t\"content:afterSave\"?: ResolvedHook<ContentAfterSaveHandler>;\n\t\"content:beforeDelete\"?: ResolvedHook<ContentBeforeDeleteHandler>;\n\t\"content:afterDelete\"?: ResolvedHook<ContentAfterDeleteHandler>;\n\t\"content:beforePublish\"?: ResolvedHook<ContentBeforePublishHandler>;\n\t\"content:beforeSchedule\"?: ResolvedHook<ContentBeforeScheduleHandler>;\n\t\"content:beforeUnpublish\"?: ResolvedHook<ContentBeforeUnpublishHandler>;\n\t\"content:afterPublish\"?: ResolvedHook<ContentAfterPublishHandler>;\n\t\"content:afterUnpublish\"?: ResolvedHook<ContentAfterUnpublishHandler>;\n\t\"content:afterRestore\"?: ResolvedHook<ContentAfterRestoreHandler>;\n\t\"content:afterSchedule\"?: ResolvedHook<ContentAfterScheduleHandler>;\n\t\"content:afterUnschedule\"?: ResolvedHook<ContentAfterUnscheduleHandler>;\n\t\"media:beforeUpload\"?: ResolvedHook<MediaBeforeUploadHandler>;\n\t\"media:afterUpload\"?: ResolvedHook<MediaAfterUploadHandler>;\n\tcron?: ResolvedHook<CronHandler>;\n\t\"email:beforeSend\"?: ResolvedHook<EmailBeforeSendHandler>;\n\t\"email:deliver\"?: ResolvedHook<EmailDeliverHandler>;\n\t\"email:afterSend\"?: ResolvedHook<EmailAfterSendHandler>;\n\t\"comment:beforeCreate\"?: ResolvedHook<CommentBeforeCreateHandler>;\n\t\"comment:moderate\"?: ResolvedHook<CommentModerateHandler>;\n\t\"comment:afterCreate\"?: ResolvedHook<CommentAfterCreateHandler>;\n\t\"comment:afterModerate\"?: ResolvedHook<CommentAfterModerateHandler>;\n\t\"page:metadata\"?: ResolvedHook<PageMetadataHandler>;\n\t\"page:fragments\"?: ResolvedHook<PageFragmentHandler>;\n}\n\n// =============================================================================\n// Plugin Admin Exports\n// =============================================================================\n\n/**\n * What a plugin exports from its /admin entrypoint\n * Uses generic component type to avoid React dependency\n */\nexport interface PluginAdminExports {\n\twidgets?: Record<string, JSX.Element>;\n\tpages?: Record<string, JSX.Element>;\n\tfields?: Record<string, JSX.Element>;\n}\n\n// =============================================================================\n// Sandbox Types\n// =============================================================================\n\n/**\n * Plugin manifest — the metadata portion of a plugin bundle, used for\n * sandboxed plugins loaded from the marketplace.\n *\n * This interface is core's stricter version of the manifest contract: it\n * uses the exhaustive `HookName` union and core's typed `PluginAdminConfig`.\n * The wire-shape lives in `@emdash-cms/plugin-types` as `PluginManifest`\n * with looser types (so the registry CLI can serialise hook names it\n * doesn't know about). Both must stay structurally compatible: every value\n * of this type must be assignable to the shared one. The static assertion\n * below catches any drift at compile time.\n */\nexport interface PluginManifest {\n\tid: string;\n\tversion: string;\n\t/**\n\t * The trust contract (see `@emdash-cms/plugin-types`). Authoritative;\n\t * `capabilities`/`allowedHosts` are derived from it at the parse boundary\n\t * via `reconcileManifestAccess`. Optional during the wire-format migration.\n\t */\n\tdeclaredAccess?: DeclaredAccess;\n\tcapabilities: PluginCapability[];\n\tallowedHosts: string[];\n\tstorage: PluginStorageConfig;\n\t/** Hook declarations — either plain name strings or structured objects */\n\thooks: Array<ManifestHookEntry | HookName>;\n\t/** Route declarations — either plain name strings or structured objects */\n\troutes: Array<ManifestRouteEntry | string>;\n\tmcp?: PluginMcpManifestConfig;\n\tadmin: PluginAdminConfig;\n}\n\n// Type-level guard: core's `PluginManifest` is intentionally a SUBTYPE of\n// the shared wire shape (`@emdash-cms/plugin-types` `PluginManifest`). The\n// wire shape uses looser types like `string` for hook names so the registry\n// CLI can serialise plugins targeting hook versions this core doesn't yet\n// know about. Core narrows `string` to `HookName` and `Record<string,\n// unknown>` to `PluginAdminConfig` because core's loader actually executes\n// against those types.\n//\n// We assert one direction at compile time: `core extends shared`. The\n// reverse direction (`shared extends core`) intentionally does NOT hold\n// because shared is wider -- a manifest written against the wire shape\n// could carry a hook name core doesn't know. That runtime narrowing is the\n// job of `manifest-schema.ts` (zod-validated, called at every JSON.parse\n// of a manifest.json), not of the type system. The static check below\n// catches the OTHER failure mode: core adding a required field or\n// non-assignable type that the wire shape doesn't allow.\n//\n// `type X = never` is itself legal as a type alias, so the assertion has to\n// be in a value position (`const _check: T = true`) for the compiler to\n// error when T resolves to `never`. Don't replace this with a bare type\n// alias.\ntype _AssertManifestCompat =\n\tPluginManifest extends import(\"@emdash-cms/plugin-types\").PluginManifest ? true : never;\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst _MANIFEST_COMPAT: _AssertManifestCompat = true;\n"],"mappings":";;;AAmFA,MAAa,iCAET;CACH,CAAC,iBAAiB,eAAe;CACjC,CAAC,0BAA0B,eAAe;CAC1C,CAAC,oBAAoB,kBAAkB;CACvC,CAAC,mBAAmB,eAAe;CACnC,CAAC,eAAe,aAAa;CAC7B,CAAC,qBAAqB,gBAAgB;CACtC,CAAC,mBAAmB,iBAAiB;CACrC,CAAC,gCAAgC,kBAAkB;CACnD;AAMD,SAAgB,4BAA4B,cAA2C;CACtF,MAAM,aAAa,IAAI,IAAI,sBAAsB,aAAa,CAAC;AAC/D,MAAK,MAAM,CAAC,SAAS,YAAY,+BAChC,KAAI,WAAW,IAAI,QAAQ,CAAE,YAAW,IAAI,QAAQ;AAErD,QAAO,CAAC,GAAG,WAAW"}
@@ -0,0 +1,103 @@
1
+ import { i as encodeBase64, t as decodeBase64 } from "./base64-DvnNgP7e.mjs";
2
+
3
+ //#region src/database/repositories/types.ts
4
+ /**
5
+ * Hard cap on cursor length. Cursors we issue are short JSON-in-base64
6
+ * blobs; a real cursor is well under 200 chars. This guards against
7
+ * malicious callers passing megabyte-sized strings to force the base64
8
+ * decoder to allocate (decodeBase64 is O(N) in input size). The MCP and
9
+ * REST schemas also clamp at 2048 — this 4096 cap is a defense-in-depth
10
+ * floor inside the repository helpers.
11
+ */
12
+ const MAX_CURSOR_LENGTH = 4096;
13
+ /**
14
+ * Order value stamped into a cursor over a *staged* reference selection, whose
15
+ * anchor is a translation group rather than a row in the link table.
16
+ *
17
+ * A preview and a public render page the same field from different places, so a
18
+ * cursor can cross that boundary in either direction — the draft publishes, or
19
+ * the preview session ends, mid-pagination. Both sides recognise this marker so
20
+ * they can tell a foreign cursor from a malformed one and restart the field's
21
+ * page rather than failing or silently emptying it.
22
+ */
23
+ const STAGED_CURSOR_MARKER = "staged";
24
+ /** Encode a cursor from order value + id */
25
+ function encodeCursor(orderValue, id) {
26
+ return encodeBase64(JSON.stringify({
27
+ orderValue,
28
+ id
29
+ }));
30
+ }
31
+ /**
32
+ * Thrown when a pagination cursor cannot be decoded.
33
+ *
34
+ * Repository callers should let this propagate; handler catch blocks
35
+ * map it to a structured `INVALID_CURSOR` error so client pagination
36
+ * bugs surface immediately rather than silently re-fetching the first
37
+ * page.
38
+ */
39
+ var InvalidCursorError = class extends Error {
40
+ constructor(cursor) {
41
+ const display = cursor.length > 50 ? `${cursor.slice(0, 47)}...` : cursor;
42
+ super(`Invalid pagination cursor: ${display}`);
43
+ this.name = "InvalidCursorError";
44
+ }
45
+ };
46
+ /**
47
+ * Decode a cursor to order value + id.
48
+ *
49
+ * Throws `InvalidCursorError` if the cursor is empty, not valid base64,
50
+ * not valid JSON, or doesn't contain string `orderValue` and `id` fields.
51
+ */
52
+ function decodeCursor(cursor) {
53
+ if (!cursor) throw new InvalidCursorError(cursor);
54
+ if (cursor.length > MAX_CURSOR_LENGTH) throw new InvalidCursorError(cursor);
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(decodeBase64(cursor));
58
+ } catch {
59
+ throw new InvalidCursorError(cursor);
60
+ }
61
+ if (parsed === null || typeof parsed !== "object") throw new InvalidCursorError(cursor);
62
+ const candidate = parsed;
63
+ if (typeof candidate.orderValue !== "string" || typeof candidate.id !== "string") throw new InvalidCursorError(cursor);
64
+ return {
65
+ orderValue: candidate.orderValue,
66
+ id: candidate.id
67
+ };
68
+ }
69
+ var EmDashValidationError = class extends Error {
70
+ constructor(message, details) {
71
+ super(message);
72
+ this.details = details;
73
+ this.name = "EmDashValidationError";
74
+ }
75
+ };
76
+ var ContentCollectionNotFoundError = class extends Error {
77
+ constructor(collection) {
78
+ super(`Collection '${collection}' not found`);
79
+ this.name = "ContentCollectionNotFoundError";
80
+ }
81
+ };
82
+ /**
83
+ * Thrown by `publish()` when called with `requireDue` for a row that is no
84
+ * longer due (its `scheduled_at` was cleared or pushed into the future between
85
+ * selection and publish — e.g. an editor unscheduled it). Lets the scheduled
86
+ * sweep skip the row silently rather than treating it as a publish failure.
87
+ */
88
+ var ScheduledNotDueError = class extends Error {
89
+ constructor(message = "Content is no longer scheduled to publish") {
90
+ super(message);
91
+ this.name = "ScheduledNotDueError";
92
+ }
93
+ };
94
+ var ContentMutationConflictError = class extends Error {
95
+ constructor(message = "Content changed while the operation was in progress") {
96
+ super(message);
97
+ this.name = "ContentMutationConflictError";
98
+ }
99
+ };
100
+
101
+ //#endregion
102
+ export { STAGED_CURSOR_MARKER as a, encodeCursor as c, InvalidCursorError as i, ContentMutationConflictError as n, ScheduledNotDueError as o, EmDashValidationError as r, decodeCursor as s, ContentCollectionNotFoundError as t };
103
+ //# sourceMappingURL=types-aOOxRSx6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-aOOxRSx6.mjs","names":[],"sources":["../src/database/repositories/types.ts"],"sourcesContent":["import type { ContentFieldFilters } from \"../../content-list-query.js\";\nimport type { CustomFieldValue } from \"../../schema/types.js\";\nimport { encodeBase64, decodeBase64 } from \"../../utils/base64.js\";\n\n/**\n * Hard cap on cursor length. Cursors we issue are short JSON-in-base64\n * blobs; a real cursor is well under 200 chars. This guards against\n * malicious callers passing megabyte-sized strings to force the base64\n * decoder to allocate (decodeBase64 is O(N) in input size). The MCP and\n * REST schemas also clamp at 2048 — this 4096 cap is a defense-in-depth\n * floor inside the repository helpers.\n */\nconst MAX_CURSOR_LENGTH = 4096;\n\nexport interface CreateContentInput {\n\t/** Explicit content ID for stable seed imports. Omit to generate a ULID. */\n\tid?: string;\n\ttype: string;\n\tslug?: string | null;\n\tdata: Record<string, unknown>;\n\tstatus?: string;\n\tauthorId?: string;\n\tprimaryBylineId?: string | null;\n\tlocale?: string;\n\ttranslationOf?: string;\n\t/** Field columns selected atomically from `translationOf` during the insert. */\n\tinheritFields?: string[];\n\tpublishedAt?: string | null;\n\t/** Override created_at (ISO 8601). Used by importers to preserve original dates. */\n\tcreatedAt?: string | null;\n}\n\nexport interface UpdateContentInput {\n\tdata?: Record<string, unknown>;\n\tstatus?: string;\n\tslug?: string | null;\n\tpublishedAt?: string | null;\n\tscheduledAt?: string | null;\n\t/** Entry owner (`ec_{collection}.author_id`). */\n\tauthorId?: string | null;\n\t/** Revision author, separate from entry ownership. */\n\trevisionAuthorId?: string | null;\n\tprimaryBylineId?: string | null;\n}\n\n/** SEO fields for content items */\nexport interface ContentSeo {\n\ttitle: string | null;\n\tdescription: string | null;\n\timage: string | null;\n\tcanonical: string | null;\n\tnoIndex: boolean;\n}\n\n/** Input for updating SEO fields on content */\nexport interface ContentSeoInput {\n\ttitle?: string | null;\n\tdescription?: string | null;\n\timage?: string | null;\n\tcanonical?: string | null;\n\tnoIndex?: boolean;\n}\n\nexport interface BylineSummary {\n\tid: string;\n\tslug: string;\n\tdisplayName: string;\n\tbio: string | null;\n\tavatarMediaId: string | null;\n\t/**\n\t * The avatar media's storage key, folded in by a LEFT JOIN on the\n\t * `media` table. Populated by the content-credit hydration path\n\t * (`getContentBylines` / `getContentBylinesMany`, i.e. the\n\t * `entry.data.bylines` populated by `getEmDashCollection` /\n\t * `getEmDashEntry`) and by the single-row finders (`findById`,\n\t * `findBySlug`, `findByUserId`, `findByUserIds`). `findMany` doesn't\n\t * join media, so it leaves this null.\n\t *\n\t * Lets a page build a direct storage URL for an author avatar without a\n\t * per-byline `MediaRepository.findById`, avoiding an N+1 when many distinct\n\t * authors appear on one page.\n\t *\n\t * Optional so adding it is a non-breaking change for existing code that\n\t * constructs a `BylineSummary` literal; the repositories always populate it\n\t * (to `null` when there's no avatar or no media join).\n\t */\n\tavatarStorageKey?: string | null;\n\t/** Avatar media alt text, from the same media join. Null when not joined. */\n\tavatarAlt?: string | null;\n\t/**\n\t * Avatar media blurhash (LQIP placeholder, migration 024), folded in by the\n\t * same media join as `avatarStorageKey`. Lets a renderer paint a blurred\n\t * placeholder while the full avatar loads, with no extra media lookup.\n\t * Null when the byline has no avatar, the media row has no blurhash, or the\n\t * byline came from `findMany`, which doesn't join media.\n\t */\n\tavatarBlurhash?: string | null;\n\t/**\n\t * Avatar media dominant colour (LQIP placeholder, migration 024), from the\n\t * same media join. Null under the same conditions as `avatarBlurhash`.\n\t */\n\tavatarDominantColor?: string | null;\n\twebsiteUrl: string | null;\n\tuserId: string | null;\n\tisGuest: boolean;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/**\n\t * Locale this byline row is presented in. Added by migration 040.\n\t * `(slug, locale)` is unique; a single slug can repeat across locales.\n\t */\n\tlocale: string;\n\t/**\n\t * Shared across translations of the same byline. Added by migration 040.\n\t * `_emdash_content_bylines.byline_id` and `ec_*.primary_byline_id` store\n\t * this value, so a credit spans every locale variant of a byline.\n\t * Nullable in storage for backwards compatibility; new rows always\n\t * populate it.\n\t */\n\ttranslationGroup: string | null;\n\t/**\n\t * Custom field values registered via the byline-fields schema (migration\n\t * 041, Discussion #1174). Optional in the TypeScript shape so existing\n\t * object-literal consumers (test fixtures, plugin renderers) stay\n\t * source-compatible; the runtime always returns `{}` when no fields are\n\t * registered. Translatable values reflect this row's locale; non-\n\t * translatable values are shared across every locale variant of the\n\t * byline's `translation_group`.\n\t */\n\tcustomFields?: Record<string, CustomFieldValue>;\n}\n\nexport interface ContentBylineCredit {\n\tbyline: BylineSummary;\n\tsortOrder: number;\n\troleLabel: string | null;\n\t/** Whether this credit was explicitly assigned or inferred from authorId */\n\tsource?: \"explicit\" | \"inferred\";\n}\n\n/** A whitelisted timestamp column a content-list date range can filter on. */\nexport type ContentDateField = \"createdAt\" | \"updatedAt\" | \"publishedAt\";\n\n/**\n * Inclusive date-range filter for a single whitelisted timestamp column.\n * Bounds are compared lexicographically against the stored ISO 8601 strings,\n * which is correct because every timestamp is written via `toISOString()`.\n * Callers wanting an inclusive upper bound should pass an end-of-day value\n * (e.g. `2024-12-31T23:59:59.999Z`); the repository does not widen `to`.\n */\nexport interface ContentDateFilter {\n\tfield: ContentDateField;\n\tfrom?: string;\n\tto?: string;\n}\n\n/**\n * Byline filter for a content list.\n *\n * `mode: \"any\"` matches entries credited to at least one of `bylineIds`;\n * `mode: \"none\"` matches entries with no credit at all.\n *\n * `bylineIds` are `translation_group` values — what\n * `_emdash_content_bylines.byline_id` stores since migration 040 — so a filter\n * matches a byline across every locale variant.\n *\n * By default only explicit credits count. `includeInferred` widens the filter\n * to the byline the list actually renders, which for an entry with no credits\n * is the one linked to its `author_id` (see `hydrateBylinesMany`).\n */\nexport interface ContentBylineFilter {\n\tmode: \"any\" | \"none\";\n\t/** Ignored when `mode` is `\"none\"`. An empty list matches nothing. */\n\tbylineIds?: string[];\n\tincludeInferred?: boolean;\n\t/**\n\t * Locale a credit has to resolve at — the locale the list is scoped to.\n\t * Applies to explicit credits as well as inferred ones, since a byline\n\t * group credited to an entry renders only where it has a row at that\n\t * locale. Defaults to each entry's own locale when the list spans locales.\n\t */\n\tlocale?: string;\n}\n\nexport interface FindManyOptions {\n\twhere?: {\n\t\tstatus?: string;\n\t\tauthorId?: string;\n\t\tlocale?: string;\n\t\t/** Case-insensitive substring to match against `searchColumns`. */\n\t\tq?: string;\n\t\t/**\n\t\t * Columns the `q` substring filter is applied to (OR'd together).\n\t\t * Resolved by the handler from the collection's display fields, slug,\n\t\t * and any field marked searchable. Each name is validated as a SQL\n\t\t * identifier.\n\t\t */\n\t\tsearchColumns?: string[];\n\t\t/**\n\t\t * Serve `q` from the collection's FTS5 index (`_emdash_fts_<slug>`)\n\t\t * instead of an unindexable substring LIKE. Set by the handler only\n\t\t * when the collection has search enabled and the index exists\n\t\t * (SQLite only). The repository combines a token-prefix MATCH with\n\t\t * an index-served slug prefix so slug lookups keep working.\n\t\t */\n\t\tuseFts?: boolean;\n\t\t/** Inclusive date range over a whitelisted timestamp column. */\n\t\tdateFilter?: ContentDateFilter;\n\t\t/** Restrict to entries by their byline credits. */\n\t\tbylineFilter?: ContentBylineFilter;\n\t\t/** AND-combined filters over custom fields explicitly marked as indexed. */\n\t\tfieldFilters?: ContentFieldFilters;\n\t};\n\torderBy?: {\n\t\tfield: string;\n\t\tdirection: \"asc\" | \"desc\";\n\t};\n\t/**\n\t * Extra field slugs allowed as `orderBy` beyond the system columns — the\n\t * collection's configured titleField/dateField. Resolved by the\n\t * handler server-side so `orderBy` stays a closed set per request.\n\t */\n\tsortableExtras?: string[];\n\tlimit?: number;\n\tcursor?: string; // Base64-encoded JSON: {orderValue: string, id: string}\n}\n\nexport interface FindManyResult<T> {\n\titems: T[];\n\tnextCursor?: string; // Base64-encoded JSON: {orderValue: string, id: string}\n\t/**\n\t * Total number of rows matching the where clause (ignoring pagination).\n\t * Optional because not every caller needs it; repositories that compute\n\t * it should set it so the UI can render a stable pagination denominator.\n\t */\n\ttotal?: number;\n}\n\n/**\n * Order value stamped into a cursor over a *staged* reference selection, whose\n * anchor is a translation group rather than a row in the link table.\n *\n * A preview and a public render page the same field from different places, so a\n * cursor can cross that boundary in either direction — the draft publishes, or\n * the preview session ends, mid-pagination. Both sides recognise this marker so\n * they can tell a foreign cursor from a malformed one and restart the field's\n * page rather than failing or silently emptying it.\n */\nexport const STAGED_CURSOR_MARKER = \"staged\";\n\n/** Encode a cursor from order value + id */\nexport function encodeCursor(orderValue: string, id: string): string {\n\treturn encodeBase64(JSON.stringify({ orderValue, id }));\n}\n\n/**\n * Thrown when a pagination cursor cannot be decoded.\n *\n * Repository callers should let this propagate; handler catch blocks\n * map it to a structured `INVALID_CURSOR` error so client pagination\n * bugs surface immediately rather than silently re-fetching the first\n * page.\n */\nexport class InvalidCursorError extends Error {\n\tconstructor(cursor: string) {\n\t\tconst display = cursor.length > 50 ? `${cursor.slice(0, 47)}...` : cursor;\n\t\tsuper(`Invalid pagination cursor: ${display}`);\n\t\tthis.name = \"InvalidCursorError\";\n\t}\n}\n\n/**\n * Decode a cursor to order value + id.\n *\n * Throws `InvalidCursorError` if the cursor is empty, not valid base64,\n * not valid JSON, or doesn't contain string `orderValue` and `id` fields.\n */\nexport function decodeCursor(cursor: string): { orderValue: string; id: string } {\n\tif (!cursor) throw new InvalidCursorError(cursor);\n\tif (cursor.length > MAX_CURSOR_LENGTH) throw new InvalidCursorError(cursor);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(decodeBase64(cursor));\n\t} catch {\n\t\tthrow new InvalidCursorError(cursor);\n\t}\n\tif (parsed === null || typeof parsed !== \"object\") {\n\t\tthrow new InvalidCursorError(cursor);\n\t}\n\tconst candidate = parsed as { orderValue?: unknown; id?: unknown };\n\tif (typeof candidate.orderValue !== \"string\" || typeof candidate.id !== \"string\") {\n\t\tthrow new InvalidCursorError(cursor);\n\t}\n\treturn { orderValue: candidate.orderValue, id: candidate.id };\n}\n\nexport interface ContentItem {\n\tid: string;\n\ttype: string;\n\tslug: string | null;\n\tstatus: string;\n\tdata: Record<string, unknown>;\n\tauthorId: string | null;\n\tprimaryBylineId: string | null;\n\tbyline?: BylineSummary | null;\n\tbylines?: ContentBylineCredit[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tpublishedAt: string | null;\n\tscheduledAt: string | null;\n\tliveRevisionId: string | null;\n\tdraftRevisionId: string | null;\n\tversion: number;\n\tlocale: string | null;\n\ttranslationGroup: string | null;\n\t/** SEO metadata — only populated for collections with `has_seo` enabled */\n\tseo?: ContentSeo;\n\t/**\n\t * For collections that support `revisions`: when a draft revision exists,\n\t * `data` reflects the unsaved draft and `liveData` carries the currently-\n\t * published values. When no draft exists, `liveData` is undefined.\n\t *\n\t * Hydrated by `EmDashRuntime.hydrateDraftData()` — repositories themselves\n\t * never set this field; it's purely a runtime-overlay concept that gives\n\t * agents a clear picture of \"draft vs. live\" without re-fetching the\n\t * revision history.\n\t */\n\tliveData?: Record<string, unknown>;\n\t/**\n\t * First page of each reference field's resolved selection, keyed by field\n\t * slug. Only populated when the caller opts in via `handleContentGet`'s\n\t * `referenceOptions` param (see content.ts) — hydration is never\n\t * unconditional because it can leak draft ids/slugs to callers without\n\t * `content:read_drafts`.\n\t *\n\t * Shape mirrors `EntryRef` from `api/handlers/relations.ts`, duplicated\n\t * here (rather than imported) so the database layer doesn't depend on\n\t * the api/handlers layer.\n\t */\n\treferences?: Record<\n\t\tstring,\n\t\t{\n\t\t\tchildren: Array<{\n\t\t\t\tid: string;\n\t\t\t\tslug: string | null;\n\t\t\t\tcollection: string;\n\t\t\t\ttitle: string | null;\n\t\t\t\tlocale: string | null;\n\t\t\t\ttranslationGroup: string | null;\n\t\t\t\tsortOrder?: number;\n\t\t\t}>;\n\t\t\tnextCursor?: string;\n\t\t}\n\t>;\n}\n\nexport class EmDashValidationError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic details?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"EmDashValidationError\";\n\t}\n}\n\nexport class ContentCollectionNotFoundError extends Error {\n\tconstructor(collection: string) {\n\t\tsuper(`Collection '${collection}' not found`);\n\t\tthis.name = \"ContentCollectionNotFoundError\";\n\t}\n}\n\n/**\n * Thrown by `publish()` when called with `requireDue` for a row that is no\n * longer due (its `scheduled_at` was cleared or pushed into the future between\n * selection and publish — e.g. an editor unscheduled it). Lets the scheduled\n * sweep skip the row silently rather than treating it as a publish failure.\n */\nexport class ScheduledNotDueError extends Error {\n\tconstructor(message = \"Content is no longer scheduled to publish\") {\n\t\tsuper(message);\n\t\tthis.name = \"ScheduledNotDueError\";\n\t}\n}\n\nexport class ContentMutationConflictError extends Error {\n\tconstructor(message = \"Content changed while the operation was in progress\") {\n\t\tsuper(message);\n\t\tthis.name = \"ContentMutationConflictError\";\n\t}\n}\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,oBAAoB;;;;;;;;;;;AA4O1B,MAAa,uBAAuB;;AAGpC,SAAgB,aAAa,YAAoB,IAAoB;AACpE,QAAO,aAAa,KAAK,UAAU;EAAE;EAAY;EAAI,CAAC,CAAC;;;;;;;;;;AAWxD,IAAa,qBAAb,cAAwC,MAAM;CAC7C,YAAY,QAAgB;EAC3B,MAAM,UAAU,OAAO,SAAS,KAAK,GAAG,OAAO,MAAM,GAAG,GAAG,CAAC,OAAO;AACnE,QAAM,8BAA8B,UAAU;AAC9C,OAAK,OAAO;;;;;;;;;AAUd,SAAgB,aAAa,QAAoD;AAChF,KAAI,CAAC,OAAQ,OAAM,IAAI,mBAAmB,OAAO;AACjD,KAAI,OAAO,SAAS,kBAAmB,OAAM,IAAI,mBAAmB,OAAO;CAC3E,IAAI;AACJ,KAAI;AACH,WAAS,KAAK,MAAM,aAAa,OAAO,CAAC;SAClC;AACP,QAAM,IAAI,mBAAmB,OAAO;;AAErC,KAAI,WAAW,QAAQ,OAAO,WAAW,SACxC,OAAM,IAAI,mBAAmB,OAAO;CAErC,MAAM,YAAY;AAClB,KAAI,OAAO,UAAU,eAAe,YAAY,OAAO,UAAU,OAAO,SACvE,OAAM,IAAI,mBAAmB,OAAO;AAErC,QAAO;EAAE,YAAY,UAAU;EAAY,IAAI,UAAU;EAAI;;AA+D9D,IAAa,wBAAb,cAA2C,MAAM;CAChD,YACC,SACA,AAAO,SACN;AACD,QAAM,QAAQ;EAFP;AAGP,OAAK,OAAO;;;AAId,IAAa,iCAAb,cAAoD,MAAM;CACzD,YAAY,YAAoB;AAC/B,QAAM,eAAe,WAAW,aAAa;AAC7C,OAAK,OAAO;;;;;;;;;AAUd,IAAa,uBAAb,cAA0C,MAAM;CAC/C,YAAY,UAAU,6CAA6C;AAClE,QAAM,QAAQ;AACd,OAAK,OAAO;;;AAId,IAAa,+BAAb,cAAkD,MAAM;CACvD,YAAY,UAAU,uDAAuD;AAC5E,QAAM,QAAQ;AACd,OAAK,OAAO"}
@@ -0,0 +1,198 @@
1
+ import * as react from "react";
2
+
3
+ //#region src/auth/types.d.ts
4
+ /**
5
+ * Auth Provider Types
6
+ *
7
+ * Defines the interfaces for pluggable authentication providers.
8
+ *
9
+ * Two systems coexist:
10
+ * - `AuthDescriptor` — transparent auth (Cloudflare Access) that authenticates
11
+ * every request via headers/cookies. No login UI needed.
12
+ * - `AuthProviderDescriptor` — pluggable login methods (GitHub, Google,
13
+ * AT Protocol, etc.) that appear as options on the login page and setup
14
+ * wizard. Passkey is built-in; providers are additive.
15
+ */
16
+ /**
17
+ * Result of authenticating a request via an external auth provider
18
+ */
19
+ interface AuthResult {
20
+ /** User's email address */
21
+ email: string;
22
+ /** User's display name */
23
+ name: string;
24
+ /** Resolved role level (e.g., 50 for Admin, 30 for Editor) */
25
+ role: number;
26
+ /** Provider-specific subject ID */
27
+ subject?: string;
28
+ /** Additional provider-specific data */
29
+ metadata?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Auth descriptor — transparent auth providers (e.g., Cloudflare Access).
33
+ *
34
+ * These authenticate every request via headers/cookies. No login UI needed.
35
+ * The module's `authenticate()` function is called by middleware on each request.
36
+ */
37
+ interface AuthDescriptor {
38
+ /**
39
+ * Auth provider type identifier
40
+ * @example "cloudflare-access", "okta", "auth0"
41
+ */
42
+ type: string;
43
+ /**
44
+ * Module specifier to import at runtime
45
+ * The module must export an `authenticate` function.
46
+ * @example "@emdash-cms/cloudflare/auth"
47
+ */
48
+ entrypoint: string;
49
+ /**
50
+ * Provider-specific configuration (JSON-serializable)
51
+ */
52
+ config: unknown;
53
+ }
54
+ /**
55
+ * Auth provider module interface
56
+ *
57
+ * Modules specified by AuthDescriptor.entrypoint must export
58
+ * an `authenticate` function matching this signature.
59
+ */
60
+ interface AuthProviderModule {
61
+ /**
62
+ * Authenticate a request using the provider
63
+ *
64
+ * @param request - The incoming HTTP request
65
+ * @param config - Provider-specific configuration from AuthDescriptor
66
+ * @returns Authentication result if valid, throws if invalid
67
+ */
68
+ authenticate(request: Request, config: unknown): Promise<AuthResult>;
69
+ }
70
+ /**
71
+ * Descriptor for a pluggable auth provider.
72
+ *
73
+ * Auth providers appear as login options on the login page and setup wizard.
74
+ * They coexist with passkey (which is built-in) and with each other.
75
+ * Any provider can be used to create the initial admin account.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // astro.config.ts
80
+ * import { atproto } from "@emdash-cms/auth-atproto";
81
+ *
82
+ * emdash({
83
+ * authProviders: [atproto(), github(), google()],
84
+ * })
85
+ * ```
86
+ */
87
+ interface AuthProviderDescriptor {
88
+ /** Unique provider ID (e.g., "github", "atproto") */
89
+ id: string;
90
+ /** Human-readable label for UI (e.g., "GitHub", "AT Protocol") */
91
+ label: string;
92
+ /** Provider-specific config (JSON-serializable) */
93
+ config?: unknown;
94
+ /**
95
+ * Module exporting React components for the admin UI.
96
+ * Statically imported at build time via virtual module.
97
+ *
98
+ * The module should export components matching `AuthProviderAdminExports`.
99
+ */
100
+ adminEntry?: string;
101
+ /**
102
+ * Astro route handlers this provider needs injected at build time.
103
+ * Used for login initiation, OAuth callbacks, well-known endpoints, etc.
104
+ */
105
+ routes?: AuthRouteDescriptor[];
106
+ /**
107
+ * URL prefixes/paths that should bypass auth middleware.
108
+ * Added to the public routes set so login/callback endpoints work
109
+ * for unauthenticated users.
110
+ */
111
+ publicRoutes?: string[];
112
+ /**
113
+ * Storage collections for persistent auth state (e.g., OAuth sessions).
114
+ * Same format as plugin storage — collections are stored in the shared
115
+ * `_plugin_storage` table namespaced under `auth:<providerId>`.
116
+ *
117
+ * Access via `getAuthProviderStorage()` from `emdash/api/route-utils`.
118
+ */
119
+ storage?: Record<string, {
120
+ indexes?: Array<string | string[]>;
121
+ uniqueIndexes?: Array<string | string[]>;
122
+ }>;
123
+ }
124
+ /**
125
+ * A route that an auth provider needs injected into the Astro app.
126
+ */
127
+ interface AuthRouteDescriptor {
128
+ /** URL pattern (e.g., "/_emdash/api/auth/atproto/login") */
129
+ pattern: string;
130
+ /** Module specifier for the Astro route handler */
131
+ entrypoint: string;
132
+ }
133
+ /**
134
+ * Expected exports from an auth provider's `adminEntry` module.
135
+ *
136
+ * All exports are optional. Providers export whichever components
137
+ * make sense for their auth flow.
138
+ */
139
+ interface AuthProviderAdminExports {
140
+ /**
141
+ * Compact button for the login page (icon + label).
142
+ * Used for providers with a simple redirect flow (GitHub, Google).
143
+ * Rendered in the "Or continue with" section.
144
+ */
145
+ LoginButton?: react.ComponentType;
146
+ /**
147
+ * Full login form for providers that need custom input.
148
+ * Used for providers like AT Protocol that need a handle field.
149
+ * Rendered as an expandable section on the login page.
150
+ */
151
+ LoginForm?: react.ComponentType;
152
+ /**
153
+ * Setup wizard step for creating the admin account via this provider.
154
+ * When present, this provider appears as an option in the setup wizard's
155
+ * "Create admin account" step.
156
+ */
157
+ SetupStep?: react.ComponentType<{
158
+ onComplete: () => void;
159
+ }>;
160
+ }
161
+ /**
162
+ * Configuration options common to external auth providers
163
+ */
164
+ interface ExternalAuthConfig {
165
+ /**
166
+ * Automatically create EmDash users on first login
167
+ * @default true
168
+ */
169
+ autoProvision?: boolean;
170
+ /**
171
+ * Role level for users not matching any group in roleMapping
172
+ * @default 30 (Editor)
173
+ */
174
+ defaultRole?: number;
175
+ /**
176
+ * Update user's role on each login based on current IdP groups
177
+ * When false, role is only set on first provisioning
178
+ * @default false
179
+ */
180
+ syncRoles?: boolean;
181
+ /**
182
+ * Map IdP group names to EmDash role levels
183
+ * First match wins if user is in multiple groups
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * roleMapping: {
188
+ * "Admins": 50, // Admin
189
+ * "Developers": 40, // Developer
190
+ * "Content Team": 30, // Editor
191
+ * }
192
+ * ```
193
+ */
194
+ roleMapping?: Record<string, number>;
195
+ }
196
+ //#endregion
197
+ export { AuthResult as a, AuthProviderModule as i, AuthProviderAdminExports as n, AuthRouteDescriptor as o, AuthProviderDescriptor as r, ExternalAuthConfig as s, AuthDescriptor as t };
198
+ //# sourceMappingURL=types-m1WbUffD.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-m1WbUffD.d.mts","names":[],"sources":["../src/auth/types.ts"],"mappings":";;;;;;AAgBA;;;;;;;;;;;;UAAiB,UAAA;EAmBc;EAjB9B,KAAA;EAiB8B;EAf9B,IAAA;EA2BA;EAzBA,IAAA;EA8BM;EA5BN,OAAA;EAqCgB;EAnChB,QAAA,GAAW,MAAA;AAAA;;;;;;;UASK,cAAA;EAkCH;;;;EA7Bb,IAAA;EA6BmE;AAwBpE;;;;EA9CC,UAAA;EAsFuD;;;EAjFvD,MAAA;AAAA;;;;;;;UASgB,kBAAA;EAsEN;;;;;;;EA9DV,YAAA,CAAa,OAAA,EAAS,OAAA,EAAS,MAAA,YAAkB,OAAA,CAAQ,UAAA;AAAA;;;;AAoF1D;;;;;;;;;;;;;;UA5DiB,sBAAA;EAgFsC;EA9EtD,EAAA;EAoFgB;EAjFhB,KAAA;;EAGA,MAAA;EAmFA;;;;;;EA3EA,UAAA;;;;;EAMA,MAAA,GAAS,mBAAA;;;;;;EAOT,YAAA;;;;;;;;EASA,OAAA,GAAU,MAAA;IAEP,OAAA,GAAU,KAAA;IAA0B,aAAA,GAAgB,KAAA;EAAA;AAAA;;;;UAOvC,mBAAA;;EAEhB,OAAA;;EAEA,UAAA;AAAA;;;;;;;UASgB,wBAAA;;;;;;EAMhB,WAAA,GANwC,KAAA,CAMV,aAAA;;;;;;EAO9B,SAAA,GAP2C,KAAA,CAOf,aAAA;;;;;;EAO5B,SAAA,GAPyC,KAAA,CAOb,aAAA;IAAgB,UAAA;EAAA;AAAA;;;;UAM5B,kBAAA;;;;;EAKhB,aAAA;;;;;EAMA,WAAA;;;;;;EAOA,SAAA;;;;;;;;;;;;;;EAeA,WAAA,GAAc,MAAA;AAAA"}
@@ -0,0 +1,124 @@
1
+ //#region src/object-cache/types.d.ts
2
+ /**
3
+ * Object cache types
4
+ *
5
+ * The object cache is an optional, distributed read-through cache that sits
6
+ * *beneath* the per-request cache (`requestCached`) and *above* the database.
7
+ * Query results (content entries, settings, menus, taxonomies) are stored in a
8
+ * fast key/value store (Cloudflare KV, or an in-isolate memory store for Node)
9
+ * so repeat reads across requests and isolates skip the database entirely.
10
+ *
11
+ * Backends only ever deal in strings — serialization (including `Date`
12
+ * preservation) is handled by the core read-through layer in `./codec.ts`, so
13
+ * every backend behaves identically.
14
+ */
15
+ /**
16
+ * A pluggable object-cache backend.
17
+ *
18
+ * Implementations must be safe to call concurrently and should never throw on
19
+ * cache misses — `get` returns `null` for a miss. A backend that throws (e.g.
20
+ * a transient KV error) degrades gracefully: the read-through layer treats a
21
+ * thrown `get` as a miss and a thrown `set` as a no-op, so the database
22
+ * remains the source of truth.
23
+ */
24
+ interface ObjectCacheBackend {
25
+ /** Return the stored string for `key`, or `null` on a miss. */
26
+ get(key: string): Promise<string | null>;
27
+ /**
28
+ * Store `value` under `key`.
29
+ *
30
+ * @param ttlSeconds Optional time-to-live in seconds. Backends that don't
31
+ * support TTLs may ignore it, but distributed backends (KV) should honor
32
+ * it so orphaned, epoch-busted keys are eventually reclaimed.
33
+ */
34
+ set(key: string, value: string, ttlSeconds?: number): Promise<void>;
35
+ /** Remove `key`. Idempotent — deleting a missing key is not an error. */
36
+ delete(key: string): Promise<void>;
37
+ }
38
+ /**
39
+ * Serializable descriptor for an object-cache backend.
40
+ *
41
+ * Mirrors {@link import("../storage/types.js").StorageDescriptor}: `entrypoint`
42
+ * is a module specifier resolved at build time that exports a
43
+ * {@link CreateObjectCacheBackendFn} named `createObjectCache`; `config` is the
44
+ * plain, serializable runtime config passed to it.
45
+ */
46
+ interface ObjectCacheDescriptor {
47
+ /** Module path exporting a `createObjectCache` function. */
48
+ entrypoint: string;
49
+ /** Serializable config passed to `createObjectCache` at runtime. */
50
+ config: ObjectCacheRuntimeConfig;
51
+ }
52
+ /**
53
+ * Runtime config shared by every backend, plus backend-specific keys.
54
+ *
55
+ * The read-through layer reads `defaultTtl`, `revalidate`, and `keyPrefix`;
56
+ * individual backends read their own keys (e.g. the KV backend reads
57
+ * `binding`).
58
+ */
59
+ interface ObjectCacheRuntimeConfig {
60
+ /**
61
+ * Default time-to-live for cached entries, in seconds.
62
+ *
63
+ * Invalidation works by epoch comparison, not key deletion: a stale value
64
+ * is detected on read (its stored epoch no longer matches) and overwritten
65
+ * in place under the same key. The TTL is just a backstop that reclaims
66
+ * keys that are never read again.
67
+ *
68
+ * @default 3600 (1 hour)
69
+ */
70
+ defaultTtl?: number;
71
+ /**
72
+ * How long (milliseconds) an isolate may reuse a cached namespace epoch
73
+ * before re-reading it from the backend.
74
+ *
75
+ * After a write bumps a namespace's epoch, an isolate keeps serving the
76
+ * previous epoch's keys until its cached epoch expires after this window. It
77
+ * is only part of the cross-isolate staleness: a distributed backend adds its
78
+ * own propagation delay (KV's edge cache is eventually consistent, up to
79
+ * ~60s), so on KV the effective window is that propagation plus this value.
80
+ * Only anonymous visitors are affected — preview and edit requests bypass the
81
+ * cache.
82
+ *
83
+ * Set to `0` to re-read the epoch on every query (strongest freshness, more
84
+ * backend reads).
85
+ *
86
+ * @default 1000
87
+ */
88
+ revalidate?: number;
89
+ /**
90
+ * Prefix applied to every cache key. Lets multiple EmDash sites share one
91
+ * KV namespace without colliding.
92
+ *
93
+ * @default "em"
94
+ */
95
+ keyPrefix?: string;
96
+ /**
97
+ * Maximum time (milliseconds) to wait for a single backend read before
98
+ * treating it as a cache miss and falling back to the database.
99
+ *
100
+ * Guards against a backend operation that stalls without resolving or
101
+ * rejecting (e.g. a cold cross-region KV read, or one queued behind the
102
+ * Workers simultaneous-connection limit), which would otherwise hang the
103
+ * request. A timed-out read degrades to a miss; the database remains the
104
+ * source of truth.
105
+ *
106
+ * Set to `0` to disable the timeout (not recommended on Cloudflare).
107
+ *
108
+ * @default 2000
109
+ */
110
+ timeout?: number;
111
+ /** Backend-specific keys (e.g. the KV binding name). */
112
+ [key: string]: unknown;
113
+ }
114
+ /**
115
+ * Factory signature exported as `createObjectCache` from a backend entrypoint.
116
+ *
117
+ * Each backend accesses its own resources directly: the KV backend imports
118
+ * bindings from `cloudflare:workers`; the memory backend uses an in-isolate
119
+ * map.
120
+ */
121
+ type CreateObjectCacheBackendFn = (config: ObjectCacheRuntimeConfig) => ObjectCacheBackend;
122
+ //#endregion
123
+ export { ObjectCacheRuntimeConfig as i, ObjectCacheBackend as n, ObjectCacheDescriptor as r, CreateObjectCacheBackendFn as t };
124
+ //# sourceMappingURL=types-uxLoPBio.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-uxLoPBio.d.mts","names":[],"sources":["../src/object-cache/types.ts"],"mappings":";;AAuBA;;;;;;;;;;;;;;;;;;;;;UAAiB,kBAAA;EAuBqB;EArBrC,GAAA,CAAI,GAAA,WAAc,OAAA;EAyBc;;;;;;AAUjC;EA3BC,GAAA,CAAI,GAAA,UAAa,KAAA,UAAe,UAAA,YAAsB,OAAA;;EAEtD,MAAA,CAAO,GAAA,WAAc,OAAA;AAAA;;;;;;;AAwFtB;;UA7EiB,qBAAA;EA6EgF;EA3EhG,UAAA;EA2EyC;EAzEzC,MAAA,EAAQ,wBAAA;AAAA;;;;;;;;UAUQ,wBAAA;;;;;;;;;;;EAWhB,UAAA;;;;;;;;;;;;;;;;;;EAkBA,UAAA;;;;;;;EAOA,SAAA;;;;;;;;;;;;;;;EAeA,OAAA;;GAEC,GAAA;AAAA;;;;;;;;KAUU,0BAAA,IAA8B,MAAA,EAAQ,wBAAA,KAA6B,kBAAA"}