emdash 0.28.1 → 0.29.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 (680) hide show
  1. package/dist/{adapters-hUy8vOB-.d.mts → adapters-DPAkL6QF.d.mts} +1 -1
  2. package/dist/{adapters-hUy8vOB-.d.mts.map → adapters-DPAkL6QF.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-CRsJ6BPM.mjs → allowed-origins-FXB-FplB.mjs} +2 -2
  4. package/dist/{allowed-origins-CRsJ6BPM.mjs.map → allowed-origins-FXB-FplB.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +22 -21
  7. package/dist/api/route-utils.mjs.map +1 -1
  8. package/dist/api/schemas/index.d.mts +2 -2
  9. package/dist/api/schemas/index.mjs +4 -4
  10. package/dist/{api-DxFSorgk.mjs → api-DVbHNApo.mjs} +75 -23
  11. package/dist/api-DVbHNApo.mjs.map +1 -0
  12. package/dist/{api-tokens-DvqeZmVq.mjs → api-tokens-UYBkl17d.mjs} +2 -2
  13. package/dist/{api-tokens-DvqeZmVq.mjs.map → api-tokens-UYBkl17d.mjs.map} +1 -1
  14. package/dist/{apply-CDJqIjPU.mjs → apply-D23iUV4q.mjs} +20 -20
  15. package/dist/{apply-CDJqIjPU.mjs.map → apply-D23iUV4q.mjs.map} +1 -1
  16. package/dist/astro/index.d.mts +13 -12
  17. package/dist/astro/index.d.mts.map +1 -1
  18. package/dist/astro/index.mjs +10 -5
  19. package/dist/astro/index.mjs.map +1 -1
  20. package/dist/astro/middleware/auth.d.mts +11 -10
  21. package/dist/astro/middleware/auth.d.mts.map +1 -1
  22. package/dist/astro/middleware/auth.mjs +8 -8
  23. package/dist/astro/middleware/redirect.mjs +7 -7
  24. package/dist/astro/middleware/request-context.d.mts +3 -0
  25. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  26. package/dist/astro/middleware/request-context.mjs +257 -30
  27. package/dist/astro/middleware/request-context.mjs.map +1 -1
  28. package/dist/astro/middleware/setup.mjs +1 -1
  29. package/dist/astro/middleware.d.mts +2 -2
  30. package/dist/astro/middleware.d.mts.map +1 -1
  31. package/dist/astro/middleware.mjs +125 -79
  32. package/dist/astro/middleware.mjs.map +1 -1
  33. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -7
  34. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -7
  35. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
  36. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  37. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
  38. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +10 -10
  39. package/dist/astro/routes/api/admin/byline-fields/index.mjs +10 -10
  40. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +10 -10
  41. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +17 -17
  42. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -17
  43. package/dist/astro/routes/api/admin/bylines/index.mjs +17 -17
  44. package/dist/astro/routes/api/admin/comments/_id_/status.d.mts.map +1 -1
  45. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +13 -13
  46. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
  47. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  48. package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
  49. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  50. package/dist/astro/routes/api/admin/comments/index.d.mts.map +1 -1
  51. package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
  52. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
  54. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
  55. package/dist/astro/routes/api/admin/media-usage/repair.d.mts +8 -0
  56. package/dist/astro/routes/api/admin/media-usage/repair.d.mts.map +1 -0
  57. package/dist/astro/routes/api/admin/media-usage/repair.mjs +28 -0
  58. package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -0
  59. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
  60. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
  61. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +43 -41
  62. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  63. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +43 -41
  64. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  65. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +42 -40
  66. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +42 -40
  68. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +42 -40
  70. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/index.mjs +42 -40
  72. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  74. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +42 -40
  75. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  76. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +42 -40
  77. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +42 -40
  79. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +42 -40
  81. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +43 -41
  83. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +42 -40
  85. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +43 -41
  87. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/updates.mjs +42 -40
  89. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +42 -40
  91. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  93. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +42 -40
  94. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  95. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  96. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
  97. package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -8
  98. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
  99. package/dist/astro/routes/api/admin/users/index.mjs +7 -7
  100. package/dist/astro/routes/api/auth/dev-bypass.mjs +7 -7
  101. package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
  102. package/dist/astro/routes/api/auth/invite/complete.mjs +12 -12
  103. package/dist/astro/routes/api/auth/invite/index.mjs +9 -9
  104. package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -11
  105. package/dist/astro/routes/api/auth/logout.mjs +4 -4
  106. package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -11
  107. package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
  108. package/dist/astro/routes/api/auth/me.mjs +8 -8
  109. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  110. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  111. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -1
  112. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  113. package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -1
  114. package/dist/astro/routes/api/auth/passkey/_id_.mjs +7 -7
  115. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  116. package/dist/astro/routes/api/auth/passkey/options.mjs +13 -13
  117. package/dist/astro/routes/api/auth/passkey/register/options.mjs +11 -11
  118. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +12 -12
  119. package/dist/astro/routes/api/auth/passkey/verify.mjs +12 -12
  120. package/dist/astro/routes/api/auth/signup/complete.mjs +12 -12
  121. package/dist/astro/routes/api/auth/signup/request.mjs +11 -11
  122. package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
  123. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts.map +1 -1
  124. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +69 -14
  125. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
  126. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +13 -13
  127. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
  128. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +4 -4
  129. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
  130. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  131. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +12 -12
  132. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +8 -8
  133. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts +9 -0
  134. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts.map +1 -0
  135. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +71 -0
  136. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -0
  137. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.d.mts +8 -0
  138. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.d.mts.map +1 -0
  139. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +50 -0
  140. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -0
  141. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
  142. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
  143. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
  144. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +15 -15
  145. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
  146. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +4 -4
  147. package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
  148. package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
  149. package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
  150. package/dist/astro/routes/api/content/_collection_/trash.mjs +8 -8
  151. package/dist/astro/routes/api/dashboard.mjs +8 -8
  152. package/dist/astro/routes/api/dev/emails.mjs +4 -4
  153. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  154. package/dist/astro/routes/api/import/probe.mjs +18 -18
  155. package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
  156. package/dist/astro/routes/api/import/wordpress/execute.d.mts +12 -11
  157. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  158. package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -16
  159. package/dist/astro/routes/api/import/wordpress/media.d.mts +11 -10
  160. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  161. package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
  162. package/dist/astro/routes/api/import/wordpress/prepare.mjs +11 -11
  163. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +12 -16
  164. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  165. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +11 -11
  166. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  167. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +18 -18
  168. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  169. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +12 -11
  170. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  171. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +28 -28
  172. package/dist/astro/routes/api/manifest.mjs +6 -6
  173. package/dist/astro/routes/api/mcp.mjs +56 -47
  174. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  175. package/dist/astro/routes/api/media/_id_/confirm.mjs +9 -9
  176. package/dist/astro/routes/api/media/_id_.mjs +8 -8
  177. package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
  178. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  179. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  180. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  181. package/dist/astro/routes/api/media/upload-url.mjs +10 -10
  182. package/dist/astro/routes/api/media.mjs +13 -13
  183. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
  184. package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
  185. package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
  186. package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
  187. package/dist/astro/routes/api/menus/_name_.mjs +9 -9
  188. package/dist/astro/routes/api/menus/index.mjs +9 -9
  189. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  190. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
  191. package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
  192. package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
  193. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  194. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
  195. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
  196. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  197. package/dist/astro/routes/api/openapi.json.mjs +24 -5
  198. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  199. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +5 -5
  200. package/dist/astro/routes/api/redirects/404s/index.mjs +12 -12
  201. package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -12
  202. package/dist/astro/routes/api/redirects/_id_.mjs +13 -13
  203. package/dist/astro/routes/api/redirects/index.mjs +13 -13
  204. package/dist/astro/routes/api/relations/_id_/index.d.mts +10 -0
  205. package/dist/astro/routes/api/relations/_id_/index.d.mts.map +1 -0
  206. package/dist/astro/routes/api/relations/_id_/index.mjs +69 -0
  207. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -0
  208. package/dist/astro/routes/api/relations/_id_/translations.d.mts +8 -0
  209. package/dist/astro/routes/api/relations/_id_/translations.d.mts.map +1 -0
  210. package/dist/astro/routes/api/relations/_id_/translations.mjs +34 -0
  211. package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -0
  212. package/dist/astro/routes/api/relations/index.d.mts +9 -0
  213. package/dist/astro/routes/api/relations/index.d.mts.map +1 -0
  214. package/dist/astro/routes/api/relations/index.mjs +53 -0
  215. package/dist/astro/routes/api/relations/index.mjs.map +1 -0
  216. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  217. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +4 -4
  218. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.d.mts.map +1 -1
  219. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +42 -40
  220. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  221. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.d.mts.map +1 -1
  222. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +42 -40
  223. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  224. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +42 -40
  225. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  226. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +42 -40
  227. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  228. package/dist/astro/routes/api/schema/collections/index.mjs +42 -40
  229. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  230. package/dist/astro/routes/api/schema/index.mjs +9 -9
  231. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +42 -40
  232. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  233. package/dist/astro/routes/api/schema/orphans/index.mjs +42 -40
  234. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  235. package/dist/astro/routes/api/search/enable.mjs +12 -12
  236. package/dist/astro/routes/api/search/index.mjs +13 -12
  237. package/dist/astro/routes/api/search/index.mjs.map +1 -1
  238. package/dist/astro/routes/api/search/rebuild.mjs +12 -12
  239. package/dist/astro/routes/api/search/stats.mjs +8 -8
  240. package/dist/astro/routes/api/search/suggest.mjs +11 -11
  241. package/dist/astro/routes/api/sections/_slug_.mjs +11 -11
  242. package/dist/astro/routes/api/sections/index.mjs +11 -11
  243. package/dist/astro/routes/api/settings/email.mjs +6 -6
  244. package/dist/astro/routes/api/settings.mjs +15 -15
  245. package/dist/astro/routes/api/setup/admin-verify.mjs +13 -13
  246. package/dist/astro/routes/api/setup/admin.mjs +12 -12
  247. package/dist/astro/routes/api/setup/dev-bypass.mjs +29 -29
  248. package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
  249. package/dist/astro/routes/api/setup/index.mjs +30 -30
  250. package/dist/astro/routes/api/setup/status.mjs +5 -5
  251. package/dist/astro/routes/api/snapshot.mjs +8 -8
  252. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +15 -15
  253. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +15 -15
  254. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +15 -15
  255. package/dist/astro/routes/api/taxonomies/index.mjs +15 -15
  256. package/dist/astro/routes/api/themes/preview.mjs +7 -7
  257. package/dist/astro/routes/api/typegen.mjs +6 -6
  258. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  259. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  260. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  261. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +8 -8
  262. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +12 -12
  263. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +12 -12
  264. package/dist/astro/routes/api/widget-areas/_name_.mjs +8 -8
  265. package/dist/astro/routes/api/widget-areas/index.mjs +12 -12
  266. package/dist/astro/routes/api/widget-components.mjs +4 -4
  267. package/dist/astro/routes/robots.txt.mjs +9 -9
  268. package/dist/astro/routes/sitemap-_collection_.xml.mjs +12 -12
  269. package/dist/astro/routes/sitemap.xml.mjs +10 -10
  270. package/dist/astro/types.d.mts +16 -13
  271. package/dist/astro/types.d.mts.map +1 -1
  272. package/dist/auth/providers/github.d.mts +1 -1
  273. package/dist/auth/providers/google.d.mts +1 -1
  274. package/dist/{authorize-Dz88F_Fw.mjs → authorize-BmCwQCib.mjs} +2 -2
  275. package/dist/{authorize-Dz88F_Fw.mjs.map → authorize-BmCwQCib.mjs.map} +1 -1
  276. package/dist/{base64-CmWvODNW.mjs → base64-C74Msx8h.mjs} +1 -1
  277. package/dist/{base64-CmWvODNW.mjs.map → base64-C74Msx8h.mjs.map} +1 -1
  278. package/dist/{byline-Bm8ZgUP9.mjs → byline-BWb5H-65.mjs} +8 -8
  279. package/dist/{byline-Bm8ZgUP9.mjs.map → byline-BWb5H-65.mjs.map} +1 -1
  280. package/dist/{byline-fields-CIx_GuN4.mjs → byline-fields-DO6bAYK8.mjs} +2 -2
  281. package/dist/{byline-fields-CIx_GuN4.mjs.map → byline-fields-DO6bAYK8.mjs.map} +1 -1
  282. package/dist/{byline-registry-BOjqDOim.mjs → byline-registry-BCuOp4UF.mjs} +3 -3
  283. package/dist/{byline-registry-BOjqDOim.mjs.map → byline-registry-BCuOp4UF.mjs.map} +1 -1
  284. package/dist/{bylines-6tm9mgQb.mjs → bylines-BGuKFaBy.mjs} +4 -4
  285. package/dist/{bylines-6tm9mgQb.mjs.map → bylines-BGuKFaBy.mjs.map} +1 -1
  286. package/dist/{bylines-CAZxGSrm.mjs → bylines-CHojDMpj.mjs} +8 -8
  287. package/dist/{bylines-CAZxGSrm.mjs.map → bylines-CHojDMpj.mjs.map} +1 -1
  288. package/dist/{cache-CEBAZjir.mjs → cache-BeR7RfN8.mjs} +3 -3
  289. package/dist/{cache-CEBAZjir.mjs.map → cache-BeR7RfN8.mjs.map} +1 -1
  290. package/dist/{challenge-store-anhwVER0.mjs → challenge-store-B426wQ6O.mjs} +1 -1
  291. package/dist/{challenge-store-anhwVER0.mjs.map → challenge-store-B426wQ6O.mjs.map} +1 -1
  292. package/dist/{chunks-B2isWQhr.mjs → chunks-BU5_nrAC.mjs} +2 -2
  293. package/dist/{chunks-B2isWQhr.mjs.map → chunks-BU5_nrAC.mjs.map} +1 -1
  294. package/dist/cli/index.mjs +28 -28
  295. package/dist/cli/index.mjs.map +1 -1
  296. package/dist/client/cf-access.d.mts +1 -1
  297. package/dist/client/index.d.mts +34 -2
  298. package/dist/client/index.d.mts.map +1 -1
  299. package/dist/client/index.mjs +6 -2
  300. package/dist/client/index.mjs.map +1 -1
  301. package/dist/{comment-CzeatwBV.mjs → comment-SWh31kS0.mjs} +2 -2
  302. package/dist/{comment-CzeatwBV.mjs.map → comment-SWh31kS0.mjs.map} +1 -1
  303. package/dist/{comment-reaction-Cj9QJY7I.mjs → comment-reaction-DgcpziXI.mjs} +2 -2
  304. package/dist/{comment-reaction-Cj9QJY7I.mjs.map → comment-reaction-DgcpziXI.mjs.map} +1 -1
  305. package/dist/{comments-BLE-jv5k.mjs → comments-kZYGppMS.mjs} +3 -3
  306. package/dist/{comments-BLE-jv5k.mjs.map → comments-kZYGppMS.mjs.map} +1 -1
  307. package/dist/{components-B_sATNUc.mjs → components-CliOkZAs.mjs} +1 -1
  308. package/dist/{components-B_sATNUc.mjs.map → components-CliOkZAs.mjs.map} +1 -1
  309. package/dist/{content-DhgEth4k.mjs → content-BO61Sx4j.mjs} +179 -20
  310. package/dist/content-BO61Sx4j.mjs.map +1 -0
  311. package/dist/{content-refresh-Br4gMzh8.mjs → content-refresh-BkkApzeS.mjs} +8 -8
  312. package/dist/{content-refresh-Br4gMzh8.mjs.map → content-refresh-BkkApzeS.mjs.map} +1 -1
  313. package/dist/{context-BRIpHARC.mjs → context-DtSFYFuS.mjs} +71 -14
  314. package/dist/context-DtSFYFuS.mjs.map +1 -0
  315. package/dist/{cron-v4FTEFR_.mjs → cron-YFJ7uNVA.mjs} +1 -1
  316. package/dist/{cron-v4FTEFR_.mjs.map → cron-YFJ7uNVA.mjs.map} +1 -1
  317. package/dist/{dashboard-EvEKF5en.mjs → dashboard-xo_gPs_D.mjs} +6 -5
  318. package/dist/dashboard-xo_gPs_D.mjs.map +1 -0
  319. package/dist/database/pg-migration-lock.d.mts +21 -0
  320. package/dist/database/pg-migration-lock.d.mts.map +1 -0
  321. package/dist/database/pg-migration-lock.mjs +45 -0
  322. package/dist/database/pg-migration-lock.mjs.map +1 -0
  323. package/dist/db/index.d.mts +3 -3
  324. package/dist/db/index.mjs +2 -2
  325. package/dist/db/libsql.d.mts +1 -1
  326. package/dist/db/postgres.d.mts +1 -1
  327. package/dist/db/postgres.d.mts.map +1 -1
  328. package/dist/db/postgres.mjs +2 -8
  329. package/dist/db/postgres.mjs.map +1 -1
  330. package/dist/db/sqlite.d.mts +1 -1
  331. package/dist/{db-errors-CK46D-ly.mjs → db-errors-BKuXh_fi.mjs} +1 -1
  332. package/dist/{db-errors-CK46D-ly.mjs.map → db-errors-BKuXh_fi.mjs.map} +1 -1
  333. package/dist/{default-CM_D83Mg.mjs → default-DY5ovGUG.mjs} +1 -1
  334. package/dist/{default-CM_D83Mg.mjs.map → default-DY5ovGUG.mjs.map} +1 -1
  335. package/dist/{device-flow-CfGP18Uw.mjs → device-flow-CPXQ_QfW.mjs} +5 -5
  336. package/dist/{device-flow-CfGP18Uw.mjs.map → device-flow-CPXQ_QfW.mjs.map} +1 -1
  337. package/dist/{dialect-helpers-DRI5pyY3.mjs → dialect-helpers-Cue7QQOR.mjs} +21 -2
  338. package/dist/dialect-helpers-Cue7QQOR.mjs.map +1 -0
  339. package/dist/{email-console-CIf4Lfvv.mjs → email-console-CjkQc7oY.mjs} +1 -1
  340. package/dist/{email-console-CIf4Lfvv.mjs.map → email-console-CjkQc7oY.mjs.map} +1 -1
  341. package/dist/{enrich-BQ0mxJRs.mjs → enrich-CFJJgxs_.mjs} +2 -2
  342. package/dist/{enrich-BQ0mxJRs.mjs.map → enrich-CFJJgxs_.mjs.map} +1 -1
  343. package/dist/{error-CkAseSqZ.mjs → error-CfJMLSkd.mjs} +12 -3
  344. package/dist/error-CfJMLSkd.mjs.map +1 -0
  345. package/dist/{escape-DqD0aCKu.mjs → escape-r8_GbEU2.mjs} +1 -1
  346. package/dist/{escape-DqD0aCKu.mjs.map → escape-r8_GbEU2.mjs.map} +1 -1
  347. package/dist/{field-defs-cache-WUI88LX5.mjs → field-defs-cache-BVrNCgSj.mjs} +5 -5
  348. package/dist/{field-defs-cache-WUI88LX5.mjs.map → field-defs-cache-BVrNCgSj.mjs.map} +1 -1
  349. package/dist/{fts-manager-BbFaF_V8.mjs → fts-manager-BD9s77qh.mjs} +27 -3
  350. package/dist/{fts-manager-BbFaF_V8.mjs.map → fts-manager-BD9s77qh.mjs.map} +1 -1
  351. package/dist/{hash-DrvzIXcz.mjs → hash-DFFrkivP.mjs} +1 -1
  352. package/dist/{hash-DrvzIXcz.mjs.map → hash-DFFrkivP.mjs.map} +1 -1
  353. package/dist/hreflang-CgIxhH4k.d.mts +48 -0
  354. package/dist/hreflang-CgIxhH4k.d.mts.map +1 -0
  355. package/dist/hreflang-pAWUiPd_.mjs +102 -0
  356. package/dist/hreflang-pAWUiPd_.mjs.map +1 -0
  357. package/dist/{import-fYLf14Co.mjs → import-2jHtLzsO.mjs} +6 -6
  358. package/dist/{import-fYLf14Co.mjs.map → import-2jHtLzsO.mjs.map} +1 -1
  359. package/dist/{index-B9sIxwe4.d.mts → index-BXOCyLj0.d.mts} +115 -21
  360. package/dist/index-BXOCyLj0.d.mts.map +1 -0
  361. package/dist/{index-Bm-Gy8Mh.d.mts → index-DxjWLKGT.d.mts} +3 -3
  362. package/dist/{index-Bm-Gy8Mh.d.mts.map → index-DxjWLKGT.d.mts.map} +1 -1
  363. package/dist/index.d.mts +20 -19
  364. package/dist/index.mjs +68 -64
  365. package/dist/{init-lock-6b309ZrF.mjs → init-lock-DJkX6Hto.mjs} +1 -1
  366. package/dist/{init-lock-6b309ZrF.mjs.map → init-lock-DJkX6Hto.mjs.map} +1 -1
  367. package/dist/{load-Djn3HWQS.mjs → load-DgoWMdRX.mjs} +2 -2
  368. package/dist/{load-Djn3HWQS.mjs.map → load-DgoWMdRX.mjs.map} +1 -1
  369. package/dist/{loader-CB6YHeul.mjs → loader-Rb8QlGZp.mjs} +5 -20
  370. package/dist/loader-Rb8QlGZp.mjs.map +1 -0
  371. package/dist/{manifest-schema-BHlgZM1W.mjs → manifest-schema-DeGNma2O.mjs} +3 -1
  372. package/dist/manifest-schema-DeGNma2O.mjs.map +1 -0
  373. package/dist/media/image-endpoint.mjs +1 -1
  374. package/dist/media/index.d.mts +1 -1
  375. package/dist/media/index.mjs +2 -2
  376. package/dist/media/local-runtime.d.mts +13 -12
  377. package/dist/media/local-runtime.d.mts.map +1 -1
  378. package/dist/media/local-runtime.mjs +8 -8
  379. package/dist/{media-BrXIaMFN.mjs → media-D2ZFowpn.mjs} +2 -2
  380. package/dist/media-D2ZFowpn.mjs.map +1 -0
  381. package/dist/{media-allowlist-CRHEeJ_i.mjs → media-allowlist-Dc05vKtt.mjs} +2 -2
  382. package/dist/{media-allowlist-CRHEeJ_i.mjs.map → media-allowlist-Dc05vKtt.mjs.map} +1 -1
  383. package/dist/{media-url-CKi5XSw4.mjs → media-url-DgIEYZr4.mjs} +1 -1
  384. package/dist/{media-url-CKi5XSw4.mjs.map → media-url-DgIEYZr4.mjs.map} +1 -1
  385. package/dist/media-usage-B__v9NMm.mjs +421 -0
  386. package/dist/media-usage-B__v9NMm.mjs.map +1 -0
  387. package/dist/{menus-Cfivc2Ad.mjs → menus-BpfevlJD.mjs} +3 -3
  388. package/dist/{menus-Cfivc2Ad.mjs.map → menus-BpfevlJD.mjs.map} +1 -1
  389. package/dist/{menus-b2T4clbO.mjs → menus-BtvH7Z7t.mjs} +31 -12
  390. package/dist/menus-BtvH7Z7t.mjs.map +1 -0
  391. package/dist/{mime-CCEzze7W.mjs → mime-DfIVjNkr.mjs} +1 -1
  392. package/dist/{mime-CCEzze7W.mjs.map → mime-DfIVjNkr.mjs.map} +1 -1
  393. package/dist/{mode-BM9QgEmt.mjs → mode-BVnhGZ2o.mjs} +1 -1
  394. package/dist/{mode-BM9QgEmt.mjs.map → mode-BVnhGZ2o.mjs.map} +1 -1
  395. package/dist/{normalize-CeglrBT9.mjs → normalize-C-SHXmra.mjs} +1 -1
  396. package/dist/{normalize-CeglrBT9.mjs.map → normalize-C-SHXmra.mjs.map} +1 -1
  397. package/dist/{oauth-authorization-CXWkIGT4.mjs → oauth-authorization-BWqWTHBK.mjs} +5 -5
  398. package/dist/{oauth-authorization-CXWkIGT4.mjs.map → oauth-authorization-BWqWTHBK.mjs.map} +1 -1
  399. package/dist/{oauth-clients-BmTI5rsl.mjs → oauth-clients-43_XADoa.mjs} +1 -1
  400. package/dist/{oauth-clients-BmTI5rsl.mjs.map → oauth-clients-43_XADoa.mjs.map} +1 -1
  401. package/dist/{oauth-state-store-YLFLcH5F.mjs → oauth-state-store-BRSUEkmx.mjs} +1 -1
  402. package/dist/{oauth-state-store-YLFLcH5F.mjs.map → oauth-state-store-BRSUEkmx.mjs.map} +1 -1
  403. package/dist/{oauth-user-lookup-Bsc_GsX-.mjs → oauth-user-lookup-Ctgemb0k.mjs} +1 -1
  404. package/dist/{oauth-user-lookup-Bsc_GsX-.mjs.map → oauth-user-lookup-Ctgemb0k.mjs.map} +1 -1
  405. package/dist/object-cache/memory.d.mts +1 -1
  406. package/dist/{options-DTTML-Tx.mjs → options-BlmBHTvX.mjs} +1 -1
  407. package/dist/{options-DTTML-Tx.mjs.map → options-BlmBHTvX.mjs.map} +1 -1
  408. package/dist/{options-iMpRRxIe.d.mts → options-COXGTtqd.d.mts} +3 -3
  409. package/dist/{options-iMpRRxIe.d.mts.map → options-COXGTtqd.d.mts.map} +1 -1
  410. package/dist/page/index.d.mts +2 -2
  411. package/dist/{parse-GmjecGct.mjs → parse-GLksnn-B.mjs} +2 -2
  412. package/dist/{parse-GmjecGct.mjs.map → parse-GLksnn-B.mjs.map} +1 -1
  413. package/dist/{passkey-config-De0ahnRg.mjs → passkey-config-CjA1UbDj.mjs} +1 -1
  414. package/dist/{passkey-config-De0ahnRg.mjs.map → passkey-config-CjA1UbDj.mjs.map} +1 -1
  415. package/dist/{patterns-BKmjvM7K.mjs → patterns-CiyXeDgr.mjs} +1 -1
  416. package/dist/{patterns-BKmjvM7K.mjs.map → patterns-CiyXeDgr.mjs.map} +1 -1
  417. package/dist/{placeholder-BSKwzRe4.d.mts → placeholder-DR-eeZr-.d.mts} +1 -1
  418. package/dist/{placeholder-BSKwzRe4.d.mts.map → placeholder-DR-eeZr-.d.mts.map} +1 -1
  419. package/dist/plugin-types.d.mts +1 -1
  420. package/dist/plugin-utils.d.mts +11 -10
  421. package/dist/plugin-utils.d.mts.map +1 -1
  422. package/dist/plugins/adapt-sandbox-entry.d.mts +11 -10
  423. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  424. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  425. package/dist/{portable-text-cCa0cGV6.mjs → portable-text-BAkgEKcv.mjs} +1 -1
  426. package/dist/{portable-text-cCa0cGV6.mjs.map → portable-text-BAkgEKcv.mjs.map} +1 -1
  427. package/dist/{preview-SSXNVPAC.mjs → preview-Rloa09Wp.mjs} +2 -2
  428. package/dist/{preview-SSXNVPAC.mjs.map → preview-Rloa09Wp.mjs.map} +1 -1
  429. package/dist/{public-url-Danv47cS.mjs → public-url-C0cEvrRu.mjs} +1 -1
  430. package/dist/{public-url-Danv47cS.mjs.map → public-url-C0cEvrRu.mjs.map} +1 -1
  431. package/dist/{schema-CX9cfNkZ.mjs → query-BxT95opY.mjs} +5 -10
  432. package/dist/query-BxT95opY.mjs.map +1 -0
  433. package/dist/{query-1Cp6U9oo.mjs → query-ZzvXyxWq.mjs} +15 -15
  434. package/dist/query-ZzvXyxWq.mjs.map +1 -0
  435. package/dist/{rate-limit-C_Lf63Dd.mjs → rate-limit-Cg4Rvc_-.mjs} +2 -2
  436. package/dist/{rate-limit-C_Lf63Dd.mjs.map → rate-limit-Cg4Rvc_-.mjs.map} +1 -1
  437. package/dist/{redirect-CoW3G-0U.mjs → redirect-Ce_6Yb6z.mjs} +1 -1
  438. package/dist/{redirect-CoW3G-0U.mjs.map → redirect-Ce_6Yb6z.mjs.map} +1 -1
  439. package/dist/{redirect-IyfNirgS.mjs → redirect-Ch3E98qZ.mjs} +4 -4
  440. package/dist/{redirect-IyfNirgS.mjs.map → redirect-Ch3E98qZ.mjs.map} +1 -1
  441. package/dist/{redirects-Bs1g42Ri.mjs → redirects-CXmVGRNZ.mjs} +6 -6
  442. package/dist/{redirects-Bs1g42Ri.mjs.map → redirects-CXmVGRNZ.mjs.map} +1 -1
  443. package/dist/{redirects-DXEXBAII.mjs → redirects-CeD7K7EX.mjs} +43 -5
  444. package/dist/redirects-CeD7K7EX.mjs.map +1 -0
  445. package/dist/{registry-B57vp_X9.mjs → registry-CyIXPi4E.mjs} +8 -8
  446. package/dist/{registry-B57vp_X9.mjs.map → registry-CyIXPi4E.mjs.map} +1 -1
  447. package/dist/relation-Ba68Tm4Z.mjs +334 -0
  448. package/dist/relation-Ba68Tm4Z.mjs.map +1 -0
  449. package/dist/{byline-fields-2Lp5Hbgf.mjs → relations-BmBmX4Eb.mjs} +60 -4
  450. package/dist/relations-BmBmX4Eb.mjs.map +1 -0
  451. package/dist/relations-C8hVyEy0.mjs +397 -0
  452. package/dist/relations-C8hVyEy0.mjs.map +1 -0
  453. package/dist/{byline-fields-CHE8UStY.d.mts → relations-CbBpoOys.d.mts} +182 -29
  454. package/dist/relations-CbBpoOys.d.mts.map +1 -0
  455. package/dist/{request-cache-KCNHp_RJ.mjs → request-cache-BSUptuJR.mjs} +1 -1
  456. package/dist/{request-cache-KCNHp_RJ.mjs.map → request-cache-BSUptuJR.mjs.map} +1 -1
  457. package/dist/{request-meta-DbvXaAvU.mjs → request-meta-DCwktC5P.mjs} +2 -2
  458. package/dist/{request-meta-DbvXaAvU.mjs.map → request-meta-DCwktC5P.mjs.map} +1 -1
  459. package/dist/{resolve-DR3wqMTy.mjs → resolve-Cd9dzclN.mjs} +1 -1
  460. package/dist/{resolve-DR3wqMTy.mjs.map → resolve-Cd9dzclN.mjs.map} +1 -1
  461. package/dist/{runner-DvFWoz8-.d.mts → runner-CiNdIk3y.d.mts} +8 -2
  462. package/dist/runner-CiNdIk3y.d.mts.map +1 -0
  463. package/dist/{runner-K8XK101B.mjs → runner-jt65bF7F.mjs} +24 -7
  464. package/dist/{runner-K8XK101B.mjs.map → runner-jt65bF7F.mjs.map} +1 -1
  465. package/dist/runtime.d.mts +12 -11
  466. package/dist/runtime.d.mts.map +1 -1
  467. package/dist/runtime.mjs +4 -4
  468. package/dist/{scheduled-publish-Drffrf2a.d.mts → scheduled-publish-DlJHGcuL.d.mts} +1 -1
  469. package/dist/scheduled-publish-DlJHGcuL.d.mts.map +1 -0
  470. package/dist/schema-DwjufZ1S.mjs +9 -0
  471. package/dist/schema-DwjufZ1S.mjs.map +1 -0
  472. package/dist/{search-DZN2HZ-V.mjs → search-Cl875CVE.mjs} +62 -12
  473. package/dist/search-Cl875CVE.mjs.map +1 -0
  474. package/dist/{secrets-kp760LlD.mjs → secrets-CO_bEmII.mjs} +4 -4
  475. package/dist/{secrets-kp760LlD.mjs.map → secrets-CO_bEmII.mjs.map} +1 -1
  476. package/dist/{sections-CpF5SaGr.mjs → sections-DTKzgoiS.mjs} +3 -3
  477. package/dist/{sections-CpF5SaGr.mjs.map → sections-DTKzgoiS.mjs.map} +1 -1
  478. package/dist/seed/index.d.mts +2 -2
  479. package/dist/seed/index.mjs +23 -23
  480. package/dist/seo/index.d.mts +4 -2
  481. package/dist/seo/index.d.mts.map +1 -1
  482. package/dist/seo/index.mjs +19 -2
  483. package/dist/seo/index.mjs.map +1 -1
  484. package/dist/{seo-DXu2UQnC.mjs → seo-BLm6SXzS.mjs} +2 -2
  485. package/dist/{seo-DXu2UQnC.mjs.map → seo-BLm6SXzS.mjs.map} +1 -1
  486. package/dist/{seo-89-53DDs.mjs → seo-BjrbXAd_.mjs} +1 -1
  487. package/dist/{seo-89-53DDs.mjs.map → seo-BjrbXAd_.mjs.map} +1 -1
  488. package/dist/{service-DQmiBMzt.mjs → service-D6zDmKXy.mjs} +3 -3
  489. package/dist/{service-DQmiBMzt.mjs.map → service-D6zDmKXy.mjs.map} +1 -1
  490. package/dist/{session-user-Cascbax7.mjs → session-user-DoSs6YM8.mjs} +1 -1
  491. package/dist/{session-user-Cascbax7.mjs.map → session-user-DoSs6YM8.mjs.map} +1 -1
  492. package/dist/{settings-zhmdKyJQ.mjs → settings-BuQYvLfy.mjs} +6 -6
  493. package/dist/{settings-zhmdKyJQ.mjs.map → settings-BuQYvLfy.mjs.map} +1 -1
  494. package/dist/{settings-rZyHEcNT.mjs → settings-CmS3TwXf.mjs} +3 -3
  495. package/dist/{settings-rZyHEcNT.mjs.map → settings-CmS3TwXf.mjs.map} +1 -1
  496. package/dist/{setup-complete-Cb3LRyzy.mjs → setup-complete-BPNgLHlU.mjs} +2 -2
  497. package/dist/{setup-complete-Cb3LRyzy.mjs.map → setup-complete-BPNgLHlU.mjs.map} +1 -1
  498. package/dist/{setup-nonce-Z8x0tHf8.mjs → setup-nonce-DEPZX96T.mjs} +1 -1
  499. package/dist/{setup-nonce-Z8x0tHf8.mjs.map → setup-nonce-DEPZX96T.mjs.map} +1 -1
  500. package/dist/{single-flight-cache-BG3B_GhN.mjs → single-flight-cache-DEtW-OEG.mjs} +2 -2
  501. package/dist/{single-flight-cache-BG3B_GhN.mjs.map → single-flight-cache-DEtW-OEG.mjs.map} +1 -1
  502. package/dist/{site-url-BBfDTgZB.mjs → site-url-CcLy5D5s.mjs} +2 -2
  503. package/dist/{site-url-BBfDTgZB.mjs.map → site-url-CcLy5D5s.mjs.map} +1 -1
  504. package/dist/{slugify-Cce3dTdg.mjs → slugify-C_tqlU4G.mjs} +1 -1
  505. package/dist/{slugify-Cce3dTdg.mjs.map → slugify-C_tqlU4G.mjs.map} +1 -1
  506. package/dist/{ssrf-1g7usGBg.mjs → ssrf-TrKYJAy0.mjs} +1 -1
  507. package/dist/{ssrf-1g7usGBg.mjs.map → ssrf-TrKYJAy0.mjs.map} +1 -1
  508. package/dist/{status-CqJQX1QN.mjs → status-D3Gy1Zc6.mjs} +1 -1
  509. package/dist/{status-CqJQX1QN.mjs.map → status-D3Gy1Zc6.mjs.map} +1 -1
  510. package/dist/storage/local.d.mts +1 -1
  511. package/dist/storage/local.mjs +1 -1
  512. package/dist/storage/s3.d.mts +1 -1
  513. package/dist/storage/s3.mjs +1 -1
  514. package/dist/{taxonomies-Bs13SN-F.mjs → taxonomies-ClS4RKaZ.mjs} +13 -9
  515. package/dist/taxonomies-ClS4RKaZ.mjs.map +1 -0
  516. package/dist/{taxonomies-kH9ABDUF.mjs → taxonomies-pUkuD6nj.mjs} +115 -36
  517. package/dist/taxonomies-pUkuD6nj.mjs.map +1 -0
  518. package/dist/{taxonomy-BxGxZZdu.mjs → taxonomy-BkxbUMSw.mjs} +12 -3
  519. package/dist/{taxonomy-BxGxZZdu.mjs.map → taxonomy-BkxbUMSw.mjs.map} +1 -1
  520. package/dist/{tokens-BGT0TUUo.mjs → tokens-BV6fgl5A.mjs} +2 -2
  521. package/dist/{tokens-BGT0TUUo.mjs.map → tokens-BV6fgl5A.mjs.map} +1 -1
  522. package/dist/{transaction-qfqpPVpu.mjs → transaction-D0FOsb3X.mjs} +1 -1
  523. package/dist/{transaction-qfqpPVpu.mjs.map → transaction-D0FOsb3X.mjs.map} +1 -1
  524. package/dist/{transport-DPefPMcz.mjs → transport-DTFhhPOg.mjs} +1 -1
  525. package/dist/{transport-DPefPMcz.mjs.map → transport-DTFhhPOg.mjs.map} +1 -1
  526. package/dist/{transport-BMDWHSgZ.d.mts → transport-DmlmzD2U.d.mts} +1 -1
  527. package/dist/{transport-BMDWHSgZ.d.mts.map → transport-DmlmzD2U.d.mts.map} +1 -1
  528. package/dist/{trusted-proxy-VTPRiX2s.mjs → trusted-proxy-CSgZVESw.mjs} +1 -1
  529. package/dist/{trusted-proxy-VTPRiX2s.mjs.map → trusted-proxy-CSgZVESw.mjs.map} +1 -1
  530. package/dist/{types-CgvhU-hF.d.mts → types-B6-N9cBB.d.mts} +1 -1
  531. package/dist/{types-CgvhU-hF.d.mts.map → types-B6-N9cBB.d.mts.map} +1 -1
  532. package/dist/{types-g_aFIdW0.d.mts → types-BCVuUPrL.d.mts} +1 -1
  533. package/dist/{types-g_aFIdW0.d.mts.map → types-BCVuUPrL.d.mts.map} +1 -1
  534. package/dist/{types-Jo3UYd6b.mjs → types-BNZsPL9z.mjs} +1 -1
  535. package/dist/{types-Jo3UYd6b.mjs.map → types-BNZsPL9z.mjs.map} +1 -1
  536. package/dist/{types-vgEWF18A.d.mts → types-B_pmP7Yq.d.mts} +1 -1
  537. package/dist/{types-vgEWF18A.d.mts.map → types-B_pmP7Yq.d.mts.map} +1 -1
  538. package/dist/{types-CuW0zWDA.mjs → types-Ch8pFMEm.mjs} +3 -3
  539. package/dist/{types-CuW0zWDA.mjs.map → types-Ch8pFMEm.mjs.map} +1 -1
  540. package/dist/{types-ea9sAPck.d.mts → types-Cm4Cz-8M.d.mts} +1 -1
  541. package/dist/{types-ea9sAPck.d.mts.map → types-Cm4Cz-8M.d.mts.map} +1 -1
  542. package/dist/{types-CGbYowGQ.d.mts → types-CtDVagM4.d.mts} +55 -3
  543. package/dist/types-CtDVagM4.d.mts.map +1 -0
  544. package/dist/{types-BcLUUbbR.d.mts → types-DLIrNtv5.d.mts} +11 -3
  545. package/dist/{types-BcLUUbbR.d.mts.map → types-DLIrNtv5.d.mts.map} +1 -1
  546. package/dist/{types-DmHk7vAt.d.mts → types-QnlQIyPE.d.mts} +1 -1
  547. package/dist/{types-DmHk7vAt.d.mts.map → types-QnlQIyPE.d.mts.map} +1 -1
  548. package/dist/{types-_HFLRzTn.d.mts → types-momGysZk.d.mts} +1 -1
  549. package/dist/{types-_HFLRzTn.d.mts.map → types-momGysZk.d.mts.map} +1 -1
  550. package/dist/{types-tM44hEcf.mjs → types-o7xo7VgH.mjs} +1 -1
  551. package/dist/{types-tM44hEcf.mjs.map → types-o7xo7VgH.mjs.map} +1 -1
  552. package/dist/{types-ClUkdbWb.d.mts → types-qljd1hsL.d.mts} +1 -1
  553. package/dist/{types-ClUkdbWb.d.mts.map → types-qljd1hsL.d.mts.map} +1 -1
  554. package/dist/{user-BjAOvU3Z.mjs → user-DTxX_Fha.mjs} +3 -3
  555. package/dist/{user-BjAOvU3Z.mjs.map → user-DTxX_Fha.mjs.map} +1 -1
  556. package/dist/{utils-BJXElxdw.mjs → utils-Cz8PVrl4.mjs} +3 -3
  557. package/dist/{utils-BJXElxdw.mjs.map → utils-Cz8PVrl4.mjs.map} +1 -1
  558. package/dist/{validate-Z1b86_3B.d.mts → validate-9jLuE301.d.mts} +5 -5
  559. package/dist/{validate-Z1b86_3B.d.mts.map → validate-9jLuE301.d.mts.map} +1 -1
  560. package/dist/{validate-CWSnKVIJ.mjs → validate-C3CpWlNt.mjs} +3 -3
  561. package/dist/{validate-CWSnKVIJ.mjs.map → validate-C3CpWlNt.mjs.map} +1 -1
  562. package/dist/{validation-0l8-RYj4.mjs → validation-DM2K_NJC.mjs} +10 -10
  563. package/dist/{validation-0l8-RYj4.mjs.map → validation-DM2K_NJC.mjs.map} +1 -1
  564. package/dist/version-BlIJvNAZ.mjs +7 -0
  565. package/dist/{version-qmeO1XZY.mjs.map → version-BlIJvNAZ.mjs.map} +1 -1
  566. package/dist/{widgets-hWcIicX8.mjs → widgets-B_X6_UXJ.mjs} +4 -4
  567. package/dist/{widgets-hWcIicX8.mjs.map → widgets-B_X6_UXJ.mjs.map} +1 -1
  568. package/dist/{wxr-taxonomies-CNFcsNCr.mjs → wxr-taxonomies-oNJB2S81.mjs} +4 -4
  569. package/dist/{wxr-taxonomies-CNFcsNCr.mjs.map → wxr-taxonomies-oNJB2S81.mjs.map} +1 -1
  570. package/dist/{wxr-taxonomies-0_uxSrmf.d.mts → wxr-taxonomies-tADW4KTa.d.mts} +1 -1
  571. package/dist/{wxr-taxonomies-0_uxSrmf.d.mts.map → wxr-taxonomies-tADW4KTa.d.mts.map} +1 -1
  572. package/dist/{zod-generator-CacrR-i8.mjs → zod-generator-CrfV79De.mjs} +3 -3
  573. package/dist/{zod-generator-CacrR-i8.mjs.map → zod-generator-CrfV79De.mjs.map} +1 -1
  574. package/package.json +11 -7
  575. package/src/api/errors.ts +11 -0
  576. package/src/api/handlers/content.ts +111 -1
  577. package/src/api/handlers/dashboard.ts +2 -0
  578. package/src/api/handlers/index.ts +6 -0
  579. package/src/api/handlers/media-usage.ts +80 -0
  580. package/src/api/handlers/relations.ts +474 -0
  581. package/src/api/handlers/taxonomies.ts +26 -4
  582. package/src/api/handlers/validate-media-fields.ts +1 -1
  583. package/src/api/openapi/document.ts +25 -0
  584. package/src/api/parse.ts +1 -1
  585. package/src/api/schemas/comments.ts +6 -0
  586. package/src/api/schemas/content.ts +8 -0
  587. package/src/api/schemas/index.ts +2 -0
  588. package/src/api/schemas/media-usage.ts +48 -0
  589. package/src/api/schemas/relations.ts +109 -0
  590. package/src/api/schemas/search.ts +1 -0
  591. package/src/astro/integration/index.ts +1 -0
  592. package/src/astro/integration/routes.ts +5 -0
  593. package/src/astro/integration/runtime.ts +24 -0
  594. package/src/astro/middleware/request-context.ts +162 -20
  595. package/src/astro/middleware.ts +22 -9
  596. package/src/astro/routes/api/admin/comments/[id]/status.ts +1 -2
  597. package/src/astro/routes/api/admin/comments/index.ts +1 -2
  598. package/src/astro/routes/api/admin/media-usage/repair.ts +24 -0
  599. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +1 -2
  600. package/src/astro/routes/api/auth/oauth/[provider].ts +1 -2
  601. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +13 -0
  602. package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/children.ts +97 -0
  603. package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/parents.ts +48 -0
  604. package/src/astro/routes/api/relations/[id]/index.ts +84 -0
  605. package/src/astro/routes/api/relations/[id]/translations.ts +33 -0
  606. package/src/astro/routes/api/relations/index.ts +56 -0
  607. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +1 -7
  608. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +1 -2
  609. package/src/astro/routes/api/search/index.ts +2 -0
  610. package/src/astro/types.ts +2 -0
  611. package/src/cli/commands/export-seed.ts +1 -10
  612. package/src/client/index.ts +39 -0
  613. package/src/comments/service.ts +1 -1
  614. package/src/comments/turnstile.ts +64 -0
  615. package/src/components/BlockquoteGroup.astro +34 -0
  616. package/src/components/CommentForm.astro +12 -5
  617. package/src/components/EmDashHead.astro +27 -1
  618. package/src/components/InlinePortableTextEditor.tsx +34 -0
  619. package/src/components/PortableText.astro +7 -1
  620. package/src/components/index.ts +2 -0
  621. package/src/components/portable-text-blockquote-group.ts +68 -0
  622. package/src/content/converters/portable-text-to-prosemirror.ts +32 -1
  623. package/src/database/dialect-helpers.ts +34 -0
  624. package/src/database/migrations/039_fix_fts5_triggers.ts +1 -1
  625. package/src/database/migrations/runner.ts +46 -6
  626. package/src/database/pg-migration-lock.ts +72 -0
  627. package/src/database/repositories/comment.ts +1 -1
  628. package/src/database/repositories/content.ts +172 -21
  629. package/src/database/repositories/media.ts +1 -1
  630. package/src/database/repositories/relation.ts +130 -5
  631. package/src/database/repositories/taxonomy.ts +9 -0
  632. package/src/database/repositories/types.ts +8 -0
  633. package/src/db/postgres.ts +5 -2
  634. package/src/emdash-runtime.ts +72 -4
  635. package/src/index.ts +6 -2
  636. package/src/loader.ts +1 -31
  637. package/src/mcp/server.ts +29 -3
  638. package/src/plugins/context.ts +85 -0
  639. package/src/plugins/define-plugin.ts +1 -0
  640. package/src/plugins/index.ts +4 -0
  641. package/src/plugins/manifest-schema.ts +2 -0
  642. package/src/plugins/types.ts +59 -0
  643. package/src/schema/byline-registry.ts +1 -1
  644. package/src/search/fts-manager.ts +34 -0
  645. package/src/search/match.ts +50 -0
  646. package/src/search/query.ts +94 -9
  647. package/src/seo/hreflang.ts +192 -0
  648. package/src/seo/index.ts +3 -0
  649. package/src/taxonomies/index.ts +62 -45
  650. package/src/taxonomies/term-counts.ts +117 -0
  651. package/src/virtual-modules.d.ts +1 -0
  652. package/src/visual-editing/editable.ts +41 -35
  653. package/src/visual-editing/toolbar-bootstrap.ts +120 -0
  654. package/src/visual-editing/toolbar.ts +46 -0
  655. package/dist/api-DxFSorgk.mjs.map +0 -1
  656. package/dist/byline-fields-2Lp5Hbgf.mjs.map +0 -1
  657. package/dist/byline-fields-CHE8UStY.d.mts.map +0 -1
  658. package/dist/content-DhgEth4k.mjs.map +0 -1
  659. package/dist/context-BRIpHARC.mjs.map +0 -1
  660. package/dist/dashboard-EvEKF5en.mjs.map +0 -1
  661. package/dist/dialect-helpers-DRI5pyY3.mjs.map +0 -1
  662. package/dist/error-CkAseSqZ.mjs.map +0 -1
  663. package/dist/index-B9sIxwe4.d.mts.map +0 -1
  664. package/dist/loader-CB6YHeul.mjs.map +0 -1
  665. package/dist/manifest-schema-BHlgZM1W.mjs.map +0 -1
  666. package/dist/media-BrXIaMFN.mjs.map +0 -1
  667. package/dist/menus-b2T4clbO.mjs.map +0 -1
  668. package/dist/query-1Cp6U9oo.mjs.map +0 -1
  669. package/dist/redirects-DXEXBAII.mjs.map +0 -1
  670. package/dist/runner-DvFWoz8-.d.mts.map +0 -1
  671. package/dist/scheduled-publish-Drffrf2a.d.mts.map +0 -1
  672. package/dist/schema-CX9cfNkZ.mjs.map +0 -1
  673. package/dist/search-DZN2HZ-V.mjs.map +0 -1
  674. package/dist/taxonomies-Bs13SN-F.mjs.map +0 -1
  675. package/dist/taxonomies-kH9ABDUF.mjs.map +0 -1
  676. package/dist/types-CGbYowGQ.d.mts.map +0 -1
  677. package/dist/version-qmeO1XZY.mjs +0 -7
  678. /package/dist/{api-tokens-DsvvCtdh.mjs → api-tokens-Dk2GrJMY.mjs} +0 -0
  679. /package/dist/{ssrf-CmuGgCq3.mjs → ssrf-B5DOv5E5.mjs} +0 -0
  680. /package/dist/{types-DROWRxYV.mjs → types-DeCZBZxn.mjs} +0 -0
package/src/loader.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  import type { LiveLoader } from "astro/loaders";
15
15
  import { Kysely, type RawBuilder, sql, type Dialect } from "kysely";
16
16
 
17
- import { currentTimestampValue, isPostgres } from "./database/dialect-helpers.js";
17
+ import { buildStatusCondition, isPostgres } from "./database/dialect-helpers.js";
18
18
  import { kyselyLogOption } from "./database/instrumentation.js";
19
19
  import { decodeCursor, encodeCursor } from "./database/repositories/types.js";
20
20
  import { validateIdentifier } from "./database/validate.js";
@@ -515,36 +515,6 @@ export type SortDirection = "asc" | "desc";
515
515
  */
516
516
  export type OrderBySpec = Record<string, SortDirection>;
517
517
 
518
- /**
519
- * Build WHERE clause for status filtering.
520
- * When filtering for 'published' status, also include scheduled content
521
- * whose scheduled_at time has passed (treating it as effectively published).
522
- */
523
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance
524
- function buildStatusCondition(
525
- db: Kysely<any>,
526
- status: string,
527
- tablePrefix?: string,
528
- ): ReturnType<typeof sql> {
529
- const statusField = tablePrefix ? `${tablePrefix}.status` : "status";
530
- const scheduledAtField = tablePrefix ? `${tablePrefix}.scheduled_at` : "scheduled_at";
531
-
532
- if (status === "published") {
533
- // Include both published content AND scheduled content past its publish time.
534
- // scheduled_at is stored as text (ISO 8601). On Postgres, we must cast it
535
- // to timestamptz for the comparison with CURRENT_TIMESTAMP to work.
536
- const scheduledAtExpr = isPostgres(db)
537
- ? sql`${sql.ref(scheduledAtField)}::timestamptz`
538
- : sql.ref(scheduledAtField);
539
- const nowExpr = isPostgres(db)
540
- ? currentTimestampValue(db)
541
- : sql`strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
542
- return sql`(${sql.ref(statusField)} = 'published' OR (${sql.ref(statusField)} = 'scheduled' AND ${scheduledAtExpr} <= ${nowExpr}))`;
543
- }
544
-
545
- return sql`${sql.ref(statusField)} = ${status}`;
546
- }
547
-
548
518
  /**
549
519
  * Resolved primary sort field and direction (used for cursor pagination).
550
520
  */
package/src/mcp/server.ts CHANGED
@@ -660,6 +660,12 @@ export function createMcpServer(): McpServer {
660
660
  .describe(
661
661
  "Bylines to credit. Each entry references an existing byline by id (see byline_list / byline_create) with an optional roleLabel. The first entry becomes the primary byline.",
662
662
  ),
663
+ taxonomies: z
664
+ .record(z.string(), z.array(z.string()))
665
+ .optional()
666
+ .describe(
667
+ "Taxonomy term assignments as { taxonomyName: [termSlug, ...] }. Term slugs are resolved in the entry's locale. Call taxonomy_list to see available taxonomies and taxonomy_list_terms to look up slugs. Missing keys leave that taxonomy unchanged.",
668
+ ),
663
669
  }),
664
670
  annotations: { destructiveHint: false },
665
671
  },
@@ -685,7 +691,7 @@ export function createMcpServer(): McpServer {
685
691
  // Publishing requires publish permission — create as draft then publish
686
692
  if (args.status === "published") {
687
693
  const user = { id: userId, role: getExtra(extra).userRole };
688
- if (!hasPermission(user, "content:publish_own" as Permission)) {
694
+ if (!hasPermission(user, "content:publish_own")) {
689
695
  throw new EmDashAuthError(
690
696
  "Insufficient permissions: publishing requires content:publish_own",
691
697
  "INSUFFICIENT_PERMISSIONS",
@@ -698,6 +704,7 @@ export function createMcpServer(): McpServer {
698
704
  locale: args.locale,
699
705
  translationOf: args.translationOf,
700
706
  bylines: args.bylines,
707
+ taxonomies: args.taxonomies,
701
708
  });
702
709
  if (!result.success) return unwrap(result);
703
710
  const itemId = extractContentId(result.data);
@@ -715,6 +722,7 @@ export function createMcpServer(): McpServer {
715
722
  locale: args.locale,
716
723
  translationOf: args.translationOf,
717
724
  bylines: args.bylines,
725
+ taxonomies: args.taxonomies,
718
726
  }),
719
727
  );
720
728
  },
@@ -771,6 +779,12 @@ export function createMcpServer(): McpServer {
771
779
  .describe(
772
780
  "Replace the byline list for this item. The first entry becomes the primary byline. Pass an empty array to clear all bylines.",
773
781
  ),
782
+ taxonomies: z
783
+ .record(z.string(), z.array(z.string()))
784
+ .optional()
785
+ .describe(
786
+ "Replace taxonomy term assignments as { taxonomyName: [termSlug, ...] }. Term slugs are resolved in the entry's locale. Only named taxonomies are touched; other taxonomies are left unchanged. Pass an empty array to clear a taxonomy.",
787
+ ),
774
788
  publishedAt: z.iso
775
789
  .datetime({ offset: true, message: "must be an ISO 8601 datetime" })
776
790
  .nullish()
@@ -805,7 +819,7 @@ export function createMcpServer(): McpServer {
805
819
  // route. Status-driven publishes are gated separately below.
806
820
  if (args.publishedAt !== undefined) {
807
821
  const user = { id: userId, role: userRole };
808
- if (!hasPermission(user, "content:publish_any" as Permission)) {
822
+ if (!hasPermission(user, "content:publish_any")) {
809
823
  throw new EmDashAuthError(
810
824
  "Setting publishedAt requires content:publish_any permission",
811
825
  "INSUFFICIENT_PERMISSIONS",
@@ -823,6 +837,7 @@ export function createMcpServer(): McpServer {
823
837
  args.slug ||
824
838
  args.seo !== undefined ||
825
839
  args.bylines !== undefined ||
840
+ args.taxonomies !== undefined ||
826
841
  args.publishedAt !== undefined
827
842
  ) {
828
843
  const updateResult = await emdash.handleContentUpdate(args.collection, resolvedId, {
@@ -832,6 +847,7 @@ export function createMcpServer(): McpServer {
832
847
  locale: args.locale,
833
848
  seo: args.seo,
834
849
  bylines: args.bylines,
850
+ taxonomies: args.taxonomies,
835
851
  publishedAt: args.publishedAt,
836
852
  _rev: args._rev,
837
853
  });
@@ -847,6 +863,7 @@ export function createMcpServer(): McpServer {
847
863
  args.slug ||
848
864
  args.seo !== undefined ||
849
865
  args.bylines !== undefined ||
866
+ args.taxonomies !== undefined ||
850
867
  args.publishedAt !== undefined
851
868
  ) {
852
869
  const updateResult = await emdash.handleContentUpdate(args.collection, resolvedId, {
@@ -856,6 +873,7 @@ export function createMcpServer(): McpServer {
856
873
  locale: args.locale,
857
874
  seo: args.seo,
858
875
  bylines: args.bylines,
876
+ taxonomies: args.taxonomies,
859
877
  publishedAt: args.publishedAt,
860
878
  _rev: args._rev,
861
879
  });
@@ -872,6 +890,7 @@ export function createMcpServer(): McpServer {
872
890
  locale: args.locale,
873
891
  seo: args.seo,
874
892
  bylines: args.bylines,
893
+ taxonomies: args.taxonomies,
875
894
  publishedAt: args.publishedAt,
876
895
  _rev: args._rev,
877
896
  }),
@@ -1008,7 +1027,7 @@ export function createMcpServer(): McpServer {
1008
1027
  // regardless of ownership (mirrors the REST PUT route's publishedAt gate).
1009
1028
  if (args.publishedAt !== undefined) {
1010
1029
  const user = { id: userId, role: userRole };
1011
- if (!hasPermission(user, "content:publish_any" as Permission)) {
1030
+ if (!hasPermission(user, "content:publish_any")) {
1012
1031
  throw new EmDashAuthError(
1013
1032
  "Setting publishedAt requires content:publish_any permission",
1014
1033
  "INSUFFICIENT_PERMISSIONS",
@@ -1932,6 +1951,12 @@ export function createMcpServer(): McpServer {
1932
1951
  .optional()
1933
1952
  .describe("Filter results by locale (omit to search all locales)"),
1934
1953
  limit: z.number().int().min(1).max(50).optional().describe("Max results (default 20)"),
1954
+ cursor: z
1955
+ .string()
1956
+ .min(1)
1957
+ .max(2048)
1958
+ .optional()
1959
+ .describe("Pagination cursor from a previous response"),
1935
1960
  }),
1936
1961
  annotations: { readOnlyHint: true },
1937
1962
  },
@@ -1944,6 +1969,7 @@ export function createMcpServer(): McpServer {
1944
1969
  collections: args.collections,
1945
1970
  locale: args.locale,
1946
1971
  limit: args.limit,
1972
+ cursor: args.cursor,
1947
1973
  });
1948
1974
  return jsonResult(results);
1949
1975
  } catch (error) {
@@ -13,6 +13,7 @@ import { MediaRepository } from "../database/repositories/media.js";
13
13
  import { OptionsRepository } from "../database/repositories/options.js";
14
14
  import { PluginStorageRepository } from "../database/repositories/plugin-storage.js";
15
15
  import { SeoRepository } from "../database/repositories/seo.js";
16
+ import { TaxonomyRepository, type Taxonomy } from "../database/repositories/taxonomy.js";
16
17
  import { UserRepository } from "../database/repositories/user.js";
17
18
  import { withTransaction } from "../database/transaction.js";
18
19
  import type { Database } from "../database/types.js";
@@ -52,6 +53,10 @@ import type {
52
53
  QueryOptions,
53
54
  ContentListOptions,
54
55
  MediaListOptions,
56
+ TaxonomyAccess,
57
+ TaxonomyDefInfo,
58
+ TaxonomyTermInfo,
59
+ TaxonomyReadOptions,
55
60
  } from "./types.js";
56
61
 
57
62
  // =============================================================================
@@ -194,6 +199,37 @@ async function assertSeoEnabled(
194
199
  return hasSeo;
195
200
  }
196
201
 
202
+ /**
203
+ * Parse the `collections` JSON column into a string array (`[]` on anything
204
+ * else). Mirrors the guards in the Cloudflare/workerd bridges so an
205
+ * in-process plugin degrades on malformed data instead of crashing.
206
+ */
207
+ function parseCollectionsColumn(value: string | null): string[] {
208
+ if (!value) return [];
209
+ try {
210
+ const parsed: unknown = JSON.parse(value);
211
+ return Array.isArray(parsed)
212
+ ? parsed.filter((item): item is string => typeof item === "string")
213
+ : [];
214
+ } catch {
215
+ return [];
216
+ }
217
+ }
218
+
219
+ /** Map a repository `Taxonomy` row to the plugin-facing term shape. */
220
+ function taxonomyToTermInfo(term: Taxonomy): TaxonomyTermInfo {
221
+ return {
222
+ id: term.id,
223
+ taxonomy: term.name,
224
+ slug: term.slug,
225
+ label: term.label,
226
+ parentId: term.parentId,
227
+ data: term.data,
228
+ locale: term.locale,
229
+ translationGroup: term.translationGroup,
230
+ };
231
+ }
232
+
197
233
  /**
198
234
  * Create read-only content access
199
235
  */
@@ -278,6 +314,48 @@ export function createContentAccess(db: Kysely<Database>): ContentAccess {
278
314
  };
279
315
  }
280
316
 
317
+ /**
318
+ * Create read-only taxonomy access (gated on `taxonomies:read`).
319
+ */
320
+ export function createTaxonomyAccess(db: Kysely<Database>): TaxonomyAccess {
321
+ const taxonomyRepo = new TaxonomyRepository(db);
322
+
323
+ return {
324
+ async getAll(options?: TaxonomyReadOptions): Promise<TaxonomyDefInfo[]> {
325
+ let query = db.selectFrom("_emdash_taxonomy_defs").selectAll();
326
+ if (options?.locale !== undefined) query = query.where("locale", "=", options.locale);
327
+ const rows = await query.orderBy("name", "asc").execute();
328
+ return rows.map((row) => ({
329
+ name: row.name,
330
+ label: row.label,
331
+ labelSingular: row.label_singular,
332
+ hierarchical: row.hierarchical === 1,
333
+ collections: parseCollectionsColumn(row.collections),
334
+ locale: row.locale,
335
+ }));
336
+ },
337
+
338
+ async getTerms(taxonomy: string, options?: TaxonomyReadOptions): Promise<TaxonomyTermInfo[]> {
339
+ const terms = await taxonomyRepo.findByName(taxonomy, { locale: options?.locale });
340
+ return terms.map(taxonomyToTermInfo);
341
+ },
342
+
343
+ async getEntryTerms(
344
+ collection: string,
345
+ entryId: string,
346
+ options?: TaxonomyReadOptions & { taxonomy?: string },
347
+ ): Promise<TaxonomyTermInfo[]> {
348
+ const terms = await taxonomyRepo.getTermsForEntry(
349
+ collection,
350
+ entryId,
351
+ options?.taxonomy,
352
+ options?.locale,
353
+ );
354
+ return terms.map(taxonomyToTermInfo);
355
+ },
356
+ };
357
+ }
358
+
281
359
  /**
282
360
  * Create full content access with write operations.
283
361
  *
@@ -1015,6 +1093,12 @@ export class PluginContextFactory {
1015
1093
  content = createContentAccess(db);
1016
1094
  }
1017
1095
 
1096
+ // Capability-gated: taxonomies (read-only)
1097
+ let taxonomies: TaxonomyAccess | undefined;
1098
+ if (capabilities.has("taxonomies:read")) {
1099
+ taxonomies = createTaxonomyAccess(db);
1100
+ }
1101
+
1018
1102
  // Capability-gated: media
1019
1103
  // `upload()` only needs `storage`; `getUploadUrl()` is derived from
1020
1104
  // storage when no explicit provider is wired. Granting write access on
@@ -1078,6 +1162,7 @@ export class PluginContextFactory {
1078
1162
  storage,
1079
1163
  kv,
1080
1164
  content,
1165
+ taxonomies,
1081
1166
  media,
1082
1167
  http,
1083
1168
  log,
@@ -142,6 +142,7 @@ function defineNativePlugin<TStorage extends PluginStorageConfig>(
142
142
  "network:request:unrestricted",
143
143
  "content:read",
144
144
  "content:write",
145
+ "taxonomies:read",
145
146
  "media:read",
146
147
  "media:write",
147
148
  "users:read",
@@ -118,6 +118,10 @@ export type {
118
118
  MediaItem,
119
119
  ContentListOptions,
120
120
  MediaListOptions,
121
+ TaxonomyAccess,
122
+ TaxonomyDefInfo,
123
+ TaxonomyTermInfo,
124
+ TaxonomyReadOptions,
121
125
 
122
126
  // Hook types
123
127
  PluginHooks,
@@ -27,6 +27,7 @@ export const CURRENT_PLUGIN_CAPABILITIES = [
27
27
  "network:request:unrestricted",
28
28
  "content:read",
29
29
  "content:write",
30
+ "taxonomies:read",
30
31
  "media:read",
31
32
  "media:write",
32
33
  "users:read",
@@ -246,6 +247,7 @@ const declaredAccessSchema = z.object({
246
247
  content: z
247
248
  .object({ read: accessConstraints.optional(), write: accessConstraints.optional() })
248
249
  .optional(),
250
+ taxonomies: z.object({ read: accessConstraints.optional() }).optional(),
249
251
  media: z
250
252
  .object({ read: accessConstraints.optional(), write: accessConstraints.optional() })
251
253
  .optional(),
@@ -244,6 +244,45 @@ export type ContentWriteInput = Record<string, unknown> & {
244
244
  seo?: ContentItemSeoInput;
245
245
  };
246
246
 
247
+ /**
248
+ * Taxonomy definition returned from the taxonomy API (e.g. "category", "tag").
249
+ */
250
+ export interface TaxonomyDefInfo {
251
+ name: string;
252
+ label: string;
253
+ labelSingular: string | null;
254
+ hierarchical: boolean;
255
+ /** Collections this taxonomy is attached to (e.g. `["posts"]`). */
256
+ collections: string[];
257
+ locale: string;
258
+ }
259
+
260
+ /**
261
+ * Taxonomy term returned from the taxonomy API. Flat shape — for hierarchical
262
+ * taxonomies the tree is reconstructed via `parentId` (which stores the
263
+ * parent's locale-agnostic `translationGroup`).
264
+ */
265
+ export interface TaxonomyTermInfo {
266
+ id: string;
267
+ /** Taxonomy name this term belongs to (e.g. "category"). */
268
+ taxonomy: string;
269
+ slug: string;
270
+ label: string;
271
+ parentId: string | null;
272
+ /** Term metadata as edited in the admin (`description` etc.). */
273
+ data: Record<string, unknown> | null;
274
+ locale: string;
275
+ translationGroup: string | null;
276
+ }
277
+
278
+ /**
279
+ * Options accepted by taxonomy read operations. Omitting `locale` returns
280
+ * rows for every locale.
281
+ */
282
+ export interface TaxonomyReadOptions {
283
+ locale?: string;
284
+ }
285
+
247
286
  /**
248
287
  * Content access interface - capability-gated
249
288
  */
@@ -258,6 +297,23 @@ export interface ContentAccess {
258
297
  delete?(collection: string, id: string): Promise<boolean>;
259
298
  }
260
299
 
300
+ /**
301
+ * Taxonomy access interface — capability-gated on `taxonomies:read`.
302
+ * Read-only: there is no plugin-facing taxonomy write API.
303
+ */
304
+ export interface TaxonomyAccess {
305
+ /** List taxonomy definitions. */
306
+ getAll(options?: TaxonomyReadOptions): Promise<TaxonomyDefInfo[]>;
307
+ /** All terms of a taxonomy, ordered by label. */
308
+ getTerms(taxonomy: string, options?: TaxonomyReadOptions): Promise<TaxonomyTermInfo[]>;
309
+ /** Terms assigned to a content entry, optionally scoped to one taxonomy. */
310
+ getEntryTerms(
311
+ collection: string,
312
+ entryId: string,
313
+ options?: TaxonomyReadOptions & { taxonomy?: string },
314
+ ): Promise<TaxonomyTermInfo[]>;
315
+ }
316
+
261
317
  /**
262
318
  * Full content access with write operations
263
319
  */
@@ -413,6 +469,9 @@ export interface PluginContext<TStorage extends PluginStorageConfig = PluginStor
413
469
  /** Content access - only if read:content or write:content capability */
414
470
  content?: ContentAccess | ContentAccessWithWrite;
415
471
 
472
+ /** Taxonomy access (read-only) - only if taxonomies:read capability */
473
+ taxonomies?: TaxonomyAccess;
474
+
416
475
  /** Media access - only if read:media or write:media capability */
417
476
  media?: MediaAccess | MediaAccessWithWrite;
418
477
 
@@ -627,7 +627,7 @@ export class BylineSchemaRegistry {
627
627
  // payload silently. Today's `BylineFieldValidation` is `{ options? }`
628
628
  // only, so this branch is a pass-through; left explicit for clarity.
629
629
  const { options: _drop, ...rest } = validation;
630
- return Object.keys(rest).length === 0 ? null : (rest as BylineFieldValidation);
630
+ return Object.keys(rest).length === 0 ? null : rest;
631
631
  }
632
632
  }
633
633
 
@@ -355,6 +355,40 @@ export class FTSManager {
355
355
  return fields.map((f) => f.slug);
356
356
  }
357
357
 
358
+ /**
359
+ * Whether a collection has a user-defined `title` field.
360
+ *
361
+ * `title` is not a system column on `ec_*` tables -- it exists only when a
362
+ * collection defines a field with slug `title`. Search and suggestion SQL
363
+ * that selects `c.title` must check this first; otherwise collections
364
+ * without a title field raise "no such column: c.title" (#1178).
365
+ */
366
+ async hasTitleColumn(collectionSlug: string): Promise<boolean> {
367
+ const withTitle = await this.getCollectionsWithTitleColumn([collectionSlug]);
368
+ return withTitle.has(collectionSlug);
369
+ }
370
+
371
+ /**
372
+ * Bulk variant of `hasTitleColumn()`: which of the given collections have
373
+ * a user-defined `title` field. One query instead of one `hasTitleColumn`
374
+ * round-trip pair per collection -- callers that check this once per
375
+ * collection in a loop (multi-collection search, suggestions) should use
376
+ * this instead (AGENTS.md: "one query beats two").
377
+ */
378
+ async getCollectionsWithTitleColumn(collectionSlugs: string[]): Promise<Set<string>> {
379
+ if (collectionSlugs.length === 0) return new Set();
380
+
381
+ const rows = await this.db
382
+ .selectFrom("_emdash_fields as f")
383
+ .innerJoin("_emdash_collections as c", "c.id", "f.collection_id")
384
+ .select(["c.slug as collection_slug"])
385
+ .where("f.slug", "=", "title")
386
+ .execute();
387
+
388
+ const withTitle = new Set(rows.map((r) => r.collection_slug));
389
+ return new Set(collectionSlugs.filter((slug) => withTitle.has(slug)));
390
+ }
391
+
358
392
  /**
359
393
  * Enable search for a collection.
360
394
  *
@@ -0,0 +1,50 @@
1
+ /**
2
+ * FTS5 match-expression builder for structured (non-user-syntax) queries.
3
+ *
4
+ * Unlike `escapeQuery` in `query.ts` (which powers the public search API and
5
+ * deliberately passes through FTS5 operators like AND/OR/NOT), this builder
6
+ * treats the input as plain words: every term is double-quoted with interior
7
+ * quotes escaped, so the result can never produce an FTS5 syntax error. Used
8
+ * by the admin content-list filter, where the input is a filter box, not a
9
+ * search-syntax field.
10
+ */
11
+
12
+ const WHITESPACE_RE = /\s+/;
13
+ const DOUBLE_QUOTE_RE = /"/g;
14
+ const GLOB_SPECIAL_RE = /[[\]*?]/g;
15
+
16
+ /**
17
+ * Build a prefix-matching FTS5 MATCH expression from free-form input.
18
+ *
19
+ * `hello wor` becomes `"hello"* "wor"*` — implicit AND with per-term prefix
20
+ * matching. Returns `""` when the input contains no usable terms; callers
21
+ * must fall back to their non-FTS path in that case.
22
+ */
23
+ export function buildFtsPrefixMatch(input: string): string {
24
+ const terms = input
25
+ .trim()
26
+ .split(WHITESPACE_RE)
27
+ .map((term) => term.replace(DOUBLE_QUOTE_RE, '""'))
28
+ .filter((term) => term.length > 0);
29
+
30
+ if (terms.length === 0) return "";
31
+ return terms.map((term) => `"${term}"*`).join(" ");
32
+ }
33
+
34
+ /**
35
+ * Build a GLOB prefix pattern from free-form input, treating GLOB
36
+ * metacharacters (`* ? [ ]`) literally by wrapping each in a character
37
+ * class (GLOB has no ESCAPE clause).
38
+ *
39
+ * GLOB (unlike default LIKE) is case-sensitive, so with a lowercased
40
+ * pattern it matches slugs (lowercase by construction) while staying
41
+ * servable by the ordinary BINARY-collated slug index — SQLite's GLOB
42
+ * optimization turns a `prefix*` pattern into an index range scan.
43
+ */
44
+ export function buildSlugGlobPrefix(input: string): string {
45
+ const escaped = input
46
+ .trim()
47
+ .toLowerCase()
48
+ .replace(GLOB_SPECIAL_RE, (c) => `[${c}]`);
49
+ return `${escaped}*`;
50
+ }