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
@@ -35,3 +35,155 @@ export function resolveLocaleChain(explicit?: string): string[] {
35
35
  if (!isI18nEnabled()) return [locale];
36
36
  return getFallbackChain(locale);
37
37
  }
38
+
39
+ const REPEATED_SLASHES = /\/{2,}/g;
40
+
41
+ /**
42
+ * Interpolate a collection `url_pattern` with a row's slug and id.
43
+ *
44
+ * Falls back to `/{collection}/{slug}` when no pattern is configured.
45
+ * Does NOT apply any locale prefix — pass the result through
46
+ * Astro's `getRelativeLocaleUrl` / `getAbsoluteLocaleUrl` (or the
47
+ * `localizePath` helper below) to add the locale segment.
48
+ */
49
+ export function interpolateUrlPattern(options: {
50
+ pattern: string | null;
51
+ collection: string;
52
+ slug: string;
53
+ id: string;
54
+ }): string {
55
+ const { pattern, collection, slug, id } = options;
56
+ const basePattern = pattern ?? `/${encodeURIComponent(collection)}/{slug}`;
57
+ let path = basePattern
58
+ .replace("{slug}", encodeURIComponent(slug))
59
+ .replace("{id}", encodeURIComponent(id));
60
+ path = path.replace(REPEATED_SLASHES, "/");
61
+ if (path.length > 1 && path.endsWith("/")) path = path.slice(0, -1);
62
+ if (!path.startsWith("/")) path = `/${path}`;
63
+ return path;
64
+ }
65
+
66
+ /**
67
+ * Apply a locale prefix to a path, honouring the user's Astro `i18n`
68
+ * routing config (`prefixDefaultLocale`, custom `path`/`codes` mappings).
69
+ *
70
+ * Reads the resolved config from `astro:config/server`, which is always
71
+ * available regardless of whether i18n is enabled -- so this function
72
+ * works in both i18n and non-i18n builds without tripping Astro's
73
+ * `i18nNotEnabled` resolver (the case with importing `astro:i18n`).
74
+ *
75
+ * Returns:
76
+ * - The original `path` when i18n is not configured.
77
+ * - The original `path` for the default locale when
78
+ * `prefixDefaultLocale` is false.
79
+ * - `/{segment}{path}` for any other configured locale, where
80
+ * `{segment}` is the locale's custom `path` if one is set,
81
+ * otherwise the locale code.
82
+ * - `null` when the row's locale isn't in the configured list.
83
+ * Callers should drop the entry: a sitemap link to a route the
84
+ * site can't serve is worse than no link at all (search engines
85
+ * get a 404 / soft-404 and downrank the page).
86
+ *
87
+ * Falls back to `getI18nConfig()` (EmDash's mirror of the same config,
88
+ * populated at runtime startup) when `astro:config/server` is
89
+ * unavailable -- e.g. running outside an Astro build context, such as
90
+ * in vitest.
91
+ */
92
+ export async function localizePath(path: string, locale: string): Promise<string | null> {
93
+ const segment = await resolveLocaleSegment(locale);
94
+ if (segment === undefined) return null;
95
+ if (segment === null || segment === "") return normalizePath(path);
96
+ return normalizePath(`/${segment}${path}`);
97
+ }
98
+
99
+ /**
100
+ * Resolve the URL segment to use for a locale.
101
+ *
102
+ * Returns:
103
+ * - `null` when i18n isn't configured (caller should not prefix).
104
+ * - `""` when the locale is the default locale and
105
+ * `prefixDefaultLocale` is false (caller should not prefix).
106
+ * - The locale's custom `path` value, or the locale string itself.
107
+ * - `undefined` when the locale isn't in the configured list --
108
+ * the row points at a route the site can't serve.
109
+ */
110
+ async function resolveLocaleSegment(locale: string): Promise<string | null | undefined> {
111
+ const i18n = await readAstroI18nConfig();
112
+ if (!i18n || !i18n.locales || i18n.locales.length <= 1) return null;
113
+
114
+ const isDefault = locale === i18n.defaultLocale;
115
+ if (isDefault && !i18n.prefixDefaultLocale) return "";
116
+
117
+ // When the locale has a custom `path`/`codes` mapping, use the path
118
+ // for the URL segment. Otherwise use the locale code directly.
119
+ for (const entry of i18n.locales) {
120
+ if (typeof entry === "string") {
121
+ if (entry === locale) return entry;
122
+ } else if (entry.codes.includes(locale)) {
123
+ return entry.path;
124
+ }
125
+ }
126
+
127
+ return undefined;
128
+ }
129
+
130
+ interface AstroI18nConfig {
131
+ defaultLocale: string;
132
+ locales: Array<string | { codes: readonly string[]; path: string }>;
133
+ prefixDefaultLocale?: boolean;
134
+ }
135
+
136
+ let astroI18nCache: AstroI18nConfig | null | undefined;
137
+
138
+ async function readAstroI18nConfig(): Promise<AstroI18nConfig | null> {
139
+ if (astroI18nCache !== undefined) return astroI18nCache;
140
+
141
+ try {
142
+ const mod = (await import("astro:config/server")) as {
143
+ i18n?: {
144
+ defaultLocale: string;
145
+ locales: Array<string | { codes: readonly string[]; path: string }>;
146
+ routing?: { prefixDefaultLocale?: boolean } | string;
147
+ };
148
+ };
149
+ if (!mod.i18n) {
150
+ astroI18nCache = null;
151
+ return null;
152
+ }
153
+ const routing = mod.i18n.routing;
154
+ astroI18nCache = {
155
+ defaultLocale: mod.i18n.defaultLocale,
156
+ locales: mod.i18n.locales,
157
+ prefixDefaultLocale:
158
+ typeof routing === "object" ? (routing.prefixDefaultLocale ?? false) : false,
159
+ };
160
+ return astroI18nCache;
161
+ } catch {
162
+ // `astro:config/server` isn't resolvable (e.g. running under vitest
163
+ // outside an Astro build). Fall back to EmDash's runtime config,
164
+ // which is populated at startup via the same astroConfig object.
165
+ const cfg = getI18nConfig();
166
+ if (!cfg || !isI18nEnabled()) {
167
+ astroI18nCache = null;
168
+ return null;
169
+ }
170
+ astroI18nCache = {
171
+ defaultLocale: cfg.defaultLocale,
172
+ locales: cfg.locales,
173
+ prefixDefaultLocale: cfg.prefixDefaultLocale,
174
+ };
175
+ return astroI18nCache;
176
+ }
177
+ }
178
+
179
+ /** @internal -- exposed for tests to reset the module-level cache. */
180
+ export function _resetAstroI18nCacheForTests(): void {
181
+ astroI18nCache = undefined;
182
+ }
183
+
184
+ function normalizePath(path: string): string {
185
+ let p = path.replace(REPEATED_SLASHES, "/");
186
+ if (p.length > 1 && p.endsWith("/")) p = p.slice(0, -1);
187
+ if (!p.startsWith("/")) p = `/${p}`;
188
+ return p;
189
+ }
package/src/index.ts CHANGED
@@ -12,6 +12,9 @@ export type {
12
12
  export {
13
13
  ContentRepository,
14
14
  MediaRepository,
15
+ PluginStorageRepository,
16
+ UserRepository,
17
+ OptionsRepository,
15
18
  EmDashValidationError,
16
19
  InvalidCursorError,
17
20
  } from "./database/repositories/index.js";
@@ -125,6 +128,8 @@ export type {
125
128
  ResolvePathResult,
126
129
  TranslationSummary,
127
130
  TranslationsResult,
131
+ WhereRange,
132
+ WhereValue,
128
133
  } from "./query.js";
129
134
 
130
135
  // Request context (ALS-based ambient state for query functions)
@@ -198,7 +203,11 @@ export {
198
203
  // Sandbox
199
204
  NoopSandboxRunner,
200
205
  SandboxNotAvailableError,
206
+ SandboxUnavailableError,
201
207
  createNoopSandboxRunner,
208
+ // HTTP access for plugins (shared between in-process, Cloudflare, and workerd runners)
209
+ createHttpAccess,
210
+ createUnrestrictedHttpAccess,
202
211
  } from "./plugins/index.js";
203
212
  export type {
204
213
  PluginDefinition,
package/src/loader.ts CHANGED
@@ -20,7 +20,7 @@ import { decodeCursor, encodeCursor } from "./database/repositories/types.js";
20
20
  import { validateIdentifier } from "./database/validate.js";
21
21
  import type { Database } from "./index.js";
22
22
  import { getRequestContext } from "./request-context.js";
23
- import { isMissingTableError } from "./utils/db-errors.js";
23
+ import { isMissingColumnError, isMissingTableError } from "./utils/db-errors.js";
24
24
 
25
25
  const FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
26
26
 
@@ -311,10 +311,12 @@ function buildStatusCondition(
311
311
  const scheduledAtExpr = isPostgres(db)
312
312
  ? sql`${sql.ref(scheduledAtField)}::timestamptz`
313
313
  : sql.ref(scheduledAtField);
314
- return sql`(${sql.ref(statusField)} = 'published' OR (${sql.ref(statusField)} = 'scheduled' AND ${scheduledAtExpr} <= ${currentTimestampValue(db)}))`;
314
+ const nowExpr = isPostgres(db)
315
+ ? currentTimestampValue(db)
316
+ : sql`strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
317
+ return sql`(${sql.ref(statusField)} = 'published' OR (${sql.ref(statusField)} = 'scheduled' AND ${scheduledAtExpr} <= ${nowExpr}))`;
315
318
  }
316
319
 
317
- // For other statuses (draft, archived), just match exactly
318
320
  return sql`${sql.ref(statusField)} = ${status}`;
319
321
  }
320
322
 
@@ -408,6 +410,65 @@ function buildCursorCondition(
408
410
  return sql`(${sql.ref(primary.field)} > ${orderValue} OR (${sql.ref(primary.field)} = ${orderValue} AND ${sql.ref(idField)} > ${cursorId}))`;
409
411
  }
410
412
 
413
+ /** Type guard: is the where value a range object (not a string or array)? */
414
+ function isWhereRange(value: WhereValue): value is WhereRange {
415
+ return value !== null && typeof value === "object" && !Array.isArray(value);
416
+ }
417
+
418
+ /**
419
+ * Build AND conditions for non-taxonomy field filters.
420
+ * Returns an array of sql fragments; empty if no field filters apply.
421
+ * Field names are validated against FIELD_NAME_PATTERN to prevent injection.
422
+ */
423
+ function buildFieldConditions(
424
+ fields: Record<string, WhereValue>,
425
+ tablePrefix?: string,
426
+ ): ReturnType<typeof sql>[] {
427
+ const conditions: ReturnType<typeof sql>[] = [];
428
+
429
+ for (const [key, value] of Object.entries(fields)) {
430
+ if (!FIELD_NAME_PATTERN.test(key)) {
431
+ console.warn(`[emdash] where filter: invalid field name "${key}" ignored`);
432
+ continue;
433
+ }
434
+ if (value == null) continue;
435
+ const ref = tablePrefix ? sql.ref(`${tablePrefix}.${key}`) : sql.ref(key);
436
+
437
+ if (isWhereRange(value)) {
438
+ if (value.gt !== undefined) conditions.push(sql`${ref} > ${value.gt}`);
439
+ if (value.gte !== undefined) conditions.push(sql`${ref} >= ${value.gte}`);
440
+ if (value.lt !== undefined) conditions.push(sql`${ref} < ${value.lt}`);
441
+ if (value.lte !== undefined) conditions.push(sql`${ref} <= ${value.lte}`);
442
+ } else if (Array.isArray(value)) {
443
+ if (value.length > 0) {
444
+ conditions.push(sql`${ref} IN (${sql.join(value.map((v) => sql`${v}`))})`);
445
+ }
446
+ } else {
447
+ conditions.push(sql`${ref} = ${value}`);
448
+ }
449
+ }
450
+
451
+ return conditions;
452
+ }
453
+
454
+ /**
455
+ * Range filter for comparison operators on field values.
456
+ * Values are compared as strings in the database. This works correctly for
457
+ * ISO 8601 dates (e.g. "2024-01-01T00:00:00Z") because lexicographic ordering
458
+ * matches chronological ordering. Ensure date values use a consistent format.
459
+ */
460
+ export interface WhereRange {
461
+ gt?: string;
462
+ gte?: string;
463
+ lt?: string;
464
+ lte?: string;
465
+ }
466
+
467
+ /**
468
+ * A where clause value: exact match, multi-value match, or range comparison.
469
+ */
470
+ export type WhereValue = string | string[] | WhereRange;
471
+
411
472
  /**
412
473
  * Filter for loadCollection - type is required
413
474
  */
@@ -421,9 +482,16 @@ export interface CollectionFilter {
421
482
  */
422
483
  cursor?: string;
423
484
  /**
424
- * Filter by field values or taxonomy terms
485
+ * Filter by field values, taxonomy terms, or ranges.
486
+ *
487
+ * Taxonomy names are detected automatically and filtered via JOIN.
488
+ * Other keys are treated as column filters on the content table.
489
+ *
490
+ * @example { category: 'news' } - taxonomy term
491
+ * @example { series: 'main' } - exact match on a content field
492
+ * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - date range
425
493
  */
426
- where?: Record<string, string | string[]>;
494
+ where?: Record<string, WhereValue>;
427
495
  /**
428
496
  * Order results by field(s)
429
497
  * @default { created_at: "desc" }
@@ -471,7 +539,7 @@ export async function getDb(): Promise<Kysely<Database>> {
471
539
  // Per-request DB override via ALS (normal mode)
472
540
  const ctx = getRequestContext();
473
541
  if (ctx?.db) {
474
- return ctx.db as Kysely<Database>; // eslint-disable-line typescript-eslint(no-unsafe-type-assertion) -- db is typed as unknown in RequestContext to avoid circular deps
542
+ return ctx.db as Kysely<Database>; // eslint-disable-line typescript/no-unsafe-type-assertion -- db is typed as unknown in RequestContext to avoid circular deps
475
543
  }
476
544
 
477
545
  if (!dbInstance) {
@@ -551,79 +619,81 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
551
619
  ? buildCursorCondition(cursor, orderBy, tableName)
552
620
  : null;
553
621
 
554
- // Check if we need taxonomy filtering
622
+ // Separate taxonomy filters from field filters
555
623
  let result: { rows: Record<string, unknown>[] };
624
+ let taxonomyFilter: { name: string; slugs: string[] } | null = null;
625
+ const fieldFilters: Record<string, WhereValue> = {};
556
626
 
557
627
  if (where && Object.keys(where).length > 0) {
558
- // Get taxonomy names to detect taxonomy filters
559
628
  const taxNames = await getTaxonomyNames(db);
560
- const taxonomyFilters: Record<string, string | string[]> = {};
561
629
 
562
630
  for (const [key, value] of Object.entries(where)) {
631
+ if (value == null) continue;
563
632
  if (taxNames.has(key)) {
564
- taxonomyFilters[key] = value;
633
+ if (isWhereRange(value)) {
634
+ console.warn(
635
+ `[emdash] where filter: range operators are not supported on taxonomy "${key}", ignored`,
636
+ );
637
+ continue;
638
+ }
639
+ if (taxonomyFilter) {
640
+ console.warn(
641
+ `[emdash] where filter: only one taxonomy is supported per query, "${key}" ignored`,
642
+ );
643
+ continue;
644
+ }
645
+ const slugs = Array.isArray(value) ? value : [value];
646
+ taxonomyFilter = { name: key, slugs };
647
+ } else {
648
+ fieldFilters[key] = value;
565
649
  }
566
650
  }
651
+ }
567
652
 
568
- // If we have taxonomy filters, use JOIN
569
- if (Object.keys(taxonomyFilters).length > 0) {
570
- // Build query with taxonomy JOIN
571
- // For now, support single taxonomy filter (can extend later for multiple)
572
- const [taxName, termSlugs] = Object.entries(taxonomyFilters)[0];
573
- const slugs = Array.isArray(termSlugs) ? termSlugs : [termSlugs];
574
- const orderByClause = buildOrderByClause(orderBy, tableName);
575
-
576
- const statusCondition = buildStatusCondition(db, status, tableName);
577
- const localeCondition = locale
578
- ? sql`AND ${sql.ref(tableName)}.locale = ${locale}`
579
- : sql``;
580
- const cursorCond = cursorConditionPrefixed
581
- ? sql`AND ${cursorConditionPrefixed}`
582
- : sql``;
583
- result = await sql<Record<string, unknown>>`
584
- SELECT DISTINCT ${sql.ref(tableName)}.* FROM ${sql.ref(tableName)}
585
- INNER JOIN content_taxonomies ct
586
- ON ct.collection = ${type}
587
- AND ct.entry_id = ${sql.ref(tableName)}.id
588
- INNER JOIN taxonomies t
589
- ON t.id = ct.taxonomy_id
590
- WHERE ${sql.ref(tableName)}.deleted_at IS NULL
591
- AND ${statusCondition}
592
- ${localeCondition}
593
- ${cursorCond}
594
- AND t.name = ${taxName}
595
- AND t.slug IN (${sql.join(slugs.map((s) => sql`${s}`))})
596
- ${orderByClause}
597
- ${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}
598
- `.execute(db);
599
- } else {
600
- // No taxonomy filters, use simple query
601
- const orderByClause = buildOrderByClause(orderBy);
602
- const statusCondition = buildStatusCondition(db, status);
603
- const localeFilter = locale ? sql`AND locale = ${locale}` : sql``;
604
- const cursorCond = cursorCondition ? sql`AND ${cursorCondition}` : sql``;
605
- result = await sql<Record<string, unknown>>`
606
- SELECT * FROM ${sql.ref(tableName)}
607
- WHERE deleted_at IS NULL
653
+ if (taxonomyFilter) {
654
+ const orderByClause = buildOrderByClause(orderBy, tableName);
655
+ const statusCondition = buildStatusCondition(db, status, tableName);
656
+ const localeCondition = locale
657
+ ? sql`AND ${sql.ref(tableName)}.locale = ${locale}`
658
+ : sql``;
659
+ const cursorCond = cursorConditionPrefixed ? sql`AND ${cursorConditionPrefixed}` : sql``;
660
+ const fieldConds = buildFieldConditions(fieldFilters, tableName);
661
+ const fieldCondsSQL =
662
+ fieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;
663
+
664
+ result = await sql<Record<string, unknown>>`
665
+ SELECT DISTINCT ${sql.ref(tableName)}.* FROM ${sql.ref(tableName)}
666
+ INNER JOIN content_taxonomies ct
667
+ ON ct.collection = ${type}
668
+ AND ct.entry_id = ${sql.ref(tableName)}.id
669
+ INNER JOIN taxonomies t
670
+ ON t.id = ct.taxonomy_id
671
+ WHERE ${sql.ref(tableName)}.deleted_at IS NULL
608
672
  AND ${statusCondition}
609
- ${localeFilter}
673
+ ${localeCondition}
610
674
  ${cursorCond}
611
- ${orderByClause}
612
- ${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}
613
- `.execute(db);
614
- }
675
+ AND t.name = ${taxonomyFilter.name}
676
+ AND t.slug IN (${sql.join(taxonomyFilter.slugs.map((s) => sql`${s}`))})
677
+ ${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}
678
+ ${orderByClause}
679
+ ${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}
680
+ `.execute(db);
615
681
  } else {
616
- // No where clause, use simple query
617
682
  const orderByClause = buildOrderByClause(orderBy);
618
683
  const statusCondition = buildStatusCondition(db, status);
619
684
  const localeFilter = locale ? sql`AND locale = ${locale}` : sql``;
620
685
  const cursorCond = cursorCondition ? sql`AND ${cursorCondition}` : sql``;
686
+ const fieldConds = buildFieldConditions(fieldFilters);
687
+ const fieldCondsSQL =
688
+ fieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;
689
+
621
690
  result = await sql<Record<string, unknown>>`
622
691
  SELECT * FROM ${sql.ref(tableName)}
623
692
  WHERE deleted_at IS NULL
624
693
  AND ${statusCondition}
625
694
  ${localeFilter}
626
695
  ${cursorCond}
696
+ ${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}
627
697
  ${orderByClause}
628
698
  ${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}
629
699
  `.execute(db);
@@ -693,13 +763,17 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
693
763
  },
694
764
  };
695
765
  } catch (error) {
696
- // Handle missing table gracefully - return empty collection.
697
- // This happens before migrations have run.
698
- if (isMissingTableError(error)) {
766
+ // Handle missing table/column gracefully - return empty collection.
767
+ // Missing table happens before migrations have run.
768
+ // Missing column happens when a where filter references a non-existent field.
769
+ const message = error instanceof Error ? error.message : String(error);
770
+ if (isMissingTableError(error) || isMissingColumnError(error)) {
771
+ if (isMissingColumnError(error)) {
772
+ console.warn(`[emdash] where filter: ${message}`);
773
+ }
699
774
  return { entries: [] };
700
775
  }
701
776
 
702
- const message = error instanceof Error ? error.message : String(error);
703
777
  return {
704
778
  error: new Error(`Failed to load collection: ${message}`),
705
779
  };
package/src/mcp/server.ts CHANGED
@@ -511,12 +511,12 @@ export function createMcpServer(): McpServer {
511
511
  if (result.success && !canReadDrafts(extra)) {
512
512
  const data =
513
513
  result.data && typeof result.data === "object"
514
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check
514
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check
515
515
  (result.data as Record<string, unknown>)
516
516
  : undefined;
517
517
  const item =
518
518
  data?.item && typeof data.item === "object"
519
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check
519
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check
520
520
  (data.item as Record<string, unknown>)
521
521
  : undefined;
522
522
  const status = typeof item?.status === "string" ? item.status : null;
@@ -1140,7 +1140,7 @@ export function createMcpServer(): McpServer {
1140
1140
  if (result.success && !canReadDrafts(extra)) {
1141
1141
  const data =
1142
1142
  result.data && typeof result.data === "object"
1143
- ? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check
1143
+ ? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- handler returns unknown data; narrowed by typeof check
1144
1144
  (result.data as Record<string, unknown>)
1145
1145
  : undefined;
1146
1146
  const translations = Array.isArray(data?.translations) ? data.translations : [];
package/src/media/mime.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export function normalizeMime(mime: string): string {
2
- return mime.split(";")[0]!.trim().toLowerCase();
2
+ return mime.split(";")[0].trim().toLowerCase();
3
3
  }
4
4
 
5
5
  export function matchesMimeAllowlist(mime: string, allowList: readonly string[]): boolean {
@@ -44,7 +44,7 @@ const OTHER_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
44
44
  * exploitable, plus more pathological shapes like leading newlines that
45
45
  * could inject across header boundaries downstream.
46
46
  */
47
- // eslint-disable-next-line eslint(no-control-regex) -- intentional: rejecting control chars is the whole point of this regex
47
+ // eslint-disable-next-line no-control-regex -- intentional: rejecting control chars is the whole point of this regex
48
48
  const WHITESPACE_OR_CONTROL_RE = /[\s\u0000-\u001f\u007f-\u009f]/;
49
49
  const TRAILING_SLASH_RE = /\/$/;
50
50
 
@@ -8,6 +8,16 @@
8
8
  * Import as: `import { apiFetch, parseApiResponse, isRecord } from "emdash/plugin-utils";`
9
9
  */
10
10
 
11
+ import type { EmDashHandlers } from "./astro/types.js";
12
+
13
+ export type PublicPluginApiRouteHandler = EmDashHandlers["handlePublicPluginApiRoute"];
14
+
15
+ export interface PublicPluginRuntimeLocals {
16
+ emdash?: {
17
+ handlePublicPluginApiRoute?: PublicPluginApiRouteHandler;
18
+ };
19
+ }
20
+
11
21
  /**
12
22
  * Fetch wrapper that adds the `X-EmDash-Request` CSRF protection header.
13
23
  *
@@ -20,6 +30,19 @@ export function apiFetch(input: string | URL | Request, init?: RequestInit): Pro
20
30
  return fetch(input, { ...init, headers });
21
31
  }
22
32
 
33
+ /**
34
+ * Get the public-only plugin route dispatcher exposed to SSR page components.
35
+ *
36
+ * This intentionally reads `handlePublicPluginApiRoute`, not the raw
37
+ * `handlePluginApiRoute` used by core's authenticated plugin API route.
38
+ */
39
+ export function getPublicPluginApiRouteHandler(
40
+ locals: PublicPluginRuntimeLocals | null | undefined,
41
+ ): PublicPluginApiRouteHandler | undefined {
42
+ const handler = locals?.emdash?.handlePublicPluginApiRoute;
43
+ return typeof handler === "function" ? handler : undefined;
44
+ }
45
+
23
46
  /**
24
47
  * Parse an API response, unwrapping the `{ data: T }` envelope.
25
48
  *
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import type { PluginDescriptor } from "../astro/integration/runtime.js";
14
- import type { SandboxedPlugin } from "../plugin-types.js";
14
+ import type { RouteEntry, RouteHandler, SandboxedPlugin } from "../plugin-types.js";
15
15
  import { PLUGIN_CAPABILITIES, HOOK_NAMES } from "./manifest-schema.js";
16
16
  import { normalizeCapabilities } from "./types.js";
17
17
  import type {
@@ -96,6 +96,31 @@ function resolveSandboxedHook(entry: AnyHookEntry, pluginId: string): ResolvedHo
96
96
  };
97
97
  }
98
98
 
99
+ /**
100
+ * Normalise a `RouteEntry` (bare handler or `{ handler, public?, input? }`
101
+ * config) to the config form. The `input` schema is intentionally typed
102
+ * `unknown` in `RouteEntry` — sandboxed plugins describe it loosely
103
+ * because the strict `z.ZodType<TInput>` constraint of the runtime's
104
+ * `PluginRoute` only narrows once the route is wired into the router.
105
+ * The wider type flows through to the runtime which validates at
106
+ * invocation time.
107
+ */
108
+ function normalizeRouteEntry(entry: RouteEntry): {
109
+ handler: RouteHandler;
110
+ public?: boolean;
111
+ input?: PluginRoute["input"];
112
+ } {
113
+ if (typeof entry === "function") {
114
+ return { handler: entry };
115
+ }
116
+ return {
117
+ handler: entry.handler,
118
+ public: entry.public,
119
+ // eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- RouteEntry.input is intentionally `unknown` (sandboxed plugins) and validated by the runtime at invocation time
120
+ input: entry.input as PluginRoute["input"],
121
+ };
122
+ }
123
+
99
124
  const VALID_CAPABILITIES_SET = new Set<string>(PLUGIN_CAPABILITIES);
100
125
 
101
126
  const VALID_HOOK_NAMES_SET = new Set<string>(HOOK_NAMES);
@@ -136,9 +161,13 @@ export function adaptSandboxEntry(
136
161
  // Resolve hooks. `SandboxedPlugin.hooks` is keyed by hook name with
137
162
  // per-key entry types; iterating with `Object.entries` collapses
138
163
  // keys to `string`, so we treat each entry as the union `AnyHookEntry`
139
- // for the duration of the loop.
164
+ // for the duration of the loop. The widening from the strict mapped
165
+ // type to a plain record is sound because each entry still matches
166
+ // one of the bare-handler / config-object shapes captured by
167
+ // `AnyHookEntry`.
140
168
  const resolvedHooks: ResolvedPluginHooks = {};
141
169
  if (definition.hooks) {
170
+ // eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- widening the strict mapped type to a string-keyed record for iteration; entries still match AnyHookEntry
142
171
  const hookMap = definition.hooks as Record<string, AnyHookEntry>;
143
172
  for (const [hookName, entry] of Object.entries(hookMap)) {
144
173
  if (!VALID_HOOK_NAMES_SET.has(hookName)) {
@@ -166,49 +195,25 @@ export function adaptSandboxEntry(
166
195
  const resolvedRoutes: Record<string, PluginRoute> = {};
167
196
  if (definition.routes) {
168
197
  for (const [routeName, rawEntry] of Object.entries(definition.routes)) {
169
- const isConfig = typeof rawEntry === "object" && rawEntry !== null && "handler" in rawEntry;
170
- const handler = isConfig
171
- ? (rawEntry as { handler: (...args: unknown[]) => Promise<unknown> }).handler
172
- : (rawEntry as (...args: unknown[]) => Promise<unknown>);
173
- const publicFlag = isConfig ? (rawEntry as { public?: boolean }).public : undefined;
174
- const inputSchema = isConfig ? (rawEntry as { input?: unknown }).input : undefined;
198
+ const normalized = normalizeRouteEntry(rawEntry);
199
+ const { handler, public: publicFlag, input: inputSchema } = normalized;
175
200
  resolvedRoutes[routeName] = {
176
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- route entry.input is intentionally loosely typed; callers validate at runtime
177
- input: inputSchema as PluginRoute["input"],
201
+ input: inputSchema,
178
202
  public: publicFlag,
179
203
  handler: async (ctx) => {
180
- // In-process, `ctx.request` is a real WHATWG `Request`
181
- // with a `Headers` object. The author-facing
182
- // `SandboxedRequest` type promises a plain
183
- // `Record<string, string>` (the shape the sandbox's
184
- // serialised form delivers). Normalise so handlers
185
- // behave the same in-process and in-isolate.
204
+ // `ctx.request` is a real WHATWG `Request` (this is the
205
+ // in-process adapter; the worker-sandbox adapter handles
206
+ // the serialised case). Flatten `Headers` to the plain
207
+ // `Record<string, string>` shape that author-facing
208
+ // `SandboxedRequest` promises so handler bodies are
209
+ // identical across both adapters.
186
210
  const headers: Record<string, string> = {};
187
- if (ctx.request && typeof ctx.request === "object") {
188
- const h: unknown = (ctx.request as { headers?: unknown }).headers;
189
- if (h && typeof h === "object") {
190
- if (typeof (h as Headers).forEach === "function") {
191
- (h as Headers).forEach((value, name) => {
192
- headers[name] = value;
193
- });
194
- } else {
195
- for (const [name, value] of Object.entries(h as Record<string, string>)) {
196
- headers[name] = value;
197
- }
198
- }
199
- }
200
- }
211
+ ctx.request.headers.forEach((value, name) => {
212
+ headers[name] = value;
213
+ });
201
214
  const requestShape = {
202
- url:
203
- (ctx.request as { url?: unknown } | undefined)?.url &&
204
- typeof (ctx.request as { url: unknown }).url === "string"
205
- ? (ctx.request as { url: string }).url
206
- : "",
207
- method:
208
- (ctx.request as { method?: unknown } | undefined)?.method &&
209
- typeof (ctx.request as { method: unknown }).method === "string"
210
- ? (ctx.request as { method: string }).method
211
- : "GET",
215
+ url: ctx.request.url,
216
+ method: ctx.request.method,
212
217
  headers,
213
218
  };
214
219
  const routeCtx = {
@@ -33,7 +33,7 @@ export interface StoredEmail {
33
33
  const GLOBAL_KEY = Symbol.for("emdash:dev-emails");
34
34
  const g = globalThis as Record<symbol, unknown>;
35
35
  const storedEmails: StoredEmail[] = (() => {
36
- // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- globalThis singleton pattern (see request-context.ts)
36
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)
37
37
  const existing = g[GLOBAL_KEY] as StoredEmail[] | undefined;
38
38
  if (existing) return existing;
39
39
  const fresh: StoredEmail[] = [];