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
@@ -0,0 +1,388 @@
1
+ /**
2
+ * Registry artifact proxy
3
+ *
4
+ * GET /_emdash/api/admin/plugins/registry/artifact?did=&slug=&version=&kind=&index=
5
+ *
6
+ * Proxies an icon / screenshot / banner image referenced by a registry
7
+ * release record so the admin UI can display it without cross-origin
8
+ * requests to arbitrary publisher hosting.
9
+ *
10
+ * Trust model (CRITICAL): the proxy never accepts an artifact URL from the
11
+ * client. The caller addresses an artifact by its coordinates
12
+ * `(did, slug, version, kind, index)`; the server resolves the *declared*
13
+ * URL from the validated release record fetched from the configured
14
+ * aggregator. The proxy can therefore only ever fetch a URL the publisher
15
+ * declared in their signed release — not an arbitrary caller-supplied URL.
16
+ *
17
+ * The publisher-declared URL is still untrusted (an attacker who controls a
18
+ * publisher record, or the aggregator, can point it anywhere), so the
19
+ * resolved URL passes through the SSRF defences (`assertSafeArtifactUrl`,
20
+ * re-validated on every redirect hop) before any fetch, and only allowlisted
21
+ * image content types are served back.
22
+ */
23
+
24
+ import type { Did } from "@atcute/lexicons";
25
+ import type { APIRoute } from "astro";
26
+
27
+ import { requirePerm } from "#api/authorize.js";
28
+ import { apiError } from "#api/error.js";
29
+ import { assertSafeArtifactUrl } from "#api/index.js";
30
+
31
+ import { coerceRegistryConfig, validateAggregatorUrl } from "../../../../../../registry/config.js";
32
+
33
+ export const prerender = false;
34
+
35
+ /**
36
+ * Image content types the proxy will pass through. Anything else is rejected.
37
+ *
38
+ * SVG is deliberately excluded: it is active content (an `<svg><script>`
39
+ * executes when navigated to as a top-level document), and the publisher
40
+ * supplies the bytes. Rather than serve it behind mitigations, we refuse it
41
+ * end-to-end — the publish CLI rejects SVG artifacts too, so a conforming
42
+ * release never references one. AVIF is included.
43
+ */
44
+ const ALLOWED_IMAGE_TYPES = new Set([
45
+ "image/png",
46
+ "image/jpeg",
47
+ "image/webp",
48
+ "image/gif",
49
+ "image/avif",
50
+ ]);
51
+
52
+ /** Artifact kinds the proxy can resolve. `screenshot` additionally needs `index`. */
53
+ const ALLOWED_KINDS = new Set(["icon", "banner", "screenshot"]);
54
+
55
+ /** Loose DID shape (`did:method:id`); the aggregator lexicon is authoritative. */
56
+ const DID_PATTERN = /^did:[a-z]+:.+/;
57
+ /** Slug grammar: ASCII letter then letters / digits / `-` / `_`. Mirrors the install route. */
58
+ const SLUG_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
59
+ /** Non-negative integer, for the screenshot index param. */
60
+ const INDEX_PATTERN = /^\d+$/;
61
+
62
+ /** Cap proxied images so a hostile host can't stream an unbounded body. */
63
+ const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
64
+
65
+ /** Redirect hops to follow, re-validating each target against SSRF rules. */
66
+ const MAX_REDIRECTS = 5;
67
+
68
+ /** Wall-clock budget covering connect + headers + body for the artifact fetch. */
69
+ const FETCH_TIMEOUT_MS = 15_000;
70
+
71
+ /** Per-aggregator-request timeout and overall budget for release resolution. */
72
+ const AGGREGATOR_REQUEST_TIMEOUT_MS = 15_000;
73
+ const AGGREGATOR_TOTAL_BUDGET_MS = 30_000;
74
+
75
+ /** Bound the version search: 20 pages * 50 per page = 1000 releases worth. */
76
+ const MAX_LIST_PAGES = 20;
77
+
78
+ /** Build a fetch that enforces a per-request and per-budget timeout. Mirrors the install handler. */
79
+ function timedFetch(totalDeadline: number): typeof fetch {
80
+ return (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {
81
+ const now = Date.now();
82
+ const remaining = Math.max(0, totalDeadline - now);
83
+ if (remaining === 0) {
84
+ return Promise.reject(new Error("Aggregator request budget exhausted"));
85
+ }
86
+ const timeout = Math.min(AGGREGATOR_REQUEST_TIMEOUT_MS, remaining);
87
+ const controller = new AbortController();
88
+ const timer = setTimeout(() => controller.abort(), timeout);
89
+ const callerSignal = init?.signal;
90
+ if (callerSignal) {
91
+ if (callerSignal.aborted) controller.abort(callerSignal.reason);
92
+ else callerSignal.addEventListener("abort", () => controller.abort(callerSignal.reason));
93
+ }
94
+ return fetch(input, { ...init, signal: controller.signal }).finally(() => {
95
+ clearTimeout(timer);
96
+ });
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Narrow one entry of a release's `artifacts` map to a usable image URL.
102
+ *
103
+ * The embedded `release` record is lexicon-validated at the DiscoveryClient
104
+ * boundary, but `artifacts` is an aggregator pass-through typed `unknown`, so
105
+ * the entry's shape is not guaranteed. Returns the `url` string only when the
106
+ * value is an object carrying a non-empty string `url`; everything else
107
+ * (missing key, wrong type, no `url`) yields `null`.
108
+ */
109
+ function declaredArtifactUrl(value: unknown): string | null {
110
+ if (!value || typeof value !== "object") return null;
111
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- narrowed to non-null object above; url checked below
112
+ const entry = value as Record<string, unknown>;
113
+ const url = entry.url;
114
+ if (typeof url !== "string" || url.length === 0) return null;
115
+ return url;
116
+ }
117
+
118
+ /**
119
+ * Resolve the declared artifact URL for `(kind, index)` from a release's
120
+ * `artifacts` map. Returns `null` when the requested artifact isn't present
121
+ * or doesn't carry a usable URL.
122
+ */
123
+ function resolveDeclaredUrl(artifacts: unknown, kind: string, index: number): string | null {
124
+ if (!artifacts || typeof artifacts !== "object") return null;
125
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- narrowed to non-null object above; each entry shape-narrowed by declaredArtifactUrl
126
+ const map = artifacts as Record<string, unknown>;
127
+
128
+ if (kind === "icon") return declaredArtifactUrl(map.icon);
129
+ if (kind === "banner") return declaredArtifactUrl(map.banner);
130
+ // kind === "screenshot"
131
+ const screenshots = map.screenshots;
132
+ if (!Array.isArray(screenshots)) return null;
133
+ if (index < 0 || index >= screenshots.length) return null;
134
+ return declaredArtifactUrl(screenshots[index]);
135
+ }
136
+
137
+ export const GET: APIRoute = async ({ url, locals }) => {
138
+ const { emdash, user } = locals;
139
+
140
+ if (!emdash?.db) {
141
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
142
+ }
143
+
144
+ const denied = requirePerm(user, "plugins:read");
145
+ if (denied) return denied;
146
+
147
+ const did = url.searchParams.get("did");
148
+ const slug = url.searchParams.get("slug");
149
+ const kind = url.searchParams.get("kind");
150
+ const versionParam = url.searchParams.get("version");
151
+ const indexParam = url.searchParams.get("index");
152
+
153
+ if (!did || !slug || !kind) {
154
+ return apiError("INVALID_REQUEST", "Missing did, slug, or kind", 400);
155
+ }
156
+ if (did.length > 256 || !DID_PATTERN.test(did)) {
157
+ return apiError("INVALID_REQUEST", "Invalid did", 400);
158
+ }
159
+ if (slug.length > 64 || !SLUG_PATTERN.test(slug)) {
160
+ return apiError("INVALID_REQUEST", "Invalid slug", 400);
161
+ }
162
+ if (!ALLOWED_KINDS.has(kind)) {
163
+ return apiError("INVALID_REQUEST", "Invalid kind", 400);
164
+ }
165
+
166
+ let index = 0;
167
+ if (kind === "screenshot") {
168
+ if (indexParam === null) {
169
+ return apiError("INVALID_REQUEST", "Missing index for screenshot", 400);
170
+ }
171
+ if (!INDEX_PATTERN.test(indexParam)) {
172
+ return apiError("INVALID_REQUEST", "Invalid index", 400);
173
+ }
174
+ index = Number(indexParam);
175
+ if (!Number.isSafeInteger(index)) {
176
+ return apiError("INVALID_REQUEST", "Invalid index", 400);
177
+ }
178
+ }
179
+
180
+ let version: string | undefined;
181
+ if (versionParam !== null && versionParam.length > 0) {
182
+ if (versionParam.length > 64) {
183
+ return apiError("INVALID_REQUEST", "Invalid version", 400);
184
+ }
185
+ version = versionParam;
186
+ }
187
+
188
+ const registryConfig = coerceRegistryConfig(emdash.config.experimental?.registry);
189
+ if (!registryConfig) {
190
+ return apiError("REGISTRY_NOT_CONFIGURED", "Registry is not configured", 400);
191
+ }
192
+ try {
193
+ validateAggregatorUrl(registryConfig.aggregatorUrl);
194
+ } catch {
195
+ return apiError("REGISTRY_NOT_CONFIGURED", "Registry aggregator URL is invalid", 500);
196
+ }
197
+
198
+ // Resolve the publisher-declared artifact URL from the release record.
199
+ let declaredUrl: string;
200
+ try {
201
+ const resolved = await resolveArtifactUrl(registryConfig, did, slug, version, kind, index);
202
+ if (resolved === null) {
203
+ return apiError("ARTIFACT_NOT_FOUND", "Artifact not found", 404);
204
+ }
205
+ declaredUrl = resolved;
206
+ } catch {
207
+ return apiError("ARTIFACT_RESOLVE_FAILED", "Failed to resolve artifact", 502);
208
+ }
209
+
210
+ const controller = new AbortController();
211
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
212
+ try {
213
+ // `assertSafeArtifactUrl` validates scheme / credentials / loopback +
214
+ // resolves the hostname and rejects private / link-local / metadata
215
+ // targets (DNS-rebinding defence). It throws a plain Error on any
216
+ // block, so a rejection here means the URL is unsafe.
217
+ let current: URL;
218
+ try {
219
+ current = await assertSafeArtifactUrl(declaredUrl);
220
+ } catch {
221
+ return apiError("ARTIFACT_URL_REJECTED", "Artifact URL is not allowed", 400);
222
+ }
223
+
224
+ let response: Response;
225
+ for (let hop = 0; ; hop++) {
226
+ response = await fetch(current.href, { redirect: "manual", signal: controller.signal });
227
+ if (response.status < 300 || response.status >= 400) break;
228
+ const location = response.headers.get("location");
229
+ if (!location) break;
230
+ if (hop === MAX_REDIRECTS) {
231
+ return apiError("ARTIFACT_URL_REJECTED", "Too many redirects", 502);
232
+ }
233
+ let next: URL;
234
+ try {
235
+ next = await assertSafeArtifactUrl(new URL(location, current).href);
236
+ } catch {
237
+ return apiError("ARTIFACT_URL_REJECTED", "Redirect target is not allowed", 400);
238
+ }
239
+ current = next;
240
+ }
241
+
242
+ if (!response.ok) {
243
+ return apiError("ARTIFACT_FETCH_FAILED", "Failed to fetch artifact", 502);
244
+ }
245
+
246
+ // Content-Type allowlist: only image types are proxied. A non-image
247
+ // (HTML error page, JSON, octet-stream) is rejected so the admin
248
+ // never renders publisher-controlled markup from the EmDash origin.
249
+ const rawType = response.headers.get("content-type") ?? "";
250
+ const contentType = rawType.split(";", 1)[0]!.trim().toLowerCase();
251
+ if (!ALLOWED_IMAGE_TYPES.has(contentType)) {
252
+ return apiError("ARTIFACT_NOT_IMAGE", "Artifact is not an allowed image type", 415);
253
+ }
254
+
255
+ const declaredLength = response.headers.get("content-length");
256
+ if (declaredLength) {
257
+ const declared = Number(declaredLength);
258
+ if (Number.isFinite(declared) && declared > MAX_IMAGE_BYTES) {
259
+ return apiError("ARTIFACT_TOO_LARGE", "Artifact exceeds size limit", 413);
260
+ }
261
+ }
262
+
263
+ const bytes = await readCapped(response, MAX_IMAGE_BYTES);
264
+ if (bytes === null) {
265
+ return apiError("ARTIFACT_TOO_LARGE", "Artifact exceeds size limit", 413);
266
+ }
267
+
268
+ // Only the allowlisted Content-Type is forwarded — never copy other
269
+ // upstream headers. `private, no-store` keeps publisher images out of
270
+ // shared caches in the authenticated admin origin.
271
+ //
272
+ // SVG is not in the allowlist, so active-content bytes never reach
273
+ // here. `Content-Disposition: attachment`, the sandbox CSP, and
274
+ // `nosniff` remain as defence-in-depth: they force a download and
275
+ // neutralise script/plugins for any image type if a client navigates
276
+ // directly to the proxy URL.
277
+ return new Response(bytes, {
278
+ headers: {
279
+ "Content-Type": contentType,
280
+ "Cache-Control": "private, no-store",
281
+ "X-Content-Type-Options": "nosniff",
282
+ "Content-Disposition": "attachment",
283
+ "Content-Security-Policy": "default-src 'none'; sandbox",
284
+ },
285
+ });
286
+ } catch {
287
+ return apiError("ARTIFACT_FETCH_FAILED", "Failed to fetch artifact", 502);
288
+ } finally {
289
+ clearTimeout(timer);
290
+ }
291
+ };
292
+
293
+ /**
294
+ * Resolve the declared artifact URL for `(did, slug, version, kind, index)`
295
+ * from the aggregator's release record. Mirrors the install handler's release
296
+ * lookup. Returns `null` when the package/release/artifact isn't found.
297
+ *
298
+ * Self-contained to this route: the install/update handlers are intentionally
299
+ * left untouched, so a small amount of resolution-pattern duplication is
300
+ * accepted here.
301
+ */
302
+ async function resolveArtifactUrl(
303
+ registryConfig: { aggregatorUrl: string; acceptLabelers?: string },
304
+ did: string,
305
+ slug: string,
306
+ version: string | undefined,
307
+ kind: string,
308
+ index: number,
309
+ ): Promise<string | null> {
310
+ // Lazy-load the discovery client so the `@atcute/client` dependency only
311
+ // loads when the registry path is exercised.
312
+ const { DiscoveryClient } = await import("@emdash-cms/registry-client/discovery");
313
+
314
+ const aggregatorDeadline = Date.now() + AGGREGATOR_TOTAL_BUDGET_MS;
315
+ const discovery = new DiscoveryClient({
316
+ aggregatorUrl: registryConfig.aggregatorUrl,
317
+ acceptLabelers: registryConfig.acceptLabelers,
318
+ fetch: timedFetch(aggregatorDeadline),
319
+ });
320
+
321
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- DID shape validated by the route before this call
322
+ const publisherDid = did as Did;
323
+
324
+ const releaseView = await (async () => {
325
+ if (!version) {
326
+ return discovery.getLatestRelease({ did: publisherDid, package: slug });
327
+ }
328
+ let cursor: string | undefined;
329
+ const seenCursors = new Set<string>();
330
+ for (let page = 0; page < MAX_LIST_PAGES; page++) {
331
+ if (cursor !== undefined) {
332
+ if (seenCursors.has(cursor)) break;
333
+ seenCursors.add(cursor);
334
+ }
335
+ const result = await discovery.listReleases({
336
+ did: publisherDid,
337
+ package: slug,
338
+ cursor,
339
+ limit: 50,
340
+ });
341
+ for (const r of result.releases) {
342
+ if (r.version === version) return r;
343
+ }
344
+ if (!result.cursor) break;
345
+ cursor = result.cursor;
346
+ }
347
+ return undefined;
348
+ })();
349
+
350
+ if (!releaseView?.release) return null;
351
+
352
+ return resolveDeclaredUrl(releaseView.release.artifacts, kind, index);
353
+ }
354
+
355
+ /**
356
+ * Read a response body into memory, aborting once it exceeds `limit`. Returns
357
+ * `null` when the cap is breached (the streamed body lied about / omitted
358
+ * Content-Length). The cap is the real defence against an unbounded body.
359
+ */
360
+ async function readCapped(response: Response, limit: number): Promise<Uint8Array | null> {
361
+ const body = response.body;
362
+ if (!body) {
363
+ const buf = new Uint8Array(await response.arrayBuffer());
364
+ return buf.length > limit ? null : buf;
365
+ }
366
+ const reader = body.getReader();
367
+ const chunks: Uint8Array[] = [];
368
+ let total = 0;
369
+ while (true) {
370
+ const { done, value } = await reader.read();
371
+ if (done) break;
372
+ if (value) {
373
+ total += value.length;
374
+ if (total > limit) {
375
+ await reader.cancel();
376
+ return null;
377
+ }
378
+ chunks.push(value);
379
+ }
380
+ }
381
+ const combined = new Uint8Array(total);
382
+ let offset = 0;
383
+ for (const chunk of chunks) {
384
+ combined.set(chunk, offset);
385
+ offset += chunk.length;
386
+ }
387
+ return combined;
388
+ }
@@ -12,6 +12,7 @@
12
12
  * view time (handle is best-effort per the lexicon).
13
13
  */
14
14
 
15
+ import { hostEnvFromVersions } from "@emdash-cms/registry-client/env";
15
16
  import type { APIRoute } from "astro";
16
17
  import { z } from "zod";
17
18
 
@@ -20,6 +21,8 @@ import { apiError, handleError, unwrapResult } from "#api/error.js";
20
21
  import { handleRegistryInstall } from "#api/index.js";
21
22
  import { isParseError, parseBody } from "#api/parse.js";
22
23
 
24
+ import { VERSION } from "../../../../../../version.js";
25
+
23
26
  export const prerender = false;
24
27
 
25
28
  const installBodySchema = z.object({
@@ -91,7 +94,10 @@ export const POST: APIRoute = async ({ request, locals }) => {
91
94
  version: body.version,
92
95
  acknowledgedDeclaredAccess: body.acknowledgedDeclaredAccess,
93
96
  },
94
- { configuredPluginIds: reservedPluginIds },
97
+ {
98
+ configuredPluginIds: reservedPluginIds,
99
+ hostEnv: hostEnvFromVersions(VERSION, emdash.config.astroVersion),
100
+ },
95
101
  );
96
102
 
97
103
  if (!result.success) return unwrapResult(result);
@@ -1,14 +1,22 @@
1
1
  /**
2
- * Marketplace update check endpoint
2
+ * Plugin update check endpoint
3
3
  *
4
- * GET /_emdash/api/admin/plugins/updates - Check for marketplace plugin updates
4
+ * GET /_emdash/api/admin/plugins/updates - Check for available updates
5
+ * across every installed plugin source (marketplace + experimental
6
+ * registry). Items are returned in a single flat list; admins correlate
7
+ * items to plugins by `pluginId` and read `source` from the existing
8
+ * `/_emdash/api/admin/plugins` list (the pluginId prefix is not a
9
+ * reliable discriminator on its own).
10
+ *
11
+ * A failure in one source does NOT blank the other — a registry-side
12
+ * aggregator outage still returns marketplace updates and vice versa.
5
13
  */
6
14
 
7
15
  import type { APIRoute } from "astro";
8
16
 
9
17
  import { requirePerm } from "#api/authorize.js";
10
- import { apiError, unwrapResult } from "#api/error.js";
11
- import { handleMarketplaceUpdateCheck } from "#api/index.js";
18
+ import { apiError } from "#api/error.js";
19
+ import { handleMarketplaceUpdateCheck, handleRegistryUpdateCheck } from "#api/index.js";
12
20
 
13
21
  export const prerender = false;
14
22
 
@@ -22,7 +30,36 @@ export const GET: APIRoute = async ({ locals }) => {
22
30
  const denied = requirePerm(user, "plugins:read");
23
31
  if (denied) return denied;
24
32
 
25
- const result = await handleMarketplaceUpdateCheck(emdash.db, emdash.config.marketplace);
33
+ // Run both checks in parallel. Catch each independently so one source's
34
+ // failure doesn't blank the other. Both throws and structured `success:
35
+ // false` returns are logged with the source name so a misconfigured
36
+ // registry doesn't disappear silently from telemetry.
37
+ const [marketplace, registry] = await Promise.all([
38
+ handleMarketplaceUpdateCheck(emdash.db, emdash.config.marketplace).catch((err) => {
39
+ console.warn("[plugins/updates] marketplace check threw:", err);
40
+ return null;
41
+ }),
42
+ handleRegistryUpdateCheck(emdash.db, emdash.config.experimental?.registry).catch((err) => {
43
+ console.warn("[plugins/updates] registry check threw:", err);
44
+ return null;
45
+ }),
46
+ ]);
47
+ if (marketplace && !marketplace.success) {
48
+ console.warn(
49
+ `[plugins/updates] marketplace check failed: ${marketplace.error.code} ${marketplace.error.message}`,
50
+ );
51
+ }
52
+ if (registry && !registry.success) {
53
+ console.warn(
54
+ `[plugins/updates] registry check failed: ${registry.error.code} ${registry.error.message}`,
55
+ );
56
+ }
57
+
58
+ const items: unknown[] = [];
59
+ if (marketplace?.success) items.push(...marketplace.data.items);
60
+ if (registry?.success) items.push(...registry.data.items);
26
61
 
27
- return unwrapResult(result);
62
+ // Match the rest of the admin API envelope (`{ data: ... }`) so the
63
+ // admin client's `parseApiResponse` unwraps `body.data`.
64
+ return Response.json({ data: { items } });
28
65
  };
@@ -28,7 +28,7 @@ export const GET: APIRoute = async ({ url, locals }) => {
28
28
  const validSorts = new Set(["name", "created", "updated"]);
29
29
  let sort: "name" | "created" | "updated" | undefined;
30
30
  if (sortParam && validSorts.has(sortParam)) {
31
- sort = sortParam as "name" | "created" | "updated"; // eslint-disable-line typescript-eslint(no-unsafe-type-assertion) -- validated by Set.has()
31
+ sort = sortParam as "name" | "created" | "updated"; // eslint-disable-line typescript/no-unsafe-type-assertion -- validated by Set.has()
32
32
  }
33
33
  const cursor = url.searchParams.get("cursor") ?? undefined;
34
34
  const limitParam = url.searchParams.get("limit");
@@ -116,9 +116,9 @@ export const GET: APIRoute = async ({ params, request, locals, session, redirect
116
116
 
117
117
  try {
118
118
  // Get OAuth providers from environment
119
- // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- locals.runtime is injected by the Cloudflare adapter at runtime; not declared on App.Locals since the adapter is optional
119
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- locals.runtime is injected by the Cloudflare adapter at runtime; not declared on App.Locals since the adapter is optional
120
120
  const runtimeLocals = locals as unknown as { runtime?: { env?: Record<string, unknown> } };
121
- // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- import.meta.env is typed as ImportMetaEnv but we need Record<string, unknown> for getOAuthConfig
121
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- import.meta.env is typed as ImportMetaEnv but we need Record<string, unknown> for getOAuthConfig
122
122
  const env = runtimeLocals.runtime?.env ?? (import.meta.env as Record<string, unknown>);
123
123
  const providers = getOAuthConfig(env);
124
124
 
@@ -95,9 +95,9 @@ export const GET: APIRoute = async ({ params, request, locals, redirect }) => {
95
95
 
96
96
  // Get OAuth providers from environment
97
97
  // Access via locals.runtime for Cloudflare, or import.meta.env for Node
98
- // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- locals.runtime is injected by the Cloudflare adapter at runtime; not declared on App.Locals since the adapter is optional
98
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- locals.runtime is injected by the Cloudflare adapter at runtime; not declared on App.Locals since the adapter is optional
99
99
  const runtimeLocals = locals as unknown as { runtime?: { env?: Record<string, unknown> } };
100
- // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- import.meta.env is typed as ImportMetaEnv but we need Record<string, unknown> for getOAuthConfig
100
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- import.meta.env is typed as ImportMetaEnv but we need Record<string, unknown> for getOAuthConfig
101
101
  const env = runtimeLocals.runtime?.env ?? (import.meta.env as Record<string, unknown>);
102
102
  const providers = getOAuthConfig(env);
103
103
 
@@ -31,13 +31,13 @@ export const POST: APIRoute = async ({ params, locals, cache }) => {
31
31
  }
32
32
  const existingData =
33
33
  existing.data && typeof existing.data === "object"
34
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
34
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check above
35
35
  (existing.data as Record<string, unknown>)
36
36
  : undefined;
37
37
  // Handler returns { item, _rev } — extract the item for ownership check
38
38
  const existingItem =
39
39
  existingData?.item && typeof existingData.item === "object"
40
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
40
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check above
41
41
  (existingData.item as Record<string, unknown>)
42
42
  : existingData;
43
43
  const authorId = typeof existingItem?.authorId === "string" ? existingItem.authorId : "";
@@ -35,13 +35,13 @@ export const POST: APIRoute = async ({ params, locals, cache }) => {
35
35
 
36
36
  const existingData =
37
37
  existing.data && typeof existing.data === "object"
38
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
38
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check above
39
39
  (existing.data as Record<string, unknown>)
40
40
  : undefined;
41
41
  // Handler returns { item, _rev } — extract the item for ownership check
42
42
  const existingItem =
43
43
  existingData?.item && typeof existingData.item === "object"
44
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
44
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check above
45
45
  (existingData.item as Record<string, unknown>)
46
46
  : existingData;
47
47
  const authorId = typeof existingItem?.authorId === "string" ? existingItem.authorId : "";
@@ -46,12 +46,12 @@ export const POST: APIRoute = async ({ params, request, locals, cache }) => {
46
46
 
47
47
  const existingData =
48
48
  existing.data && typeof existing.data === "object"
49
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
49
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check above
50
50
  (existing.data as Record<string, unknown>)
51
51
  : undefined;
52
52
  const existingItem =
53
53
  existingData?.item && typeof existingData.item === "object"
54
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
54
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check above
55
55
  (existingData.item as Record<string, unknown>)
56
56
  : existingData;
57
57
  const authorId = typeof existingItem?.authorId === "string" ? existingItem.authorId : "";
@@ -31,13 +31,13 @@ export const POST: APIRoute = async ({ params, locals, cache }) => {
31
31
  }
32
32
  const existingData =
33
33
  existing.data && typeof existing.data === "object"
34
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
34
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check above
35
35
  (existing.data as Record<string, unknown>)
36
36
  : undefined;
37
37
  // Handler returns { item, _rev } — extract the item for ownership check
38
38
  const existingItem =
39
39
  existingData?.item && typeof existingData.item === "object"
40
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
40
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check above
41
41
  (existingData.item as Record<string, unknown>)
42
42
  : existingData;
43
43
  const authorId = typeof existingItem?.authorId === "string" ? existingItem.authorId : "";
@@ -20,12 +20,12 @@ export const prerender = false;
20
20
  function extractOwnership(data: unknown): { authorId: string; resolvedId: string | undefined } {
21
21
  const obj =
22
22
  data && typeof data === "object"
23
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown; narrowed by typeof
23
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown; narrowed by typeof
24
24
  (data as Record<string, unknown>)
25
25
  : undefined;
26
26
  const item =
27
27
  obj?.item && typeof obj.item === "object"
28
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof
28
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof
29
29
  (obj.item as Record<string, unknown>)
30
30
  : obj;
31
31
  return {
@@ -34,7 +34,7 @@ export const GET: APIRoute = async ({ params, locals }) => {
34
34
  if (dbErr) return dbErr;
35
35
 
36
36
  try {
37
- const repo = new TaxonomyRepository(emdash!.db);
37
+ const repo = new TaxonomyRepository(emdash.db);
38
38
  const terms = await repo.getTermsForEntry(collection, id, taxonomy);
39
39
 
40
40
  return apiSuccess({
@@ -68,12 +68,12 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
68
68
  const dbErr = requireDb(emdash?.db);
69
69
  if (dbErr) return dbErr;
70
70
 
71
- if (!emdash!.handleContentGet) {
71
+ if (!emdash.handleContentGet) {
72
72
  return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
73
73
  }
74
74
 
75
75
  // Verify the content exists before modifying its terms
76
- const existing = await emdash!.handleContentGet(collection, id);
76
+ const existing = await emdash.handleContentGet(collection, id);
77
77
  if (!existing.success) {
78
78
  return apiError(
79
79
  existing.error?.code ?? "NOT_FOUND",
@@ -85,13 +85,13 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
85
85
  // Check ownership for edit permission
86
86
  const existingData =
87
87
  existing.data && typeof existing.data === "object"
88
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
88
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check above
89
89
  (existing.data as Record<string, unknown>)
90
90
  : undefined;
91
91
  // Handler returns { item, _rev } — extract the item for ownership check
92
92
  const existingItem =
93
93
  existingData?.item && typeof existingData.item === "object"
94
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
94
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check above
95
95
  (existingData.item as Record<string, unknown>)
96
96
  : existingData;
97
97
  const authorId = typeof existingItem?.authorId === "string" ? existingItem.authorId : "";
@@ -107,7 +107,7 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
107
107
  if (isParseError(body)) return body;
108
108
  const { termIds } = body;
109
109
 
110
- const repo = new TaxonomyRepository(emdash!.db);
110
+ const repo = new TaxonomyRepository(emdash.db);
111
111
 
112
112
  // Verify all term IDs exist and belong to the correct taxonomy
113
113
  for (const termId of termIds) {
@@ -41,7 +41,7 @@ export const GET: APIRoute = async ({ params, locals }) => {
41
41
  if (result.success && !hasPermission(user, "content:read_drafts")) {
42
42
  const data =
43
43
  result.data && typeof result.data === "object"
44
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check
44
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check
45
45
  (result.data as Record<string, unknown>)
46
46
  : undefined;
47
47
  const translations = Array.isArray(data?.translations) ? data.translations : [];