emdash 0.14.0 → 0.16.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 (650) hide show
  1. package/dist/{adapters-9DybjTO6.d.mts → adapters-C4yd_UJR.d.mts} +1 -1
  2. package/dist/{adapters-9DybjTO6.d.mts.map → adapters-C4yd_UJR.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-CDdG-4Gd.mjs → allowed-origins-D0fFk9a6.mjs} +2 -2
  4. package/dist/{allowed-origins-CDdG-4Gd.mjs.map → allowed-origins-D0fFk9a6.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +15 -15
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +3 -3
  9. package/dist/{api-BMLZuwM4.mjs → api-BNKqxyFX.mjs} +560 -56
  10. package/dist/api-BNKqxyFX.mjs.map +1 -0
  11. package/dist/{api-tokens-eYymBhIT.mjs → api-tokens-ucpcNXDt.mjs} +2 -2
  12. package/dist/{api-tokens-eYymBhIT.mjs.map → api-tokens-ucpcNXDt.mjs.map} +1 -1
  13. package/dist/{apply-v4DBgjPw.mjs → apply-BOPaD-s9.mjs} +17 -17
  14. package/dist/{apply-v4DBgjPw.mjs.map → apply-BOPaD-s9.mjs.map} +1 -1
  15. package/dist/astro/index.d.mts +10 -10
  16. package/dist/astro/index.d.mts.map +1 -1
  17. package/dist/astro/index.mjs +53 -5
  18. package/dist/astro/index.mjs.map +1 -1
  19. package/dist/astro/middleware/auth.d.mts +9 -9
  20. package/dist/astro/middleware/auth.mjs +6 -6
  21. package/dist/astro/middleware/auth.mjs.map +1 -1
  22. package/dist/astro/middleware/redirect.mjs +4 -4
  23. package/dist/astro/middleware/request-context.mjs +3 -3
  24. package/dist/astro/middleware/request-context.mjs.map +1 -1
  25. package/dist/astro/middleware/setup.mjs +1 -1
  26. package/dist/astro/middleware.d.mts.map +1 -1
  27. package/dist/astro/middleware.mjs +377 -75
  28. package/dist/astro/middleware.mjs.map +1 -1
  29. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  30. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  31. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  32. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  33. package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -1
  34. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -17
  35. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  36. package/dist/astro/routes/api/admin/bylines/_id_/translations.d.mts +9 -0
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.d.mts.map +1 -0
  38. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +70 -0
  39. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -0
  40. package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -1
  41. package/dist/astro/routes/api/admin/bylines/index.mjs +25 -16
  42. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  43. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
  44. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  45. package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
  46. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  47. package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
  48. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  49. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  50. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  51. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  52. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +33 -32
  53. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +33 -32
  55. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  56. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +32 -31
  57. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  58. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +32 -31
  59. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  60. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +34 -32
  61. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  62. package/dist/astro/routes/api/admin/plugins/index.mjs +32 -31
  63. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +32 -31
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +34 -32
  68. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +32 -31
  70. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts +8 -0
  72. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts.map +1 -0
  73. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +59 -0
  74. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -0
  75. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts +8 -0
  76. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -0
  77. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +85 -0
  78. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -0
  79. package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts +8 -0
  80. package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -0
  81. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +301 -0
  82. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -0
  83. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +51 -32
  85. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -1
  87. package/dist/astro/routes/api/admin/plugins/updates.mjs +45 -32
  88. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  89. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +32 -31
  90. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  91. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  92. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +32 -31
  93. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  95. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  96. package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
  97. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  98. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  99. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  100. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  101. package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
  102. package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
  103. package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
  104. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  105. package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
  106. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  107. package/dist/astro/routes/api/auth/me.mjs +5 -5
  108. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  109. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  110. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -1
  111. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  112. package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -1
  113. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  114. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  115. package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
  116. package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
  117. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
  118. package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
  119. package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
  120. package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
  121. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  122. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
  123. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  124. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  125. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  126. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  127. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs.map +1 -1
  128. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  129. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
  130. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
  131. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  132. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  133. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs.map +1 -1
  134. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  135. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
  136. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  137. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +10 -9
  138. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  139. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  140. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -1
  141. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  142. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  143. package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -6
  144. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  145. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  146. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  147. package/dist/astro/routes/api/dashboard.mjs +7 -7
  148. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  149. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  150. package/dist/astro/routes/api/import/probe.mjs +10 -10
  151. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  152. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  153. package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -8
  154. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  155. package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
  156. package/dist/astro/routes/api/import/wordpress/prepare.mjs +8 -8
  157. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
  158. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts +11 -1
  159. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts.map +1 -1
  160. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs +17 -1
  161. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs.map +1 -1
  162. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  163. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +9 -9
  164. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  165. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  166. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
  167. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  168. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +11 -11
  169. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  170. package/dist/astro/routes/api/manifest.mjs +4 -4
  171. package/dist/astro/routes/api/mcp.mjs +29 -29
  172. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  173. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  174. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  175. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  176. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  177. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  178. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  179. package/dist/astro/routes/api/media/upload-url.mjs +7 -7
  180. package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
  181. package/dist/astro/routes/api/media.mjs +8 -8
  182. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
  183. package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
  184. package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
  185. package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
  186. package/dist/astro/routes/api/menus/_name_.mjs +7 -7
  187. package/dist/astro/routes/api/menus/index.mjs +7 -7
  188. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  189. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  190. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  191. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  192. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  193. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  194. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  195. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  196. package/dist/astro/routes/api/openapi.json.mjs +3 -3
  197. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  198. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  199. package/dist/astro/routes/api/redirects/404s/index.mjs +8 -8
  200. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  201. package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
  202. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  203. package/dist/astro/routes/api/redirects/_id_.mjs +9 -9
  204. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  205. package/dist/astro/routes/api/redirects/index.mjs +9 -9
  206. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  207. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  208. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  209. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +32 -31
  210. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  211. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +32 -31
  212. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  213. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +32 -31
  214. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  215. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +32 -31
  216. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  217. package/dist/astro/routes/api/schema/collections/index.mjs +32 -31
  218. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  219. package/dist/astro/routes/api/schema/index.mjs +6 -6
  220. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  221. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +32 -31
  222. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  223. package/dist/astro/routes/api/schema/orphans/index.mjs +32 -31
  224. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  225. package/dist/astro/routes/api/search/enable.mjs +9 -9
  226. package/dist/astro/routes/api/search/index.mjs +8 -8
  227. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  228. package/dist/astro/routes/api/search/stats.mjs +6 -6
  229. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  230. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  231. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  232. package/dist/astro/routes/api/sections/index.mjs +8 -8
  233. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  234. package/dist/astro/routes/api/settings/email.mjs +4 -4
  235. package/dist/astro/routes/api/settings.mjs +10 -10
  236. package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
  237. package/dist/astro/routes/api/setup/admin.mjs +9 -9
  238. package/dist/astro/routes/api/setup/dev-bypass.mjs +22 -22
  239. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  240. package/dist/astro/routes/api/setup/index.mjs +22 -22
  241. package/dist/astro/routes/api/setup/status.mjs +4 -4
  242. package/dist/astro/routes/api/snapshot.mjs +6 -6
  243. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  244. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -10
  245. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  246. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -10
  247. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  248. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -10
  249. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  250. package/dist/astro/routes/api/taxonomies/index.mjs +11 -10
  251. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  252. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  253. package/dist/astro/routes/api/typegen.mjs +5 -5
  254. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  255. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  256. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  257. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  258. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
  259. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
  260. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  261. package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
  262. package/dist/astro/routes/api/widget-components.mjs +3 -3
  263. package/dist/astro/routes/robots.txt.mjs +5 -5
  264. package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
  265. package/dist/astro/routes/sitemap-_collection_.xml.mjs +58 -13
  266. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  267. package/dist/astro/routes/sitemap.xml.mjs +6 -6
  268. package/dist/astro/types.d.mts +20 -12
  269. package/dist/astro/types.d.mts.map +1 -1
  270. package/dist/auth/providers/github.d.mts +1 -1
  271. package/dist/auth/providers/google.d.mts +1 -1
  272. package/dist/{authorize-BlyCH-96.mjs → authorize-Bn4S4DUT.mjs} +2 -2
  273. package/dist/{authorize-BlyCH-96.mjs.map → authorize-Bn4S4DUT.mjs.map} +1 -1
  274. package/dist/byline-BDylH_m4.mjs +404 -0
  275. package/dist/byline-BDylH_m4.mjs.map +1 -0
  276. package/dist/{bylines-BdUP8NuI.d.mts → bylines-B2_XmnSU.d.mts} +73 -28
  277. package/dist/bylines-B2_XmnSU.d.mts.map +1 -0
  278. package/dist/bylines-B7TFEvFf.mjs +118 -0
  279. package/dist/bylines-B7TFEvFf.mjs.map +1 -0
  280. package/dist/bylines-n6nykUyI.mjs +174 -0
  281. package/dist/bylines-n6nykUyI.mjs.map +1 -0
  282. package/dist/{cache-CXCpjWiL.mjs → cache-BcI1yUjR.mjs} +2 -2
  283. package/dist/{cache-CXCpjWiL.mjs.map → cache-BcI1yUjR.mjs.map} +1 -1
  284. package/dist/{challenge-store-CJ0OOHOr.mjs → challenge-store-Dng1SxKT.mjs} +1 -1
  285. package/dist/{challenge-store-CJ0OOHOr.mjs.map → challenge-store-Dng1SxKT.mjs.map} +1 -1
  286. package/dist/{chunks-DyGtu1Bv.mjs → chunks-cYG4SnIP.mjs} +2 -2
  287. package/dist/{chunks-DyGtu1Bv.mjs.map → chunks-cYG4SnIP.mjs.map} +1 -1
  288. package/dist/cli/index.mjs +68 -30
  289. package/dist/cli/index.mjs.map +1 -1
  290. package/dist/client/cf-access.d.mts +1 -1
  291. package/dist/client/index.d.mts +1 -1
  292. package/dist/client/index.mjs +1 -1
  293. package/dist/client/index.mjs.map +1 -1
  294. package/dist/{comment-Dd9MI82-.mjs → comment-C76G-9tz.mjs} +2 -2
  295. package/dist/{comment-Dd9MI82-.mjs.map → comment-C76G-9tz.mjs.map} +1 -1
  296. package/dist/{comments-koGI0FrK.mjs → comments-CCxFFGY1.mjs} +3 -3
  297. package/dist/{comments-koGI0FrK.mjs.map → comments-CCxFFGY1.mjs.map} +1 -1
  298. package/dist/{components-mZem7pbe.mjs → components-Dx3DM0gg.mjs} +1 -1
  299. package/dist/{components-mZem7pbe.mjs.map → components-Dx3DM0gg.mjs.map} +1 -1
  300. package/dist/config-CVssduLe.mjs.map +1 -1
  301. package/dist/{content-D6YG26WG.mjs → content-8voQNTXX.mjs} +3 -3
  302. package/dist/{content-D6YG26WG.mjs.map → content-8voQNTXX.mjs.map} +1 -1
  303. package/dist/{context-qF8d3IPR.mjs → context-B7qiYrz2.mjs} +10 -10
  304. package/dist/context-B7qiYrz2.mjs.map +1 -0
  305. package/dist/{cron-H8eJ46dv.mjs → cron-Bd3b3iuj.mjs} +1 -1
  306. package/dist/{cron-H8eJ46dv.mjs.map → cron-Bd3b3iuj.mjs.map} +1 -1
  307. package/dist/{dashboard-BmWSIUwY.mjs → dashboard-BeaFSPpx.mjs} +4 -4
  308. package/dist/{dashboard-BmWSIUwY.mjs.map → dashboard-BeaFSPpx.mjs.map} +1 -1
  309. package/dist/db/index.d.mts +3 -3
  310. package/dist/db/index.mjs +1 -1
  311. package/dist/db/libsql.d.mts +1 -1
  312. package/dist/db/postgres.d.mts +1 -1
  313. package/dist/db/sqlite.d.mts +1 -1
  314. package/dist/db/sqlite.mjs +1 -1
  315. package/dist/{db-errors-CGN9kJfo.mjs → db-errors-BiYqoX-n.mjs} +14 -2
  316. package/dist/db-errors-BiYqoX-n.mjs.map +1 -0
  317. package/dist/{default-Dbs22Gg4.mjs → default-BvTAYCzx.mjs} +1 -1
  318. package/dist/{default-Dbs22Gg4.mjs.map → default-BvTAYCzx.mjs.map} +1 -1
  319. package/dist/{device-flow-BqJRxa0Q.mjs → device-flow-B9oG8PwP.mjs} +4 -4
  320. package/dist/{device-flow-BqJRxa0Q.mjs.map → device-flow-B9oG8PwP.mjs.map} +1 -1
  321. package/dist/{email-console-Dmp5Q-P2.mjs → email-console-CubRll9q.mjs} +1 -1
  322. package/dist/email-console-CubRll9q.mjs.map +1 -0
  323. package/dist/{error-tSQWIl5U.mjs → error-ChfADBuu.mjs} +19 -9
  324. package/dist/error-ChfADBuu.mjs.map +1 -0
  325. package/dist/errors-9P_FDrJ_.mjs +17 -0
  326. package/dist/errors-9P_FDrJ_.mjs.map +1 -0
  327. package/dist/{escape-B8bdIryO.mjs → escape-Cg6kMELH.mjs} +1 -1
  328. package/dist/{escape-B8bdIryO.mjs.map → escape-Cg6kMELH.mjs.map} +1 -1
  329. package/dist/{fts-manager-B633C-kQ.mjs → fts-manager-C_b-4x8u.mjs} +2 -2
  330. package/dist/{fts-manager-B633C-kQ.mjs.map → fts-manager-C_b-4x8u.mjs.map} +1 -1
  331. package/dist/{import-CNfLOgDE.mjs → import-DG80rC_I.mjs} +3 -3
  332. package/dist/{import-CNfLOgDE.mjs.map → import-DG80rC_I.mjs.map} +1 -1
  333. package/dist/{index-BV8iJ-6s.d.mts → index-BPZFAcgE.d.mts} +384 -123
  334. package/dist/index-BPZFAcgE.d.mts.map +1 -0
  335. package/dist/{index-D2gvztOP.d.mts → index-CC42STEm.d.mts} +3 -3
  336. package/dist/{index-D2gvztOP.d.mts.map → index-CC42STEm.d.mts.map} +1 -1
  337. package/dist/index.d.mts +17 -17
  338. package/dist/index.mjs +53 -52
  339. package/dist/{load-QzYRpVN3.mjs → load-CLFRjk9r.mjs} +2 -2
  340. package/dist/{load-QzYRpVN3.mjs.map → load-CLFRjk9r.mjs.map} +1 -1
  341. package/dist/{loader-Cs6-Bqe6.mjs → loader-D-vIJjfY.mjs} +86 -46
  342. package/dist/loader-D-vIJjfY.mjs.map +1 -0
  343. package/dist/{manifest-schema-HCtSh4Jq.mjs → manifest-schema-Czqf0TLu.mjs} +1 -1
  344. package/dist/{manifest-schema-HCtSh4Jq.mjs.map → manifest-schema-Czqf0TLu.mjs.map} +1 -1
  345. package/dist/media/index.d.mts +1 -1
  346. package/dist/media/local-runtime.d.mts +11 -11
  347. package/dist/media/local-runtime.mjs +4 -4
  348. package/dist/{media-Dg7he9uK.mjs → media-CKQd8AYU.mjs} +2 -2
  349. package/dist/media-CKQd8AYU.mjs.map +1 -0
  350. package/dist/{media-allowlist-B8EX01DH.mjs → media-allowlist-BNloC69x.mjs} +1 -1
  351. package/dist/{media-allowlist-B8EX01DH.mjs.map → media-allowlist-BNloC69x.mjs.map} +1 -1
  352. package/dist/{menus-X4Z-eBA1.mjs → menus-C-nWT5Tu.mjs} +42 -17
  353. package/dist/menus-C-nWT5Tu.mjs.map +1 -0
  354. package/dist/{menus-DOzIecHi.mjs → menus-arUNspyU.mjs} +2 -2
  355. package/dist/menus-arUNspyU.mjs.map +1 -0
  356. package/dist/mime-KV5TqkMN.mjs.map +1 -1
  357. package/dist/{mode-DPRPvJYm.mjs → mode-CaaiebZI.mjs} +1 -1
  358. package/dist/{mode-DPRPvJYm.mjs.map → mode-CaaiebZI.mjs.map} +1 -1
  359. package/dist/{oauth-authorization-62GmpGIH.mjs → oauth-authorization-CTMeVfvj.mjs} +4 -4
  360. package/dist/{oauth-authorization-62GmpGIH.mjs.map → oauth-authorization-CTMeVfvj.mjs.map} +1 -1
  361. package/dist/{oauth-clients-D_B0_-Bz.mjs → oauth-clients-eJCbkVSG.mjs} +1 -1
  362. package/dist/oauth-clients-eJCbkVSG.mjs.map +1 -0
  363. package/dist/{oauth-state-store-DpsZViTu.mjs → oauth-state-store-vOSdOeGe.mjs} +1 -1
  364. package/dist/{oauth-state-store-DpsZViTu.mjs.map → oauth-state-store-vOSdOeGe.mjs.map} +1 -1
  365. package/dist/{oauth-user-lookup-meyS2oB1.mjs → oauth-user-lookup-3JwsVw6N.mjs} +1 -1
  366. package/dist/{oauth-user-lookup-meyS2oB1.mjs.map → oauth-user-lookup-3JwsVw6N.mjs.map} +1 -1
  367. package/dist/options-BL4X94qY.mjs.map +1 -1
  368. package/dist/{options-Cq64Wx0O.d.mts → options-DhV-gwJb.d.mts} +4 -4
  369. package/dist/options-DhV-gwJb.d.mts.map +1 -0
  370. package/dist/page/index.d.mts +2 -2
  371. package/dist/{parse-BFTPon-J.mjs → parse-DHbXfvxO.mjs} +2 -2
  372. package/dist/{parse-BFTPon-J.mjs.map → parse-DHbXfvxO.mjs.map} +1 -1
  373. package/dist/{passkey-config-Cg86_ISa.mjs → passkey-config-BloQOT3y.mjs} +1 -1
  374. package/dist/{passkey-config-Cg86_ISa.mjs.map → passkey-config-BloQOT3y.mjs.map} +1 -1
  375. package/dist/{placeholder-D3cFCU9y.d.mts → placeholder-KCkkCtgQ.d.mts} +1 -1
  376. package/dist/{placeholder-D3cFCU9y.d.mts.map → placeholder-KCkkCtgQ.d.mts.map} +1 -1
  377. package/dist/plugin-types.d.mts +1 -1
  378. package/dist/plugin-utils.d.mts +25 -10
  379. package/dist/plugin-utils.d.mts.map +1 -1
  380. package/dist/plugin-utils.mjs +11 -10
  381. package/dist/plugin-utils.mjs.map +1 -1
  382. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  383. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  384. package/dist/plugins/adapt-sandbox-entry.mjs +26 -15
  385. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  386. package/dist/{preview-C1LOEbWZ.mjs → preview-D4z0WONU.mjs} +2 -2
  387. package/dist/{preview-C1LOEbWZ.mjs.map → preview-D4z0WONU.mjs.map} +1 -1
  388. package/dist/{public-url-CseXl9Fv.mjs → public-url-CUWWFME2.mjs} +1 -1
  389. package/dist/{public-url-CseXl9Fv.mjs.map → public-url-CUWWFME2.mjs.map} +1 -1
  390. package/dist/{query-axZmO6Tn.mjs → query-7m6-l0f_.mjs} +27 -17
  391. package/dist/query-7m6-l0f_.mjs.map +1 -0
  392. package/dist/{rate-limit-t5CVjCO6.mjs → rate-limit-D8RAXN8b.mjs} +2 -2
  393. package/dist/{rate-limit-t5CVjCO6.mjs.map → rate-limit-D8RAXN8b.mjs.map} +1 -1
  394. package/dist/{redirect-DGRsLO2I.mjs → redirect-BINiRYq4.mjs} +1 -1
  395. package/dist/{redirect-DGRsLO2I.mjs.map → redirect-BINiRYq4.mjs.map} +1 -1
  396. package/dist/{redirect-DkaDxq8e.mjs → redirect-CjfDGrTd.mjs} +2 -2
  397. package/dist/{redirect-DkaDxq8e.mjs.map → redirect-CjfDGrTd.mjs.map} +1 -1
  398. package/dist/{redirects-Dmj6KRU3.mjs → redirects-COMLwsV5.mjs} +19 -5
  399. package/dist/redirects-COMLwsV5.mjs.map +1 -0
  400. package/dist/{redirects-D1fdd68T.mjs → redirects-CowoEHdE.mjs} +3 -3
  401. package/dist/{redirects-D1fdd68T.mjs.map → redirects-CowoEHdE.mjs.map} +1 -1
  402. package/dist/{registry-BnCeHYsf.mjs → registry-Cyp-dx6J.mjs} +4 -4
  403. package/dist/{registry-BnCeHYsf.mjs.map → registry-Cyp-dx6J.mjs.map} +1 -1
  404. package/dist/request-cache-dzCt8TZB.mjs.map +1 -1
  405. package/dist/request-context.mjs.map +1 -1
  406. package/dist/{request-meta-CLCwSQOS.mjs → request-meta-C_Cjii-T.mjs} +2 -2
  407. package/dist/{request-meta-CLCwSQOS.mjs.map → request-meta-C_Cjii-T.mjs.map} +1 -1
  408. package/dist/resolve-D6sM-SgF.mjs +143 -0
  409. package/dist/resolve-D6sM-SgF.mjs.map +1 -0
  410. package/dist/{runner-DcfZewkO.d.mts → runner-DSQBurMS.d.mts} +8 -5
  411. package/dist/runner-DSQBurMS.d.mts.map +1 -0
  412. package/dist/{runner-DdnQIwz_.mjs → runner-Drnvs96u.mjs} +491 -188
  413. package/dist/runner-Drnvs96u.mjs.map +1 -0
  414. package/dist/runtime.d.mts +10 -10
  415. package/dist/runtime.mjs +2 -2
  416. package/dist/{schema-BmqagCwG.mjs → schema-CI9mYPX3.mjs} +4 -4
  417. package/dist/{schema-BmqagCwG.mjs.map → schema-CI9mYPX3.mjs.map} +1 -1
  418. package/dist/{search-CPrvO5u8.mjs → search-DKz_mGBP.mjs} +4 -4
  419. package/dist/{search-CPrvO5u8.mjs.map → search-DKz_mGBP.mjs.map} +1 -1
  420. package/dist/{secrets-6pgZyq0K.mjs → secrets-rPdhEBkD.mjs} +1 -1
  421. package/dist/{secrets-6pgZyq0K.mjs.map → secrets-rPdhEBkD.mjs.map} +1 -1
  422. package/dist/{sections-Cm-zb-gZ.mjs → sections-DBbCDIAT.mjs} +3 -3
  423. package/dist/{sections-Cm-zb-gZ.mjs.map → sections-DBbCDIAT.mjs.map} +1 -1
  424. package/dist/seed/index.d.mts +2 -2
  425. package/dist/seed/index.mjs +16 -16
  426. package/dist/seo/index.d.mts +1 -1
  427. package/dist/{seo-DRq9-EPP.mjs → seo-BGCyDlkb.mjs} +2 -2
  428. package/dist/{seo-DRq9-EPP.mjs.map → seo-BGCyDlkb.mjs.map} +1 -1
  429. package/dist/{seo-BoR4wCUh.mjs → seo-Dq707mNQ.mjs} +5 -3
  430. package/dist/seo-Dq707mNQ.mjs.map +1 -0
  431. package/dist/{service-vByySp-2.mjs → service-B0H7U1Y9.mjs} +3 -3
  432. package/dist/{service-vByySp-2.mjs.map → service-B0H7U1Y9.mjs.map} +1 -1
  433. package/dist/{settings-xQKsWnzQ.mjs → settings-BSXRtTzk.mjs} +3 -3
  434. package/dist/settings-BSXRtTzk.mjs.map +1 -0
  435. package/dist/{settings-CBBj7HUd.mjs → settings-DfwNyQkf.mjs} +3 -3
  436. package/dist/{settings-CBBj7HUd.mjs.map → settings-DfwNyQkf.mjs.map} +1 -1
  437. package/dist/{setup-BGAJ2uXs.mjs → setup-Cf_TyOv5.mjs} +2 -2
  438. package/dist/{setup-BGAJ2uXs.mjs.map → setup-Cf_TyOv5.mjs.map} +1 -1
  439. package/dist/{setup-complete-C6ZCLhKo.mjs → setup-complete-MzzN9u0b.mjs} +1 -1
  440. package/dist/{setup-complete-C6ZCLhKo.mjs.map → setup-complete-MzzN9u0b.mjs.map} +1 -1
  441. package/dist/{setup-nonce-CY1gQiAU.mjs → setup-nonce-DXuriHsg.mjs} +1 -1
  442. package/dist/{setup-nonce-CY1gQiAU.mjs.map → setup-nonce-DXuriHsg.mjs.map} +1 -1
  443. package/dist/{site-url-D-M4Fd8O.mjs → site-url-xkhw1tcz.mjs} +1 -1
  444. package/dist/{site-url-D-M4Fd8O.mjs.map → site-url-xkhw1tcz.mjs.map} +1 -1
  445. package/dist/{ssrf-DzFN_qV-.mjs → ssrf-MZ-zrG6-.mjs} +1 -1
  446. package/dist/{ssrf-DzFN_qV-.mjs.map → ssrf-MZ-zrG6-.mjs.map} +1 -1
  447. package/dist/storage/local.d.mts +1 -1
  448. package/dist/storage/local.mjs +1 -1
  449. package/dist/storage/local.mjs.map +1 -1
  450. package/dist/storage/s3.d.mts +1 -1
  451. package/dist/storage/s3.mjs +1 -1
  452. package/dist/storage/s3.mjs.map +1 -1
  453. package/dist/{taxonomies-Dc0mzlms.mjs → taxonomies-4vx0nmMr.mjs} +4 -4
  454. package/dist/{taxonomies-Dc0mzlms.mjs.map → taxonomies-4vx0nmMr.mjs.map} +1 -1
  455. package/dist/{taxonomies-Cn9UpaR2.mjs → taxonomies-CcvrMLbR.mjs} +8 -43
  456. package/dist/taxonomies-CcvrMLbR.mjs.map +1 -0
  457. package/dist/{taxonomy-wPfusMK9.mjs → taxonomy-zqGQUqgu.mjs} +3 -3
  458. package/dist/{taxonomy-wPfusMK9.mjs.map → taxonomy-zqGQUqgu.mjs.map} +1 -1
  459. package/dist/{tokens-DILYNZMi.mjs → tokens-N8otWMmj.mjs} +1 -1
  460. package/dist/{tokens-DILYNZMi.mjs.map → tokens-N8otWMmj.mjs.map} +1 -1
  461. package/dist/{transport-fw-mKJzT.mjs → transport-B6CHddbu.mjs} +1 -1
  462. package/dist/{transport-fw-mKJzT.mjs.map → transport-B6CHddbu.mjs.map} +1 -1
  463. package/dist/{transport-GeXlLscf.d.mts → transport-C2MGqtL6.d.mts} +1 -1
  464. package/dist/{transport-GeXlLscf.d.mts.map → transport-C2MGqtL6.d.mts.map} +1 -1
  465. package/dist/{trusted-proxy-CJhQIk65.mjs → trusted-proxy-97pajC2f.mjs} +1 -1
  466. package/dist/{trusted-proxy-CJhQIk65.mjs.map → trusted-proxy-97pajC2f.mjs.map} +1 -1
  467. package/dist/{types-CwXMEPRr.mjs → types-B0bmgwMG.mjs} +2 -2
  468. package/dist/types-B0bmgwMG.mjs.map +1 -0
  469. package/dist/{types-Dz9CGX_d.mjs → types-Cd9UCu3t.mjs} +1 -1
  470. package/dist/{types-Dz9CGX_d.mjs.map → types-Cd9UCu3t.mjs.map} +1 -1
  471. package/dist/{types-DmxPPXGf.d.mts → types-CkDSF81F.d.mts} +1 -1
  472. package/dist/{types-DmxPPXGf.d.mts.map → types-CkDSF81F.d.mts.map} +1 -1
  473. package/dist/{types-BWhaSS7U.d.mts → types-CpUuGcd5.d.mts} +1 -1
  474. package/dist/{types-BWhaSS7U.d.mts.map → types-CpUuGcd5.d.mts.map} +1 -1
  475. package/dist/{types-DFowNO60.d.mts → types-D599-ruj.d.mts} +1 -1
  476. package/dist/{types-DFowNO60.d.mts.map → types-D599-ruj.d.mts.map} +1 -1
  477. package/dist/{types-B05e2naf.d.mts → types-DGHWRQgr.d.mts} +3 -3
  478. package/dist/{types-B05e2naf.d.mts.map → types-DGHWRQgr.d.mts.map} +1 -1
  479. package/dist/{types-CzvJd1ND.d.mts → types-DaYDYW6g.d.mts} +14 -1
  480. package/dist/types-DaYDYW6g.d.mts.map +1 -0
  481. package/dist/{types-C1KKK4VP.d.mts → types-DaqNzqVt.d.mts} +16 -1
  482. package/dist/{types-C1KKK4VP.d.mts.map → types-DaqNzqVt.d.mts.map} +1 -1
  483. package/dist/{types-DW1l0gCv.d.mts → types-Dgo6y-Ut.d.mts} +1 -1
  484. package/dist/{types-DW1l0gCv.d.mts.map → types-Dgo6y-Ut.d.mts.map} +1 -1
  485. package/dist/{types-Cb2UCDJg.d.mts → types-bYmRn_Uy.d.mts} +1 -1
  486. package/dist/{types-Cb2UCDJg.d.mts.map → types-bYmRn_Uy.d.mts.map} +1 -1
  487. package/dist/{user-Dr1bOCqS.mjs → user-hUSOaIJy.mjs} +2 -2
  488. package/dist/{user-Dr1bOCqS.mjs.map → user-hUSOaIJy.mjs.map} +1 -1
  489. package/dist/{utils-_F-rWBTN.mjs → utils-C3wTAP-P.mjs} +1 -1
  490. package/dist/{utils-_F-rWBTN.mjs.map → utils-C3wTAP-P.mjs.map} +1 -1
  491. package/dist/{validate-BpQGsmd7.d.mts → validate-DQtHw9NT.d.mts} +5 -5
  492. package/dist/{validate-BpQGsmd7.d.mts.map → validate-DQtHw9NT.d.mts.map} +1 -1
  493. package/dist/{validate-DlFxcVVK.mjs → validate-IGltez8n.mjs} +2 -2
  494. package/dist/{validate-DlFxcVVK.mjs.map → validate-IGltez8n.mjs.map} +1 -1
  495. package/dist/{validation-BiFJqUp5.mjs → validation-Bmymau7y.mjs} +6 -6
  496. package/dist/{validation-BiFJqUp5.mjs.map → validation-Bmymau7y.mjs.map} +1 -1
  497. package/dist/version-BTc87L3L.mjs +7 -0
  498. package/dist/{version-DNmQakZO.mjs.map → version-BTc87L3L.mjs.map} +1 -1
  499. package/dist/{widgets-B9j_yzlk.mjs → widgets-yHQa4c6c.mjs} +3 -3
  500. package/dist/widgets-yHQa4c6c.mjs.map +1 -0
  501. package/dist/{zod-generator-DSyz01KE.mjs → zod-generator-B80aap1J.mjs} +2 -2
  502. package/dist/{zod-generator-DSyz01KE.mjs.map → zod-generator-B80aap1J.mjs.map} +1 -1
  503. package/package.json +12 -10
  504. package/src/api/error.ts +18 -3
  505. package/src/api/errors.ts +8 -0
  506. package/src/api/handlers/bylines.ts +161 -0
  507. package/src/api/handlers/content.ts +125 -43
  508. package/src/api/handlers/index.ts +8 -0
  509. package/src/api/handlers/marketplace.ts +27 -5
  510. package/src/api/handlers/oauth-clients.ts +1 -1
  511. package/src/api/handlers/registry.ts +622 -5
  512. package/src/api/handlers/seo.ts +16 -1
  513. package/src/api/handlers/snapshot.ts +1 -1
  514. package/src/api/openapi/document.ts +1 -1
  515. package/src/api/schemas/bylines.ts +46 -0
  516. package/src/astro/integration/index.ts +27 -1
  517. package/src/astro/integration/routes.ts +10 -0
  518. package/src/astro/integration/runtime.ts +20 -1
  519. package/src/astro/integration/virtual-modules.ts +19 -2
  520. package/src/astro/integration/vite-config.ts +2 -2
  521. package/src/astro/middleware/auth.ts +7 -7
  522. package/src/astro/middleware/request-context.ts +1 -1
  523. package/src/astro/middleware.ts +35 -20
  524. package/src/astro/public-plugin-api-routes.ts +41 -0
  525. package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -12
  526. package/src/astro/routes/api/admin/bylines/[id]/translations.ts +99 -0
  527. package/src/astro/routes/api/admin/bylines/index.ts +22 -11
  528. package/src/astro/routes/api/admin/plugins/[id]/update.ts +1 -0
  529. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +6 -1
  530. package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +51 -0
  531. package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +83 -0
  532. package/src/astro/routes/api/admin/plugins/registry/artifact.ts +388 -0
  533. package/src/astro/routes/api/admin/plugins/registry/install.ts +7 -1
  534. package/src/astro/routes/api/admin/plugins/updates.ts +43 -6
  535. package/src/astro/routes/api/admin/themes/marketplace/index.ts +1 -1
  536. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +2 -2
  537. package/src/astro/routes/api/auth/oauth/[provider].ts +2 -2
  538. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +2 -2
  539. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +2 -2
  540. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -2
  541. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +2 -2
  542. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +2 -2
  543. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +6 -6
  544. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
  545. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +2 -2
  546. package/src/astro/routes/api/content/[collection]/[id].ts +6 -6
  547. package/src/astro/routes/api/import/wordpress/execute.ts +1 -1
  548. package/src/astro/routes/api/import/wordpress/prepare.ts +2 -2
  549. package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +22 -0
  550. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +8 -5
  551. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +2 -2
  552. package/src/astro/routes/api/media/upload-url.ts +1 -1
  553. package/src/astro/routes/api/redirects/404s/index.ts +3 -3
  554. package/src/astro/routes/api/redirects/404s/summary.ts +1 -1
  555. package/src/astro/routes/api/redirects/[id].ts +3 -3
  556. package/src/astro/routes/api/redirects/index.ts +2 -2
  557. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +4 -4
  558. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +2 -6
  559. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +1 -1
  560. package/src/astro/routes/api/schema/collections/[slug]/index.ts +6 -6
  561. package/src/astro/routes/api/schema/collections/index.ts +4 -4
  562. package/src/astro/routes/api/schema/index.ts +1 -1
  563. package/src/astro/routes/api/schema/orphans/[slug].ts +1 -1
  564. package/src/astro/routes/api/schema/orphans/index.ts +1 -1
  565. package/src/astro/routes/api/sections/[slug].ts +3 -3
  566. package/src/astro/routes/api/sections/index.ts +2 -2
  567. package/src/astro/routes/sitemap-[collection].xml.ts +114 -14
  568. package/src/astro/types.ts +18 -0
  569. package/src/auth/rate-limit.ts +1 -1
  570. package/src/auth/trusted-proxy.ts +1 -1
  571. package/src/bylines/index.ts +154 -55
  572. package/src/cli/commands/init.ts +4 -8
  573. package/src/client/index.ts +1 -1
  574. package/src/components/InlinePortableTextEditor.tsx +5 -1
  575. package/src/components/inline-code-block.tsx +343 -0
  576. package/src/config/secrets.ts +3 -3
  577. package/src/content/converters/portable-text-to-prosemirror.ts +35 -11
  578. package/src/database/connection.ts +3 -10
  579. package/src/database/errors.ts +14 -0
  580. package/src/database/index.ts +3 -1
  581. package/src/database/migrations/006_taxonomy_defs.ts +1 -1
  582. package/src/database/migrations/014_draft_revisions.ts +6 -6
  583. package/src/database/migrations/040_byline_i18n.ts +497 -0
  584. package/src/database/migrations/runner.ts +33 -22
  585. package/src/database/repositories/audit.ts +2 -2
  586. package/src/database/repositories/byline.ts +320 -50
  587. package/src/database/repositories/media.ts +2 -2
  588. package/src/database/repositories/menu.ts +1 -1
  589. package/src/database/repositories/options.ts +3 -3
  590. package/src/database/repositories/plugin-storage.ts +3 -3
  591. package/src/database/repositories/types.ts +13 -0
  592. package/src/database/types.ts +15 -0
  593. package/src/emdash-runtime.ts +493 -20
  594. package/src/i18n/config.ts +1 -1
  595. package/src/i18n/resolve.ts +152 -0
  596. package/src/index.ts +9 -0
  597. package/src/loader.ts +134 -60
  598. package/src/mcp/server.ts +3 -3
  599. package/src/media/mime.ts +1 -1
  600. package/src/page/absolute-url.ts +1 -1
  601. package/src/plugin-utils.ts +23 -0
  602. package/src/plugins/adapt-sandbox-entry.ts +45 -40
  603. package/src/plugins/email-console.ts +1 -1
  604. package/src/plugins/index.ts +1 -0
  605. package/src/plugins/marketplace.ts +1 -1
  606. package/src/plugins/sandbox/index.ts +1 -0
  607. package/src/plugins/sandbox/noop.ts +11 -3
  608. package/src/plugins/sandbox/types.ts +28 -0
  609. package/src/query.ts +41 -7
  610. package/src/registry/config.ts +1 -1
  611. package/src/request-cache.ts +3 -3
  612. package/src/request-context.ts +1 -1
  613. package/src/settings/index.ts +4 -4
  614. package/src/storage/local.ts +1 -1
  615. package/src/storage/s3.ts +3 -3
  616. package/src/utils/db-errors.ts +24 -0
  617. package/src/widgets/index.ts +1 -1
  618. package/dist/api-BMLZuwM4.mjs.map +0 -1
  619. package/dist/byline-D09BaS4j.mjs +0 -220
  620. package/dist/byline-D09BaS4j.mjs.map +0 -1
  621. package/dist/bylines-BTM2xtP8.mjs +0 -113
  622. package/dist/bylines-BTM2xtP8.mjs.map +0 -1
  623. package/dist/bylines-BdUP8NuI.d.mts.map +0 -1
  624. package/dist/connection-2igzM-AT.mjs +0 -57
  625. package/dist/connection-2igzM-AT.mjs.map +0 -1
  626. package/dist/context-qF8d3IPR.mjs.map +0 -1
  627. package/dist/db-errors-CGN9kJfo.mjs.map +0 -1
  628. package/dist/email-console-Dmp5Q-P2.mjs.map +0 -1
  629. package/dist/error-tSQWIl5U.mjs.map +0 -1
  630. package/dist/index-BV8iJ-6s.d.mts.map +0 -1
  631. package/dist/loader-Cs6-Bqe6.mjs.map +0 -1
  632. package/dist/media-Dg7he9uK.mjs.map +0 -1
  633. package/dist/menus-DOzIecHi.mjs.map +0 -1
  634. package/dist/menus-X4Z-eBA1.mjs.map +0 -1
  635. package/dist/oauth-clients-D_B0_-Bz.mjs.map +0 -1
  636. package/dist/options-Cq64Wx0O.d.mts.map +0 -1
  637. package/dist/query-axZmO6Tn.mjs.map +0 -1
  638. package/dist/redirects-Dmj6KRU3.mjs.map +0 -1
  639. package/dist/runner-DcfZewkO.d.mts.map +0 -1
  640. package/dist/runner-DdnQIwz_.mjs.map +0 -1
  641. package/dist/seo-BoR4wCUh.mjs.map +0 -1
  642. package/dist/settings-xQKsWnzQ.mjs.map +0 -1
  643. package/dist/taxonomies-Cn9UpaR2.mjs.map +0 -1
  644. package/dist/types-CwXMEPRr.mjs.map +0 -1
  645. package/dist/types-CzvJd1ND.d.mts.map +0 -1
  646. package/dist/version-DNmQakZO.mjs +0 -7
  647. package/dist/widgets-B9j_yzlk.mjs.map +0 -1
  648. /package/dist/{api-tokens-D3C9v02m.mjs → api-tokens-iPIHAY8N.mjs} +0 -0
  649. /package/dist/{ssrf-CTul4uQi.mjs → ssrf-BIcd-aXW.mjs} +0 -0
  650. /package/dist/{types-Db67HHlU.mjs → types-1NNkmTIn.mjs} +0 -0
@@ -38,7 +38,10 @@
38
38
  * mitigated by the artifact checksum but not detected.
39
39
  */
40
40
 
41
+ import { ClientResponseError, ClientValidationError } from "@atcute/client";
41
42
  import type { Did } from "@atcute/lexicons";
43
+ import { checkEnvCompatibility, findSkippedEnvConstraints } from "@emdash-cms/registry-client/env";
44
+ import type { HostEnv } from "@emdash-cms/registry-client/env";
42
45
  import type { Kysely } from "kysely";
43
46
 
44
47
  import type { Database } from "../../database/types.js";
@@ -59,7 +62,13 @@ import { resolveAndValidateExternalUrl, SsrfError } from "../../security/ssrf.js
59
62
  import { EmDashStorageError } from "../../storage/types.js";
60
63
  import type { Storage } from "../../storage/types.js";
61
64
  import type { ApiResult } from "../types.js";
62
- import { deleteBundleFromR2, storeBundleInR2 } from "./marketplace.js";
65
+ import {
66
+ deleteBundleFromR2,
67
+ diffCapabilities,
68
+ diffRouteVisibility,
69
+ loadBundleFromR2,
70
+ storeBundleInR2,
71
+ } from "./marketplace.js";
63
72
 
64
73
  // ── Types ──────────────────────────────────────────────────────────
65
74
 
@@ -162,7 +171,7 @@ async function sha256MultibaseMultihash(bytes: Uint8Array): Promise<string> {
162
171
  * Hash functions other than sha2-256 are out of scope for this
163
172
  * initial release; the install fails closed.
164
173
  */
165
- async function verifyChecksum(bytes: Uint8Array, checksum: string): Promise<boolean> {
174
+ export async function verifyChecksum(bytes: Uint8Array, checksum: string): Promise<boolean> {
166
175
  if (SHA256_HEX_PATTERN.test(checksum)) {
167
176
  const actual = await sha256Hex(bytes);
168
177
  return checksum.toLowerCase() === actual;
@@ -314,7 +323,7 @@ function isLocalhostHostname(hostname: string): boolean {
314
323
  * `import.meta.env.DEV` is a Vite/Astro compile-time constant, so
315
324
  * production bundles cannot enable the dev escape hatch at runtime.
316
325
  */
317
- async function assertSafeArtifactUrl(urlString: string): Promise<URL> {
326
+ export async function assertSafeArtifactUrl(urlString: string): Promise<URL> {
318
327
  let url: URL;
319
328
  try {
320
329
  url = new URL(urlString);
@@ -364,7 +373,7 @@ async function assertSafeArtifactUrl(urlString: string): Promise<URL> {
364
373
  return await resolveAndValidateExternalUrl(url.href);
365
374
  } catch (err) {
366
375
  if (err instanceof SsrfError) {
367
- throw new Error(`Artifact URL rejected: ${err.message}`);
376
+ throw new Error(`Artifact URL rejected: ${err.message}`, { cause: err });
368
377
  }
369
378
  throw err;
370
379
  }
@@ -513,6 +522,52 @@ async function fetchArtifact(mirrors: string[], declaredUrl: string): Promise<Ui
513
522
  );
514
523
  }
515
524
 
525
+ /**
526
+ * The shape of a single env-compatibility failure returned to the admin in
527
+ * the `ENV_INCOMPATIBLE` error's `details`.
528
+ */
529
+ interface EnvIncompatibleError {
530
+ code: "ENV_INCOMPATIBLE";
531
+ message: string;
532
+ details: { requires: Record<string, string>; host: HostEnv };
533
+ }
534
+
535
+ /**
536
+ * Gate a release's `requires` constraints against the running host
537
+ * environment. `requires` is the lexicon-`unknown` value off the signed
538
+ * release record — never trust its shape; `checkEnvCompatibility` guards it.
539
+ *
540
+ * Returns `null` when every advertised constraint is satisfied (or there are
541
+ * none), or a structured `ENV_INCOMPATIBLE` error naming the unsatisfied
542
+ * constraints and the host versions. The error carries the guarded `requires`
543
+ * and `host` maps so the admin can render the same mismatch the UI gate shows.
544
+ */
545
+ export function assertEnvCompatible(
546
+ requires: unknown,
547
+ hostEnv: HostEnv,
548
+ ): EnvIncompatibleError | null {
549
+ // A constraint the host can't evaluate (unknown or unparseable host
550
+ // version) downgrades the gate to a no-op for that env. Log it so a
551
+ // silent bypass is observable rather than invisible.
552
+ for (const skipped of findSkippedEnvConstraints(requires, hostEnv)) {
553
+ console.warn(
554
+ `[registry] env compatibility constraint skipped: ${skipped.key} requires ${skipped.required} but host version is ${skipped.reason}`,
555
+ );
556
+ }
557
+ const mismatches = checkEnvCompatibility(requires, hostEnv);
558
+ if (mismatches.length === 0) return null;
559
+ const guarded: Record<string, string> = {};
560
+ for (const m of mismatches) guarded[m.key] = m.required;
561
+ const summary = mismatches
562
+ .map((m) => `${m.key} requires ${m.required} but host is ${m.host}`)
563
+ .join("; ");
564
+ return {
565
+ code: "ENV_INCOMPATIBLE",
566
+ message: `This release is not compatible with the current environment: ${summary}.`,
567
+ details: { requires: guarded, host: hostEnv },
568
+ };
569
+ }
570
+
516
571
  // ── Install ────────────────────────────────────────────────────────
517
572
 
518
573
  export async function handleRegistryInstall(
@@ -521,7 +576,7 @@ export async function handleRegistryInstall(
521
576
  sandboxRunner: SandboxRunner | null,
522
577
  registryConfigInput: RegistryConfigInput | undefined,
523
578
  input: RegistryInstallInput,
524
- opts?: { configuredPluginIds?: Set<string> },
579
+ opts?: { configuredPluginIds?: Set<string>; hostEnv?: HostEnv },
525
580
  ): Promise<ApiResult<RegistryInstallResult>> {
526
581
  // Accept either the bare-string shorthand or the full
527
582
  // `RegistryConfig` object (see `RegistryConfigInput`).
@@ -730,6 +785,17 @@ export async function handleRegistryInstall(
730
785
  };
731
786
  }
732
787
 
788
+ // Step 3b: environment compatibility. The signed release record may
789
+ // carry a `requires` block (`env:emdash`, `env:astro`, ...). Refuse
790
+ // the install if the running host doesn't satisfy a constraint, so a
791
+ // stale browser tab or non-UI caller can't bypass the admin's
792
+ // disabled Install button. `requires` is lexicon-`unknown`; the
793
+ // helper guards its shape.
794
+ if (opts?.hostEnv) {
795
+ const envError = assertEnvCompatible(releaseView.release?.requires, opts.hostEnv);
796
+ if (envError) return { success: false, error: envError };
797
+ }
798
+
733
799
  // Step 3a: enforce the configured minimum release age. The browser
734
800
  // applies the same check up front for UX, but the gate lives here
735
801
  // -- a stale browser tab, a deep link, or a non-admin-UI caller
@@ -1062,6 +1128,24 @@ export async function handleRegistryInstall(
1062
1128
  },
1063
1129
  };
1064
1130
  } catch (err) {
1131
+ if (err instanceof ClientValidationError) {
1132
+ return {
1133
+ success: false,
1134
+ error: {
1135
+ code: "AGGREGATOR_RESPONSE_INVALID",
1136
+ message: `Aggregator returned a response that does not conform to its lexicon (${err.target})`,
1137
+ },
1138
+ };
1139
+ }
1140
+ if (err instanceof ClientResponseError) {
1141
+ return {
1142
+ success: false,
1143
+ error: {
1144
+ code: err.status === 404 ? "AGGREGATOR_NOT_FOUND" : "AGGREGATOR_HTTP_ERROR",
1145
+ message: `Aggregator returned ${err.status}: ${err.error}`,
1146
+ },
1147
+ };
1148
+ }
1065
1149
  if (err instanceof EmDashStorageError) {
1066
1150
  return {
1067
1151
  success: false,
@@ -1081,3 +1165,536 @@ export async function handleRegistryInstall(
1081
1165
  };
1082
1166
  }
1083
1167
  }
1168
+
1169
+ // ── Uninstall ──────────────────────────────────────────────────────
1170
+
1171
+ export interface RegistryUninstallResult {
1172
+ pluginId: string;
1173
+ /** True when `_plugin_storage` rows were also deleted (opts.deleteData). */
1174
+ dataDeleted: boolean;
1175
+ }
1176
+
1177
+ /**
1178
+ * Uninstall a registry-source plugin. Deletes the R2 bundle under
1179
+ * `registry/<pluginId>/<version>/`, optionally drops the plugin's
1180
+ * `_plugin_storage` rows, and removes the `_plugin_state` row. The
1181
+ * sandbox runtime is reconciled by the route's `syncRegistryPlugins`
1182
+ * call after this returns.
1183
+ *
1184
+ * Refuses to uninstall plugins whose `source` is not `"registry"` to
1185
+ * avoid trashing a marketplace/config plugin that happens to share the
1186
+ * pluginId namespace.
1187
+ */
1188
+ export async function handleRegistryUninstall(
1189
+ db: Kysely<Database>,
1190
+ storage: Storage | null,
1191
+ pluginId: string,
1192
+ opts?: { deleteData?: boolean },
1193
+ ): Promise<ApiResult<RegistryUninstallResult>> {
1194
+ try {
1195
+ const stateRepo = new PluginStateRepository(db);
1196
+ const existing = await stateRepo.get(pluginId);
1197
+ if (!existing || existing.source !== "registry") {
1198
+ return {
1199
+ success: false,
1200
+ error: {
1201
+ code: "NOT_FOUND",
1202
+ message: `No registry plugin found: ${pluginId}`,
1203
+ },
1204
+ };
1205
+ }
1206
+
1207
+ // `_plugin_state.version` carries the installed version directly for
1208
+ // registry-source rows (there's no shadow column like marketplace's
1209
+ // `marketplaceVersion`). Use it verbatim for the R2 prefix.
1210
+ const version = existing.version;
1211
+
1212
+ // Order: optional storage cleanup → bundle delete → state row delete.
1213
+ // The most failure-prone step runs first so a transient DB error
1214
+ // (deadlock, contention) cascades to the outer catch with the state
1215
+ // row and bundle intact — admin retries safely. Bundle delete is
1216
+ // idempotent on misses.
1217
+ let dataDeleted = false;
1218
+ if (opts?.deleteData) {
1219
+ await db.deleteFrom("_plugin_storage").where("plugin_id", "=", pluginId).execute();
1220
+ dataDeleted = true;
1221
+ }
1222
+
1223
+ if (storage) {
1224
+ await deleteBundleFromR2(storage, pluginId, version, "registry");
1225
+ }
1226
+
1227
+ await stateRepo.delete(pluginId);
1228
+
1229
+ return { success: true, data: { pluginId, dataDeleted } };
1230
+ } catch (err) {
1231
+ console.error("[registry-uninstall] Failed:", err);
1232
+ return {
1233
+ success: false,
1234
+ error: {
1235
+ code: "UNINSTALL_FAILED",
1236
+ message: "Failed to uninstall plugin",
1237
+ },
1238
+ };
1239
+ }
1240
+ }
1241
+
1242
+ // ── Update ─────────────────────────────────────────────────────────
1243
+
1244
+ export interface RegistryUpdateResult {
1245
+ pluginId: string;
1246
+ oldVersion: string;
1247
+ newVersion: string;
1248
+ capabilityChanges: { added: string[]; removed: string[] };
1249
+ /** Set only when `newlyPublic` is non-empty, mirroring marketplace. */
1250
+ routeVisibilityChanges?: { newlyPublic: string[] };
1251
+ }
1252
+
1253
+ /**
1254
+ * Update a registry-source plugin to a newer release. Mirrors
1255
+ * `handleMarketplaceUpdate`: resolves the target version via the aggregator,
1256
+ * re-runs the artifact fetch / checksum / extract pipeline, diffs capabilities
1257
+ * and route visibility against the currently installed bundle, and gates
1258
+ * escalations behind `confirmCapabilityChanges` / `confirmRouteVisibilityChanges`
1259
+ * so the admin re-consents to widened permissions.
1260
+ *
1261
+ * Refuses non-registry sources. Refuses when the stored state row is missing
1262
+ * the `(publisherDid, slug)` it needs to resolve against the aggregator.
1263
+ */
1264
+ export async function handleRegistryUpdate(
1265
+ db: Kysely<Database>,
1266
+ storage: Storage | null,
1267
+ sandboxRunner: SandboxRunner | null,
1268
+ registryConfigInput: RegistryConfigInput | undefined,
1269
+ pluginId: string,
1270
+ opts?: {
1271
+ version?: string;
1272
+ confirmCapabilityChanges?: boolean;
1273
+ confirmRouteVisibilityChanges?: boolean;
1274
+ hostEnv?: HostEnv;
1275
+ },
1276
+ ): Promise<ApiResult<RegistryUpdateResult>> {
1277
+ const registryConfig = coerceRegistryConfig(registryConfigInput);
1278
+ if (!registryConfig) {
1279
+ return {
1280
+ success: false,
1281
+ error: { code: "REGISTRY_NOT_CONFIGURED", message: "Registry is not configured" },
1282
+ };
1283
+ }
1284
+ if (!storage) {
1285
+ return {
1286
+ success: false,
1287
+ error: {
1288
+ code: "STORAGE_NOT_CONFIGURED",
1289
+ message: "Storage is required for registry plugin updates",
1290
+ },
1291
+ };
1292
+ }
1293
+ if (!sandboxRunner || !sandboxRunner.isAvailable()) {
1294
+ return {
1295
+ success: false,
1296
+ error: { code: "SANDBOX_NOT_AVAILABLE", message: "Sandbox runner is required" },
1297
+ };
1298
+ }
1299
+ try {
1300
+ validateAggregatorUrl(registryConfig.aggregatorUrl);
1301
+ } catch (err) {
1302
+ return {
1303
+ success: false,
1304
+ error: {
1305
+ code: "REGISTRY_NOT_CONFIGURED",
1306
+ message: err instanceof Error ? err.message : "Invalid aggregator URL",
1307
+ },
1308
+ };
1309
+ }
1310
+
1311
+ try {
1312
+ const stateRepo = new PluginStateRepository(db);
1313
+ const existing = await stateRepo.get(pluginId);
1314
+ if (!existing || existing.source !== "registry") {
1315
+ return {
1316
+ success: false,
1317
+ error: { code: "NOT_FOUND", message: `No registry plugin found: ${pluginId}` },
1318
+ };
1319
+ }
1320
+ if (!existing.registryPublisherDid || !existing.registrySlug) {
1321
+ return {
1322
+ success: false,
1323
+ error: {
1324
+ code: "INVALID_STATE",
1325
+ message: `Registry plugin ${pluginId} is missing publisher DID or slug in state`,
1326
+ },
1327
+ };
1328
+ }
1329
+ const oldVersion = existing.version;
1330
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- existing.registryPublisherDid is a DID string written by the install handler
1331
+ const publisherDid = existing.registryPublisherDid as Did;
1332
+ const slug = existing.registrySlug;
1333
+
1334
+ const { DiscoveryClient } = await import("@emdash-cms/registry-client/discovery");
1335
+ const aggregatorDeadline = Date.now() + AGGREGATOR_TOTAL_BUDGET_MS;
1336
+ const discovery = new DiscoveryClient({
1337
+ aggregatorUrl: registryConfig.aggregatorUrl,
1338
+ acceptLabelers: registryConfig.acceptLabelers,
1339
+ fetch: timedFetch(aggregatorDeadline),
1340
+ });
1341
+
1342
+ // Resolve target release. Explicit version → paginate listReleases;
1343
+ // otherwise getLatestRelease (aggregator applies its own filters).
1344
+ const MAX_LIST_PAGES = 20;
1345
+ const releaseView = await (async () => {
1346
+ if (!opts?.version) {
1347
+ return discovery.getLatestRelease({ did: publisherDid, package: slug });
1348
+ }
1349
+ let cursor: string | undefined;
1350
+ const seenCursors = new Set<string>();
1351
+ for (let page = 0; page < MAX_LIST_PAGES; page++) {
1352
+ if (cursor !== undefined) {
1353
+ if (seenCursors.has(cursor)) break;
1354
+ seenCursors.add(cursor);
1355
+ }
1356
+ const result = await discovery.listReleases({
1357
+ did: publisherDid,
1358
+ package: slug,
1359
+ cursor,
1360
+ limit: 50,
1361
+ });
1362
+ for (const r of result.releases) {
1363
+ if (r.version === opts.version) return r;
1364
+ }
1365
+ if (!result.cursor) break;
1366
+ cursor = result.cursor;
1367
+ }
1368
+ return undefined;
1369
+ })();
1370
+
1371
+ if (!releaseView) {
1372
+ return {
1373
+ success: false,
1374
+ error: {
1375
+ code: "NO_VERSION",
1376
+ message: opts?.version
1377
+ ? `Version ${opts.version} not found for ${publisherDid}/${slug}`
1378
+ : `No installable release found for ${publisherDid}/${slug}`,
1379
+ },
1380
+ };
1381
+ }
1382
+
1383
+ // Identity cross-check. A buggy/compromised aggregator must not
1384
+ // trick us into installing a record signed for a different
1385
+ // (did, slug, version) under this plugin's pluginId.
1386
+ const signedRelease = releaseView.release;
1387
+ if (
1388
+ releaseView.did !== publisherDid ||
1389
+ releaseView.package !== slug ||
1390
+ signedRelease?.package !== slug ||
1391
+ (opts?.version !== undefined && releaseView.version !== opts.version) ||
1392
+ signedRelease?.version !== releaseView.version
1393
+ ) {
1394
+ return {
1395
+ success: false,
1396
+ error: {
1397
+ code: "AGGREGATOR_IDENTITY_MISMATCH",
1398
+ message:
1399
+ "Aggregator returned a release view that does not match the requested package or version.",
1400
+ },
1401
+ };
1402
+ }
1403
+
1404
+ const newVersion = releaseView.version;
1405
+ if (newVersion === oldVersion) {
1406
+ return {
1407
+ success: false,
1408
+ error: {
1409
+ code: "ALREADY_UP_TO_DATE",
1410
+ message: "Plugin is already at the requested version",
1411
+ },
1412
+ };
1413
+ }
1414
+
1415
+ // Yanked label check (mirrors install).
1416
+ const releaseYanked = (releaseView.labels ?? []).some(
1417
+ (l: { val?: string }) => l.val === "security:yanked",
1418
+ );
1419
+ if (releaseYanked) {
1420
+ return {
1421
+ success: false,
1422
+ error: { code: "YANKED", message: "Release has been yanked by a trusted labeller" },
1423
+ };
1424
+ }
1425
+
1426
+ // Environment compatibility gate. An ungated update could otherwise
1427
+ // land a version whose `requires` the host doesn't satisfy. Same
1428
+ // guard as install; `requires` is lexicon-`unknown`.
1429
+ if (opts?.hostEnv) {
1430
+ const envError = assertEnvCompatible(signedRelease.requires, opts.hostEnv);
1431
+ if (envError) return { success: false, error: envError };
1432
+ }
1433
+
1434
+ const declaredUrl = signedRelease.artifacts?.package?.url;
1435
+ const declaredChecksum = signedRelease.artifacts?.package?.checksum;
1436
+ if (!declaredUrl || !declaredChecksum) {
1437
+ return {
1438
+ success: false,
1439
+ error: {
1440
+ code: "INVALID_RELEASE",
1441
+ message: "Release record is missing artifact url or checksum",
1442
+ },
1443
+ };
1444
+ }
1445
+
1446
+ // SSRF check on declared URL + each mirror.
1447
+ await assertSafeArtifactUrl(declaredUrl);
1448
+ const rawMirrors = releaseView.mirrors ?? [];
1449
+ const mirrors = rawMirrors.slice(0, MAX_MIRRORS);
1450
+ for (const mirror of mirrors) {
1451
+ await assertSafeArtifactUrl(mirror);
1452
+ }
1453
+
1454
+ // `fetchArtifact` derives its own per-call deadline internally.
1455
+ const artifactBytes = await fetchArtifact(mirrors, declaredUrl);
1456
+ if (!(await verifyChecksum(artifactBytes, declaredChecksum))) {
1457
+ return {
1458
+ success: false,
1459
+ error: {
1460
+ code: "CHECKSUM_MISMATCH",
1461
+ message: "Artifact bytes do not match the release's published checksum",
1462
+ },
1463
+ };
1464
+ }
1465
+
1466
+ const bundle: PluginBundle = await extractBundle(artifactBytes);
1467
+
1468
+ if (bundle.manifest.version !== newVersion) {
1469
+ return {
1470
+ success: false,
1471
+ error: {
1472
+ code: "BUNDLE_VERSION_MISMATCH",
1473
+ message: `Bundle manifest version (${bundle.manifest.version}) does not match release version (${newVersion})`,
1474
+ },
1475
+ };
1476
+ }
1477
+ if (bundle.manifest.id !== slug) {
1478
+ return {
1479
+ success: false,
1480
+ error: {
1481
+ code: "BUNDLE_IDENTITY_MISMATCH",
1482
+ message: `Bundle manifest id (${bundle.manifest.id}) does not match registry slug (${slug})`,
1483
+ },
1484
+ };
1485
+ }
1486
+
1487
+ // Rewrite manifest.id to the opaque pluginId so the sandbox loader
1488
+ // and R2 layout stay in sync across install and update.
1489
+ bundle.manifest = { ...bundle.manifest, id: pluginId };
1490
+
1491
+ // Diff capabilities + route visibility against the currently
1492
+ // installed bundle. Loading from R2 keeps us honest: the diff is
1493
+ // against the bytes the sandbox is actually running, not whatever
1494
+ // the state row claims.
1495
+ const oldBundle = await loadBundleFromR2(storage, pluginId, oldVersion, "registry");
1496
+ const oldCaps = oldBundle?.manifest.capabilities ?? [];
1497
+ const capabilityChanges = diffCapabilities(oldCaps, bundle.manifest.capabilities);
1498
+ const hasEscalation = capabilityChanges.added.length > 0;
1499
+ if (hasEscalation && !opts?.confirmCapabilityChanges) {
1500
+ return {
1501
+ success: false,
1502
+ error: {
1503
+ code: "CAPABILITY_ESCALATION",
1504
+ message: "Plugin update requires new capabilities",
1505
+ details: { capabilityChanges },
1506
+ },
1507
+ };
1508
+ }
1509
+
1510
+ const routeVisibilityChanges = diffRouteVisibility(oldBundle?.manifest, bundle.manifest);
1511
+ const hasNewPublicRoutes = routeVisibilityChanges.newlyPublic.length > 0;
1512
+ if (hasNewPublicRoutes && !opts?.confirmRouteVisibilityChanges) {
1513
+ return {
1514
+ success: false,
1515
+ error: {
1516
+ code: "ROUTE_VISIBILITY_ESCALATION",
1517
+ message: "Plugin update exposes new public (unauthenticated) routes",
1518
+ details: { routeVisibilityChanges, capabilityChanges },
1519
+ },
1520
+ };
1521
+ }
1522
+
1523
+ // Store new bundle. R2 prefix is deterministic per (pluginId, version),
1524
+ // so a retry of the same update is idempotent.
1525
+ await storeBundleInR2(storage, pluginId, newVersion, bundle, "registry");
1526
+
1527
+ // Update state. Preserve publisher/slug; refresh displayName /
1528
+ // description from the install handler's seeded values (we don't
1529
+ // re-fetch the profile here — that's a separate `getPackage` round
1530
+ // trip and the install-time values are still authoritative for
1531
+ // the same package identity).
1532
+ await stateRepo.upsert(pluginId, newVersion, "active", {
1533
+ source: "registry",
1534
+ registryPublisherDid: publisherDid,
1535
+ registrySlug: slug,
1536
+ displayName: existing.displayName ?? slug,
1537
+ description: existing.description ?? undefined,
1538
+ });
1539
+
1540
+ // Best-effort cleanup of the old bundle. Failures here don't roll
1541
+ // back the upgrade (the new bundle is already stored and committed
1542
+ // in the state row); the orphan is just storage we'll pay for.
1543
+ deleteBundleFromR2(storage, pluginId, oldVersion, "registry").catch(() => {});
1544
+
1545
+ return {
1546
+ success: true,
1547
+ data: {
1548
+ pluginId,
1549
+ oldVersion,
1550
+ newVersion,
1551
+ capabilityChanges,
1552
+ routeVisibilityChanges: hasNewPublicRoutes ? routeVisibilityChanges : undefined,
1553
+ },
1554
+ };
1555
+ } catch (err) {
1556
+ if (err instanceof ClientValidationError) {
1557
+ return {
1558
+ success: false,
1559
+ error: {
1560
+ code: "AGGREGATOR_RESPONSE_INVALID",
1561
+ message: `Aggregator returned a response that does not conform to its lexicon (${err.target})`,
1562
+ },
1563
+ };
1564
+ }
1565
+ if (err instanceof ClientResponseError) {
1566
+ return {
1567
+ success: false,
1568
+ error: {
1569
+ code: err.status === 404 ? "AGGREGATOR_NOT_FOUND" : "AGGREGATOR_HTTP_ERROR",
1570
+ message: `Aggregator returned ${err.status}: ${err.error}`,
1571
+ },
1572
+ };
1573
+ }
1574
+ if (err instanceof EmDashStorageError) {
1575
+ return {
1576
+ success: false,
1577
+ error: {
1578
+ code: err.code ?? "STORAGE_ERROR",
1579
+ message: "Storage error while updating plugin",
1580
+ },
1581
+ };
1582
+ }
1583
+ console.error("[registry-update] Failed:", err);
1584
+ return {
1585
+ success: false,
1586
+ error: {
1587
+ code: "UPDATE_FAILED",
1588
+ message: err instanceof Error ? err.message : "Failed to update plugin",
1589
+ },
1590
+ };
1591
+ }
1592
+ }
1593
+
1594
+ // ── Update check ───────────────────────────────────────────────────
1595
+
1596
+ export interface RegistryUpdateCheck {
1597
+ pluginId: string;
1598
+ installed: string;
1599
+ latest: string;
1600
+ hasUpdate: boolean;
1601
+ /**
1602
+ * Both diff fields are `false` here by design: computing them at
1603
+ * update-check time would require downloading both bundles (or
1604
+ * extracting from the signed release extension and the installed
1605
+ * R2 bundle), which is too expensive for a bulk preview. The actual
1606
+ * escalation gate runs at update time in `handleRegistryUpdate`.
1607
+ * Mirrors marketplace's `hasRouteVisibilityChanges: false`.
1608
+ */
1609
+ hasCapabilityChanges: boolean;
1610
+ hasRouteVisibilityChanges: boolean;
1611
+ }
1612
+
1613
+ /**
1614
+ * Bulk update check across every installed registry plugin. Queries the
1615
+ * aggregator for each plugin's latest release and reports `hasUpdate`
1616
+ * based on the version comparison. Plugins whose aggregator lookup fails
1617
+ * (unreachable, delisted, malformed) are skipped silently — one bad
1618
+ * publisher must not blank the whole admin Updates list.
1619
+ */
1620
+ export async function handleRegistryUpdateCheck(
1621
+ db: Kysely<Database>,
1622
+ registryConfigInput: RegistryConfigInput | undefined,
1623
+ ): Promise<ApiResult<{ items: RegistryUpdateCheck[] }>> {
1624
+ const registryConfig = coerceRegistryConfig(registryConfigInput);
1625
+ if (!registryConfig) {
1626
+ return {
1627
+ success: false,
1628
+ error: { code: "REGISTRY_NOT_CONFIGURED", message: "Registry is not configured" },
1629
+ };
1630
+ }
1631
+
1632
+ try {
1633
+ const stateRepo = new PluginStateRepository(db);
1634
+ const registryPlugins = await stateRepo.getRegistryPlugins();
1635
+ if (registryPlugins.length === 0) {
1636
+ return { success: true, data: { items: [] } };
1637
+ }
1638
+
1639
+ const { DiscoveryClient } = await import("@emdash-cms/registry-client/discovery");
1640
+ const aggregatorDeadline = Date.now() + AGGREGATOR_TOTAL_BUDGET_MS;
1641
+ const discovery = new DiscoveryClient({
1642
+ aggregatorUrl: registryConfig.aggregatorUrl,
1643
+ acceptLabelers: registryConfig.acceptLabelers,
1644
+ fetch: timedFetch(aggregatorDeadline),
1645
+ });
1646
+
1647
+ const items: RegistryUpdateCheck[] = [];
1648
+ for (const plugin of registryPlugins) {
1649
+ if (!plugin.registryPublisherDid || !plugin.registrySlug) continue;
1650
+ try {
1651
+ const releaseView = await discovery.getLatestRelease({
1652
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- DID string was validated by the install handler
1653
+ did: plugin.registryPublisherDid as Did,
1654
+ package: plugin.registrySlug,
1655
+ });
1656
+ const latest = releaseView.version;
1657
+ if (!latest) continue;
1658
+ const installed = plugin.version;
1659
+ items.push({
1660
+ pluginId: plugin.pluginId,
1661
+ installed,
1662
+ latest,
1663
+ hasUpdate: latest !== installed,
1664
+ hasCapabilityChanges: false,
1665
+ hasRouteVisibilityChanges: false,
1666
+ });
1667
+ } catch (err) {
1668
+ // Skip plugins that can't be checked. Don't fail the whole
1669
+ // list because one aggregator query went wrong.
1670
+ console.warn(`[registry-update-check] Skipped ${plugin.pluginId}:`, err);
1671
+ }
1672
+ }
1673
+
1674
+ return { success: true, data: { items } };
1675
+ } catch (err) {
1676
+ if (err instanceof ClientValidationError) {
1677
+ return {
1678
+ success: false,
1679
+ error: {
1680
+ code: "AGGREGATOR_RESPONSE_INVALID",
1681
+ message: `Aggregator returned a response that does not conform to its lexicon (${err.target})`,
1682
+ },
1683
+ };
1684
+ }
1685
+ if (err instanceof ClientResponseError) {
1686
+ return {
1687
+ success: false,
1688
+ error: {
1689
+ code: err.status === 404 ? "AGGREGATOR_NOT_FOUND" : "AGGREGATOR_HTTP_ERROR",
1690
+ message: `Aggregator returned ${err.status}: ${err.error}`,
1691
+ },
1692
+ };
1693
+ }
1694
+ console.error("[registry-update-check] Failed:", err);
1695
+ return {
1696
+ success: false,
1697
+ error: { code: "UPDATE_CHECK_FAILED", message: "Failed to check for registry updates" },
1698
+ };
1699
+ }
1700
+ }