emdash 0.37.0 → 0.38.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 (811) hide show
  1. package/dist/{activation-K0kGBWuJ.mjs → activation-DyNTe_Tl.mjs} +3 -3
  2. package/dist/{activation-K0kGBWuJ.mjs.map → activation-DyNTe_Tl.mjs.map} +1 -1
  3. package/dist/{adapters-BDQwg236.d.mts → adapters-DCEgOBXi.d.mts} +1 -1
  4. package/dist/{adapters-BDQwg236.d.mts.map → adapters-DCEgOBXi.d.mts.map} +1 -1
  5. package/dist/{allowed-origins-BGglilcs.mjs → allowed-origins-GFUVavRj.mjs} +2 -2
  6. package/dist/{allowed-origins-BGglilcs.mjs.map → allowed-origins-GFUVavRj.mjs.map} +1 -1
  7. package/dist/api/route-utils.d.mts +3 -3
  8. package/dist/api/route-utils.mjs +23 -22
  9. package/dist/api/route-utils.mjs.map +1 -1
  10. package/dist/api/schemas/index.d.mts +2 -2
  11. package/dist/api/schemas/index.mjs +5 -5
  12. package/dist/{api-Dz6rgoa3.mjs → api-BvxJmnFY.mjs} +141 -87
  13. package/dist/api-BvxJmnFY.mjs.map +1 -0
  14. package/dist/{api-tokens-BSsQACNe.mjs → api-tokens-xpGqMHrC.mjs} +2 -2
  15. package/dist/{api-tokens-BSsQACNe.mjs.map → api-tokens-xpGqMHrC.mjs.map} +1 -1
  16. package/dist/{apply-B4SIOxR1.mjs → apply-DLmM3R7f.mjs} +25 -21
  17. package/dist/apply-DLmM3R7f.mjs.map +1 -0
  18. package/dist/{config-it29yDLA.mjs → artifact-fetch-P2JXVwOq.mjs} +8 -199
  19. package/dist/artifact-fetch-P2JXVwOq.mjs.map +1 -0
  20. package/dist/astro/index.d.mts +12 -12
  21. package/dist/astro/index.d.mts.map +1 -1
  22. package/dist/astro/index.mjs +37 -11
  23. package/dist/astro/index.mjs.map +1 -1
  24. package/dist/astro/middleware/auth.d.mts +10 -10
  25. package/dist/astro/middleware/auth.mjs +6 -6
  26. package/dist/astro/middleware/media-usage-write-fence.mjs +3 -3
  27. package/dist/astro/middleware/redirect.mjs +7 -5
  28. package/dist/astro/middleware/redirect.mjs.map +1 -1
  29. package/dist/astro/middleware/request-context.mjs +3 -3
  30. package/dist/astro/middleware/setup.mjs +1 -1
  31. package/dist/astro/middleware.d.mts +10 -10
  32. package/dist/astro/middleware.d.mts.map +1 -1
  33. package/dist/astro/middleware.mjs +154 -125
  34. package/dist/astro/middleware.mjs.map +1 -1
  35. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
  36. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
  37. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
  38. package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
  39. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  40. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
  41. package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
  42. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
  43. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +16 -16
  44. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
  45. package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
  46. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
  47. package/dist/astro/routes/api/admin/comments/_id_.mjs +3 -3
  48. package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
  49. package/dist/astro/routes/api/admin/comments/counts.mjs +3 -3
  50. package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
  51. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  52. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  53. package/dist/astro/routes/api/admin/media-usage/activation.mjs +13 -13
  54. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +15 -15
  55. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +15 -15
  56. package/dist/astro/routes/api/admin/media-usage/progress.mjs +13 -13
  57. package/dist/astro/routes/api/admin/media-usage/repair.mjs +16 -16
  58. package/dist/astro/routes/api/admin/media-usage/work/index.mjs +15 -15
  59. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +15 -15
  60. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  61. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  62. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -53
  63. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +56 -53
  65. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  66. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +54 -51
  67. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  68. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
  69. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +54 -51
  70. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +55 -52
  72. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +55 -52
  74. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  75. package/dist/astro/routes/api/admin/plugins/index.mjs +54 -51
  76. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  77. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  78. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +54 -51
  79. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +55 -52
  81. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +54 -51
  83. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +55 -52
  85. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +56 -53
  87. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +5 -4
  89. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +56 -53
  91. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +55 -52
  93. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/plugins/updates.mjs +54 -51
  95. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +54 -51
  97. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  98. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  99. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +54 -51
  100. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  101. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
  102. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  103. package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
  104. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  105. package/dist/astro/routes/api/admin/users/index.mjs +6 -6
  106. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  107. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  108. package/dist/astro/routes/api/auth/invite/complete.mjs +11 -11
  109. package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
  110. package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
  111. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  112. package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
  113. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  114. package/dist/astro/routes/api/auth/me.mjs +7 -7
  115. package/dist/astro/routes/api/auth/mode.mjs +2 -2
  116. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  117. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  118. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
  119. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  120. package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
  121. package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
  122. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
  123. package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
  124. package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
  125. package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
  126. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  127. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
  128. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +11 -11
  129. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  130. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
  131. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +13 -8
  132. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  133. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  134. package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts +10 -0
  135. package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts.map +1 -0
  136. package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +66 -0
  137. package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs.map +1 -0
  138. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
  139. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
  140. package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -1
  141. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +14 -9
  142. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  143. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +19 -17
  144. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  145. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +19 -17
  146. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  147. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  148. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  149. package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
  150. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +15 -8
  151. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  152. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +15 -14
  153. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  154. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  155. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
  156. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +13 -8
  157. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  158. package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
  159. package/dist/astro/routes/api/content/_collection_/_id_.mjs +23 -11
  160. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  161. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  162. package/dist/astro/routes/api/content/_collection_/index.mjs +14 -9
  163. package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
  164. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
  165. package/dist/astro/routes/api/dashboard.mjs +6 -6
  166. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  167. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  168. package/dist/astro/routes/api/import/probe.mjs +16 -16
  169. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  170. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
  171. package/dist/astro/routes/api/import/wordpress/execute.mjs +14 -13
  172. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  173. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
  174. package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
  175. package/dist/astro/routes/api/import/wordpress/prepare.mjs +10 -10
  176. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
  177. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +13 -13
  178. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  179. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +16 -16
  180. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
  181. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +27 -26
  182. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  183. package/dist/astro/routes/api/manifest.mjs +4 -4
  184. package/dist/astro/routes/api/mcp.mjs +71 -55
  185. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  186. package/dist/astro/routes/api/media/_id_/confirm.mjs +10 -10
  187. package/dist/astro/routes/api/media/_id_/replace.mjs +8 -8
  188. package/dist/astro/routes/api/media/_id_/upload.mjs +5 -5
  189. package/dist/astro/routes/api/media/_id_/usage.mjs +18 -18
  190. package/dist/astro/routes/api/media/_id_.mjs +17 -17
  191. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  192. package/dist/astro/routes/api/media/folders/_id_.mjs +8 -8
  193. package/dist/astro/routes/api/media/folders/index.mjs +8 -8
  194. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  195. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  196. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  197. package/dist/astro/routes/api/media/upload-url.mjs +9 -9
  198. package/dist/astro/routes/api/media.mjs +21 -21
  199. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
  200. package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
  201. package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
  202. package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
  203. package/dist/astro/routes/api/menus/_name_.mjs +9 -9
  204. package/dist/astro/routes/api/menus/index.mjs +9 -9
  205. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  206. package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
  207. package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
  208. package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
  209. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  210. package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
  211. package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
  212. package/dist/astro/routes/api/oauth/token.mjs +5 -5
  213. package/dist/astro/routes/api/openapi.json.mjs +84 -18
  214. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  215. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  216. package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
  217. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  218. package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
  219. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  220. package/dist/astro/routes/api/redirects/_id_.mjs +13 -12
  221. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  222. package/dist/astro/routes/api/redirects/index.mjs +13 -12
  223. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  224. package/dist/astro/routes/api/relations/_id_/index.mjs +19 -17
  225. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  226. package/dist/astro/routes/api/relations/_id_/translations.mjs +14 -12
  227. package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
  228. package/dist/astro/routes/api/relations/index.mjs +19 -17
  229. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  230. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  231. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  232. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +54 -51
  233. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  234. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +54 -51
  235. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  236. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +54 -51
  237. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  238. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +54 -51
  239. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  240. package/dist/astro/routes/api/schema/collections/index.mjs +54 -51
  241. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  242. package/dist/astro/routes/api/schema/collections/reorder.mjs +54 -51
  243. package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
  244. package/dist/astro/routes/api/schema/index.mjs +13 -11
  245. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  246. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +54 -51
  247. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  248. package/dist/astro/routes/api/schema/orphans/index.mjs +54 -51
  249. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  250. package/dist/astro/routes/api/search/enable.mjs +12 -11
  251. package/dist/astro/routes/api/search/enable.mjs.map +1 -1
  252. package/dist/astro/routes/api/search/index.mjs +11 -10
  253. package/dist/astro/routes/api/search/index.mjs.map +1 -1
  254. package/dist/astro/routes/api/search/rebuild.mjs +12 -11
  255. package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
  256. package/dist/astro/routes/api/search/stats.mjs +7 -6
  257. package/dist/astro/routes/api/search/stats.mjs.map +1 -1
  258. package/dist/astro/routes/api/search/suggest.mjs +11 -10
  259. package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
  260. package/dist/astro/routes/api/sections/_slug_.mjs +11 -10
  261. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  262. package/dist/astro/routes/api/sections/index.mjs +11 -10
  263. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  264. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -6
  265. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs.map +1 -1
  266. package/dist/astro/routes/api/settings/backups/archives/index.mjs +6 -5
  267. package/dist/astro/routes/api/settings/backups/archives/index.mjs.map +1 -1
  268. package/dist/astro/routes/api/settings/backups/export.mjs +7 -6
  269. package/dist/astro/routes/api/settings/backups/export.mjs.map +1 -1
  270. package/dist/astro/routes/api/settings/backups/index.mjs +8 -7
  271. package/dist/astro/routes/api/settings/backups/index.mjs.map +1 -1
  272. package/dist/astro/routes/api/settings/email.mjs +4 -4
  273. package/dist/astro/routes/api/settings.mjs +14 -14
  274. package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
  275. package/dist/astro/routes/api/setup/admin.mjs +11 -11
  276. package/dist/astro/routes/api/setup/dev-bypass.mjs +33 -31
  277. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  278. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  279. package/dist/astro/routes/api/setup/index.mjs +33 -31
  280. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  281. package/dist/astro/routes/api/setup/status.mjs +3 -3
  282. package/dist/astro/routes/api/snapshot.mjs +8 -7
  283. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  284. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +16 -15
  285. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
  286. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +16 -15
  287. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  288. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +16 -15
  289. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  290. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +16 -15
  291. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  292. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +15 -14
  293. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -1
  294. package/dist/astro/routes/api/taxonomies/_name_.mjs +16 -15
  295. package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
  296. package/dist/astro/routes/api/taxonomies/index.mjs +16 -15
  297. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  298. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  299. package/dist/astro/routes/api/typegen.mjs +4 -4
  300. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  301. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  302. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  303. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +8 -8
  304. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +12 -12
  305. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +12 -12
  306. package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -7
  307. package/dist/astro/routes/api/widget-areas/index.mjs +12 -12
  308. package/dist/astro/routes/api/widget-components.mjs +2 -2
  309. package/dist/astro/routes/robots.txt.mjs +6 -6
  310. package/dist/astro/routes/sitemap-_collection_.xml.mjs +11 -10
  311. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  312. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  313. package/dist/astro/types.d.mts +32 -17
  314. package/dist/astro/types.d.mts.map +1 -1
  315. package/dist/auth/providers/github.d.mts +1 -1
  316. package/dist/auth/providers/google.d.mts +1 -1
  317. package/dist/{authorize-Bkf_UHhD.mjs → authorize-C2QHlWSS.mjs} +2 -2
  318. package/dist/{authorize-Bkf_UHhD.mjs.map → authorize-C2QHlWSS.mjs.map} +1 -1
  319. package/dist/{backup-rwVAl9NI.mjs → backup-oS8ft5Cm.mjs} +5 -5
  320. package/dist/{backup-rwVAl9NI.mjs.map → backup-oS8ft5Cm.mjs.map} +1 -1
  321. package/dist/{bundle-C8S2Zl6U.mjs → bundle-CL0JjIPx.mjs} +4 -4
  322. package/dist/{bundle-C8S2Zl6U.mjs.map → bundle-CL0JjIPx.mjs.map} +1 -1
  323. package/dist/{byline-DuhF7NWl.mjs → byline-Vdi85CsZ.mjs} +6 -6
  324. package/dist/{byline-DuhF7NWl.mjs.map → byline-Vdi85CsZ.mjs.map} +1 -1
  325. package/dist/{byline-fields-BovY4KYM.mjs → byline-fields-DPVRFMz2.mjs} +2 -2
  326. package/dist/{byline-fields-BovY4KYM.mjs.map → byline-fields-DPVRFMz2.mjs.map} +1 -1
  327. package/dist/{byline-registry-Bpu9-MVs.mjs → byline-registry-BxDGIO0I.mjs} +2 -2
  328. package/dist/{byline-registry-Bpu9-MVs.mjs.map → byline-registry-BxDGIO0I.mjs.map} +1 -1
  329. package/dist/{bylines-CJ5nd6Lw.mjs → bylines-BX8QhcTk.mjs} +7 -7
  330. package/dist/{bylines-CJ5nd6Lw.mjs.map → bylines-BX8QhcTk.mjs.map} +1 -1
  331. package/dist/{bylines-RwBAeOF1.mjs → bylines-w-E1IEQd.mjs} +3 -3
  332. package/dist/{bylines-RwBAeOF1.mjs.map → bylines-w-E1IEQd.mjs.map} +1 -1
  333. package/dist/{cache-BF5Kvn59.mjs → cache--7HKu5Xm.mjs} +4 -4
  334. package/dist/{cache-BF5Kvn59.mjs.map → cache--7HKu5Xm.mjs.map} +1 -1
  335. package/dist/{capture-triggers-CNW1q3HK.mjs → capture-triggers-CeAsC76Z.mjs} +2 -2
  336. package/dist/{capture-triggers-CNW1q3HK.mjs.map → capture-triggers-CeAsC76Z.mjs.map} +1 -1
  337. package/dist/{challenge-store-DQN_Yrck.mjs → challenge-store-BIOak-tp.mjs} +1 -1
  338. package/dist/{challenge-store-DQN_Yrck.mjs.map → challenge-store-BIOak-tp.mjs.map} +1 -1
  339. package/dist/{chrome-tags-D8fiZG94.mjs → chrome-tags-DzDQBCjX.mjs} +1 -1
  340. package/dist/{chrome-tags-D8fiZG94.mjs.map → chrome-tags-DzDQBCjX.mjs.map} +1 -1
  341. package/dist/{chunks-C4szrD8o.mjs → chunks-VG_tyqnP.mjs} +2 -2
  342. package/dist/{chunks-C4szrD8o.mjs.map → chunks-VG_tyqnP.mjs.map} +1 -1
  343. package/dist/cli/index.mjs +66 -38
  344. package/dist/cli/index.mjs.map +1 -1
  345. package/dist/client/cf-access.d.mts +1 -1
  346. package/dist/client/index.d.mts +17 -7
  347. package/dist/client/index.d.mts.map +1 -1
  348. package/dist/client/index.mjs +17 -12
  349. package/dist/client/index.mjs.map +1 -1
  350. package/dist/{collection-deletion-Bj07NHbj.mjs → collection-deletion-BCwaWTDw.mjs} +4 -4
  351. package/dist/{collection-deletion-Bj07NHbj.mjs.map → collection-deletion-BCwaWTDw.mjs.map} +1 -1
  352. package/dist/collection-slugs-cache-7lTmNzeA.mjs +85 -0
  353. package/dist/collection-slugs-cache-7lTmNzeA.mjs.map +1 -0
  354. package/dist/{comment-reaction-BhrvSHml.mjs → comment-reaction-CDyvPQRj.mjs} +2 -2
  355. package/dist/{comment-reaction-BhrvSHml.mjs.map → comment-reaction-CDyvPQRj.mjs.map} +1 -1
  356. package/dist/{comments-Ct4ensnf.mjs → comments-VzmVLyaC.mjs} +1 -1
  357. package/dist/{comments-Ct4ensnf.mjs.map → comments-VzmVLyaC.mjs.map} +1 -1
  358. package/dist/{components-DJbo1z0S.mjs → components-CL6Wkdk-.mjs} +1 -1
  359. package/dist/{components-DJbo1z0S.mjs.map → components-CL6Wkdk-.mjs.map} +1 -1
  360. package/dist/config--eWjQJE5.mjs +217 -0
  361. package/dist/config--eWjQJE5.mjs.map +1 -0
  362. package/dist/{index-BJNMCWmu.d.mts → config-CGAhyOjP.d.mts} +138 -47
  363. package/dist/config-CGAhyOjP.d.mts.map +1 -0
  364. package/dist/{config-B9eZ340f.d.mts → config-ChFzshGd.d.mts} +1 -1
  365. package/dist/{config-B9eZ340f.d.mts.map → config-ChFzshGd.d.mts.map} +1 -1
  366. package/dist/{content-DjvM0T92.mjs → content-CNfMWuhY.mjs} +121 -5
  367. package/dist/content-CNfMWuhY.mjs.map +1 -0
  368. package/dist/{content-list-query-Btqd4uV2.d.mts → content-list-query-B8d4UQp9.d.mts} +1 -1
  369. package/dist/{content-list-query-Btqd4uV2.d.mts.map → content-list-query-B8d4UQp9.d.mts.map} +1 -1
  370. package/dist/{content-refresh-Bwp-8yGy.mjs → content-refresh-GTMyi2Xy.mjs} +8 -8
  371. package/dist/{content-refresh-Bwp-8yGy.mjs.map → content-refresh-GTMyi2Xy.mjs.map} +1 -1
  372. package/dist/{content-repair-Czdp7jz5.mjs → content-repair-CIMt5C0U.mjs} +4 -4
  373. package/dist/{content-repair-Czdp7jz5.mjs.map → content-repair-CIMt5C0U.mjs.map} +1 -1
  374. package/dist/{context-CX6gxOLW.mjs → context-C9PB8vGd.mjs} +265 -25
  375. package/dist/context-C9PB8vGd.mjs.map +1 -0
  376. package/dist/{cron-C6o7VppJ.mjs → cron-DHAy9oyq.mjs} +1 -1
  377. package/dist/{cron-C6o7VppJ.mjs.map → cron-DHAy9oyq.mjs.map} +1 -1
  378. package/dist/{dashboard-C2kTeeRI.mjs → dashboard-BNSvAN8A.mjs} +4 -4
  379. package/dist/{dashboard-C2kTeeRI.mjs.map → dashboard-BNSvAN8A.mjs.map} +1 -1
  380. package/dist/db/index.d.mts +3 -3
  381. package/dist/db/index.mjs +2 -2
  382. package/dist/db/libsql-migrations.d.mts +1 -1
  383. package/dist/db/libsql-migrations.mjs +5 -5
  384. package/dist/db/libsql.d.mts +1 -1
  385. package/dist/db/postgres-migrations.d.mts +1 -1
  386. package/dist/db/postgres-migrations.mjs +5 -5
  387. package/dist/db/postgres.d.mts +1 -1
  388. package/dist/db/sqlite-migrations.d.mts +1 -1
  389. package/dist/db/sqlite-migrations.mjs +5 -5
  390. package/dist/db/sqlite.d.mts +1 -1
  391. package/dist/db/sqlite.mjs +1 -1
  392. package/dist/{default-Clra32mw.mjs → default-ByZ0JqZo.mjs} +1 -1
  393. package/dist/{default-Clra32mw.mjs.map → default-ByZ0JqZo.mjs.map} +1 -1
  394. package/dist/{deferred-tasks-CvDETTJO.d.mts → deferred-tasks-Cu4NSJpa.d.mts} +1 -1
  395. package/dist/{deferred-tasks-CvDETTJO.d.mts.map → deferred-tasks-Cu4NSJpa.d.mts.map} +1 -1
  396. package/dist/{dev-typegen-DzOPfsNj.mjs → dev-typegen-DHT7lcMU.mjs} +1 -1
  397. package/dist/{dev-typegen-DzOPfsNj.mjs.map → dev-typegen-DHT7lcMU.mjs.map} +1 -1
  398. package/dist/{device-flow-D2oCWvLJ.mjs → device-flow-Cf6bhCCT.mjs} +4 -4
  399. package/dist/{device-flow-D2oCWvLJ.mjs.map → device-flow-Cf6bhCCT.mjs.map} +1 -1
  400. package/dist/{dialect-helpers-BSbfaO3F.mjs → dialect-helpers-BcQvkHgn.mjs} +83 -2
  401. package/dist/dialect-helpers-BcQvkHgn.mjs.map +1 -0
  402. package/dist/{direct-executor-Bfa5_ToE.mjs → direct-executor-yAyUGSqB.mjs} +3 -3
  403. package/dist/{direct-executor-Bfa5_ToE.mjs.map → direct-executor-yAyUGSqB.mjs.map} +1 -1
  404. package/dist/{dist-89xCrGqi.mjs → dist-BAsh8dbf.mjs} +1 -1
  405. package/dist/{dist-89xCrGqi.mjs.map → dist-BAsh8dbf.mjs.map} +1 -1
  406. package/dist/{email-console-Dzb6uGYa.mjs → email-console-DNup1Fku.mjs} +1 -1
  407. package/dist/{email-console-Dzb6uGYa.mjs.map → email-console-DNup1Fku.mjs.map} +1 -1
  408. package/dist/{enrich-BX0IDp4z.mjs → enrich-t2Xvjdqa.mjs} +3 -3
  409. package/dist/{enrich-BX0IDp4z.mjs.map → enrich-t2Xvjdqa.mjs.map} +1 -1
  410. package/dist/entry-lock-BEr8gDkG.mjs +163 -0
  411. package/dist/entry-lock-BEr8gDkG.mjs.map +1 -0
  412. package/dist/{relations-DnRK4YIT.d.mts → entry-lock-CGAtrwAR.d.mts} +92 -37
  413. package/dist/entry-lock-CGAtrwAR.d.mts.map +1 -0
  414. package/dist/{redirects-BLNOWQTn.mjs → entry-lock-DIYHAaSw.mjs} +57 -14
  415. package/dist/entry-lock-DIYHAaSw.mjs.map +1 -0
  416. package/dist/entry-locks-BEcX7ET0.mjs +167 -0
  417. package/dist/entry-locks-BEcX7ET0.mjs.map +1 -0
  418. package/dist/{error-DFrQjppn.mjs → error-BDcFyoRt.mjs} +2 -2
  419. package/dist/{error-DFrQjppn.mjs.map → error-BDcFyoRt.mjs.map} +1 -1
  420. package/dist/{errors-DsVoDUjJ.mjs → errors-DvMdNrgf.mjs} +8 -1
  421. package/dist/errors-DvMdNrgf.mjs.map +1 -0
  422. package/dist/{escape-HmHTC1Is.mjs → escape-B3asJC6W.mjs} +1 -1
  423. package/dist/{escape-HmHTC1Is.mjs.map → escape-B3asJC6W.mjs.map} +1 -1
  424. package/dist/{field-defs-cache-BM4SIRqH.mjs → field-defs-cache-Cf5FHK0M.mjs} +5 -5
  425. package/dist/{field-defs-cache-BM4SIRqH.mjs.map → field-defs-cache-Cf5FHK0M.mjs.map} +1 -1
  426. package/dist/{fts-manager-Do1BlW2r.mjs → fts-manager-iddym8cd.mjs} +4 -4
  427. package/dist/{fts-manager-Do1BlW2r.mjs.map → fts-manager-iddym8cd.mjs.map} +1 -1
  428. package/dist/{hash-3JJPlHF2.mjs → hash-BRweX6jz.mjs} +1 -1
  429. package/dist/{hash-3JJPlHF2.mjs.map → hash-BRweX6jz.mjs.map} +1 -1
  430. package/dist/{hook-result-DCh2WUpe.d.mts → hook-result-BrshYHLx.d.mts} +1 -1
  431. package/dist/{hook-result-DCh2WUpe.d.mts.map → hook-result-BrshYHLx.d.mts.map} +1 -1
  432. package/dist/{hreflang-B6hbAuuO.d.mts → hreflang-CQpu5bMy.d.mts} +2 -2
  433. package/dist/{hreflang-B6hbAuuO.d.mts.map → hreflang-CQpu5bMy.d.mts.map} +1 -1
  434. package/dist/{hreflang-DQbPZliA.mjs → hreflang-DshnweTC.mjs} +9 -8
  435. package/dist/{hreflang-DQbPZliA.mjs.map → hreflang-DshnweTC.mjs.map} +1 -1
  436. package/dist/{identity-DksvEazf.mjs → identity-CjGKDq8J.mjs} +3 -3
  437. package/dist/{identity-DksvEazf.mjs.map → identity-CjGKDq8J.mjs.map} +1 -1
  438. package/dist/{import-CJpaBBBT.mjs → import-D96g2otw.mjs} +5 -5
  439. package/dist/{import-CJpaBBBT.mjs.map → import-D96g2otw.mjs.map} +1 -1
  440. package/dist/{index-Du8K7bWa.d.mts → index-1ECYpfiF.d.mts} +3 -3
  441. package/dist/{index-Du8K7bWa.d.mts.map → index-1ECYpfiF.d.mts.map} +1 -1
  442. package/dist/index.d.mts +22 -22
  443. package/dist/index.mjs +81 -78
  444. package/dist/{init-lock-DJkX6Hto.mjs → init-lock-CFNBe_iH.mjs} +1 -1
  445. package/dist/{init-lock-DJkX6Hto.mjs.map → init-lock-CFNBe_iH.mjs.map} +1 -1
  446. package/dist/{load-CawHjTOH.mjs → load-DPtY9cZo.mjs} +2 -2
  447. package/dist/{load-CawHjTOH.mjs.map → load-DPtY9cZo.mjs.map} +1 -1
  448. package/dist/{loader-Z8vl7zTq.mjs → loader-WJi6GFRn.mjs} +46 -8
  449. package/dist/loader-WJi6GFRn.mjs.map +1 -0
  450. package/dist/{manifest-builder-COtzuca2.mjs → manifest-builder-BfNlGQIA.mjs} +2 -2
  451. package/dist/{manifest-builder-COtzuca2.mjs.map → manifest-builder-BfNlGQIA.mjs.map} +1 -1
  452. package/dist/{manifest-schema-BNWwR8Vd.mjs → manifest-schema-CILooI5J.mjs} +1 -1
  453. package/dist/{manifest-schema-BNWwR8Vd.mjs.map → manifest-schema-CILooI5J.mjs.map} +1 -1
  454. package/dist/media/image-endpoint.mjs +1 -1
  455. package/dist/media/index.d.mts +1 -1
  456. package/dist/media/index.mjs +3 -3
  457. package/dist/media/local-runtime.d.mts +12 -12
  458. package/dist/media/local-runtime.mjs +5 -5
  459. package/dist/{media-BHjus86Y.mjs → media-C1EIZKh1.mjs} +1 -1
  460. package/dist/{media-BHjus86Y.mjs.map → media-C1EIZKh1.mjs.map} +1 -1
  461. package/dist/{media-allowlist-CoTBWoDp.mjs → media-allowlist-elXJgb_K.mjs} +2 -2
  462. package/dist/{media-allowlist-CoTBWoDp.mjs.map → media-allowlist-elXJgb_K.mjs.map} +1 -1
  463. package/dist/{media-folders-BGkATs8n.mjs → media-folders-DASfX_DH.mjs} +1 -1
  464. package/dist/{media-folders-BGkATs8n.mjs.map → media-folders-DASfX_DH.mjs.map} +1 -1
  465. package/dist/{media-upload-BCidR-EY.mjs → media-upload-C7_AQJ5v.mjs} +8 -8
  466. package/dist/{media-upload-BCidR-EY.mjs.map → media-upload-C7_AQJ5v.mjs.map} +1 -1
  467. package/dist/{media-url-DHoPr0hq.mjs → media-url-8dVl1loq.mjs} +19 -2
  468. package/dist/media-url-8dVl1loq.mjs.map +1 -0
  469. package/dist/{media-usage-CdY5jhSR.mjs → media-usage-C1EswMTq.mjs} +9 -9
  470. package/dist/{media-usage-CdY5jhSR.mjs.map → media-usage-C1EswMTq.mjs.map} +1 -1
  471. package/dist/{media-usage-activation-BgeMtK5C.mjs → media-usage-activation-CrHNltlL.mjs} +3 -3
  472. package/dist/{media-usage-activation-BgeMtK5C.mjs.map → media-usage-activation-CrHNltlL.mjs.map} +1 -1
  473. package/dist/{media-usage-work-D6D9sMCA.mjs → media-usage-work-C5B1zT1c.mjs} +2 -2
  474. package/dist/{media-usage-work-D6D9sMCA.mjs.map → media-usage-work-C5B1zT1c.mjs.map} +1 -1
  475. package/dist/{media-usage-work-CnGCdHxx.mjs → media-usage-work-IkQx_Yz6.mjs} +4 -4
  476. package/dist/{media-usage-work-CnGCdHxx.mjs.map → media-usage-work-IkQx_Yz6.mjs.map} +1 -1
  477. package/dist/{media-usage-write-fence-hjeD4u7s.mjs → media-usage-write-fence-B9anjOSg.mjs} +3 -3
  478. package/dist/{media-usage-write-fence-hjeD4u7s.mjs.map → media-usage-write-fence-B9anjOSg.mjs.map} +1 -1
  479. package/dist/{menus-6qSwTNxG.mjs → menus-D8mC4eaN.mjs} +115 -136
  480. package/dist/menus-D8mC4eaN.mjs.map +1 -0
  481. package/dist/{menus-uvPLXMZf.mjs → menus-UdwjHZJC.mjs} +11 -3
  482. package/dist/{menus-uvPLXMZf.mjs.map → menus-UdwjHZJC.mjs.map} +1 -1
  483. package/dist/migrations/index.d.mts +1 -1
  484. package/dist/migrations/index.mjs +4 -4
  485. package/dist/{mime-CUIG6x84.mjs → mime-DYpsOAny.mjs} +1 -1
  486. package/dist/{mime-CUIG6x84.mjs.map → mime-DYpsOAny.mjs.map} +1 -1
  487. package/dist/{mode-DN_WneRx.mjs → mode-Dm4BHhRH.mjs} +1 -1
  488. package/dist/{mode-DN_WneRx.mjs.map → mode-Dm4BHhRH.mjs.map} +1 -1
  489. package/dist/{node-sqlite-compat-BuJXIeMz.mjs → node-sqlite-compat-2sezm-Zd.mjs} +1 -1
  490. package/dist/{node-sqlite-compat-BuJXIeMz.mjs.map → node-sqlite-compat-2sezm-Zd.mjs.map} +1 -1
  491. package/dist/{normalize-C2xNjTSG.mjs → normalize-4nkKGsuW.mjs} +1 -1
  492. package/dist/{normalize-C2xNjTSG.mjs.map → normalize-4nkKGsuW.mjs.map} +1 -1
  493. package/dist/{oauth-authorization-Dj6Kwc21.mjs → oauth-authorization-BxE_lURD.mjs} +4 -4
  494. package/dist/{oauth-authorization-Dj6Kwc21.mjs.map → oauth-authorization-BxE_lURD.mjs.map} +1 -1
  495. package/dist/{oauth-clients-FD7I0J8m.mjs → oauth-clients-DJIdOdq0.mjs} +1 -1
  496. package/dist/{oauth-clients-FD7I0J8m.mjs.map → oauth-clients-DJIdOdq0.mjs.map} +1 -1
  497. package/dist/{oauth-state-store-DkmDOmHs.mjs → oauth-state-store-CsdxP57n.mjs} +1 -1
  498. package/dist/{oauth-state-store-DkmDOmHs.mjs.map → oauth-state-store-CsdxP57n.mjs.map} +1 -1
  499. package/dist/{oauth-user-lookup-CvIwGpYd.mjs → oauth-user-lookup-HzzW-dkF.mjs} +1 -1
  500. package/dist/{oauth-user-lookup-CvIwGpYd.mjs.map → oauth-user-lookup-HzzW-dkF.mjs.map} +1 -1
  501. package/dist/object-cache/memory.d.mts +1 -1
  502. package/dist/{options-BHPeIbBd.mjs → options-D1FBiAv1.mjs} +60 -5
  503. package/dist/options-D1FBiAv1.mjs.map +1 -0
  504. package/dist/{options-CYb4y7hM.d.mts → options-D8Y0VHc7.d.mts} +9 -3
  505. package/dist/options-D8Y0VHc7.d.mts.map +1 -0
  506. package/dist/page/index.d.mts +2 -2
  507. package/dist/page/index.d.mts.map +1 -1
  508. package/dist/page/index.mjs +12 -0
  509. package/dist/page/index.mjs.map +1 -1
  510. package/dist/{parse-Ckpg-Qfp.mjs → parse-WRg5C3NX.mjs} +2 -2
  511. package/dist/{parse-Ckpg-Qfp.mjs.map → parse-WRg5C3NX.mjs.map} +1 -1
  512. package/dist/{passkey-config-O_lj3y0k.mjs → passkey-config-qIdO-wF6.mjs} +1 -1
  513. package/dist/{passkey-config-O_lj3y0k.mjs.map → passkey-config-qIdO-wF6.mjs.map} +1 -1
  514. package/dist/{patterns-D9iDO3j8.mjs → patterns-DC8CLptu.mjs} +1 -1
  515. package/dist/{patterns-D9iDO3j8.mjs.map → patterns-DC8CLptu.mjs.map} +1 -1
  516. package/dist/{placeholder-4X9BrRrp.d.mts → placeholder-COrvARyD.d.mts} +1 -1
  517. package/dist/{placeholder-4X9BrRrp.d.mts.map → placeholder-COrvARyD.d.mts.map} +1 -1
  518. package/dist/plugin-types.d.mts +3 -3
  519. package/dist/plugin-types.d.mts.map +1 -1
  520. package/dist/plugin-utils.d.mts +10 -10
  521. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
  522. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  523. package/dist/{policy-Dhtwntrt.mjs → policy-XCfb-IE9.mjs} +2 -2
  524. package/dist/{policy-Dhtwntrt.mjs.map → policy-XCfb-IE9.mjs.map} +1 -1
  525. package/dist/{portable-text-U85hOafW.mjs → portable-text-BS3d5n-0.mjs} +1 -1
  526. package/dist/{portable-text-U85hOafW.mjs.map → portable-text-BS3d5n-0.mjs.map} +1 -1
  527. package/dist/{preview-B_vJLvf8.mjs → preview-BxwsGgGp.mjs} +2 -2
  528. package/dist/{preview-B_vJLvf8.mjs.map → preview-BxwsGgGp.mjs.map} +1 -1
  529. package/dist/{protocol-JdD2YhY9.d.mts → protocol-CLn58-nw.d.mts} +2 -2
  530. package/dist/{protocol-JdD2YhY9.d.mts.map → protocol-CLn58-nw.d.mts.map} +1 -1
  531. package/dist/{public-url-CarhZJgf.mjs → public-url-FWWAvnre.mjs} +1 -1
  532. package/dist/{public-url-CarhZJgf.mjs.map → public-url-FWWAvnre.mjs.map} +1 -1
  533. package/dist/{query-BZKZcG5b.mjs → query-DygOte9M.mjs} +25 -16
  534. package/dist/query-DygOte9M.mjs.map +1 -0
  535. package/dist/{query-BndaFxxp.mjs → query-gtXT03Wc.mjs} +4 -4
  536. package/dist/{query-BndaFxxp.mjs.map → query-gtXT03Wc.mjs.map} +1 -1
  537. package/dist/{rate-limit-BZmATC6W.mjs → rate-limit-CQUPm0dh.mjs} +2 -2
  538. package/dist/{rate-limit-BZmATC6W.mjs.map → rate-limit-CQUPm0dh.mjs.map} +1 -1
  539. package/dist/{redirect-CzqnLxK-.mjs → redirect-D1cWafi6.mjs} +1 -1
  540. package/dist/{redirect-CzqnLxK-.mjs.map → redirect-D1cWafi6.mjs.map} +1 -1
  541. package/dist/{redirect-CZkbozu9.mjs → redirect-DId44BS1.mjs} +19 -6
  542. package/dist/redirect-DId44BS1.mjs.map +1 -0
  543. package/dist/{redirects-CqzNM0KM.mjs → redirects-DN-ZE33W.mjs} +5 -5
  544. package/dist/{redirects-CqzNM0KM.mjs.map → redirects-DN-ZE33W.mjs.map} +1 -1
  545. package/dist/{registry-AZAsRsor.mjs → registry-DTqaqxed.mjs} +26 -10
  546. package/dist/registry-DTqaqxed.mjs.map +1 -0
  547. package/dist/{relation-04DfKRTO.mjs → relation-DxgCHOBw.mjs} +2 -2
  548. package/dist/{relation-04DfKRTO.mjs.map → relation-DxgCHOBw.mjs.map} +1 -1
  549. package/dist/{relations-CcFwDJdJ.mjs → relations-KKDSLUwS.mjs} +4 -4
  550. package/dist/{relations-CcFwDJdJ.mjs.map → relations-KKDSLUwS.mjs.map} +1 -1
  551. package/dist/{relations-C4htk5sb.mjs → relations-rOmbndUJ.mjs} +3 -3
  552. package/dist/{relations-C4htk5sb.mjs.map → relations-rOmbndUJ.mjs.map} +1 -1
  553. package/dist/{request-cache-DH9zdCOD.mjs → request-cache-DAZZmesc.mjs} +1 -1
  554. package/dist/{request-cache-DH9zdCOD.mjs.map → request-cache-DAZZmesc.mjs.map} +1 -1
  555. package/dist/request-context.d.mts +1 -1
  556. package/dist/{request-meta-DYxLlnmz.mjs → request-meta-BgjUQLQ-.mjs} +2 -2
  557. package/dist/{request-meta-DYxLlnmz.mjs.map → request-meta-BgjUQLQ-.mjs.map} +1 -1
  558. package/dist/{resolve-prZ3mP7l.mjs → resolve-Cy0aWSRj.mjs} +37 -4
  559. package/dist/resolve-Cy0aWSRj.mjs.map +1 -0
  560. package/dist/{runner-YKfIMnaF.d.mts → runner-CfwysRM0.d.mts} +2 -2
  561. package/dist/{runner-YKfIMnaF.d.mts.map → runner-CfwysRM0.d.mts.map} +1 -1
  562. package/dist/{runner-BLIDKpmA.mjs → runner-nEzvnogG.mjs} +419 -295
  563. package/dist/runner-nEzvnogG.mjs.map +1 -0
  564. package/dist/runtime.d.mts +11 -11
  565. package/dist/runtime.mjs +3 -2
  566. package/dist/runtime.mjs.map +1 -1
  567. package/dist/{schema-CGnBeLiW.mjs → schema-CRu38Pr5.mjs} +3 -3
  568. package/dist/{schema-CGnBeLiW.mjs.map → schema-CRu38Pr5.mjs.map} +1 -1
  569. package/dist/{schema-DYr-Vd-L.mjs → schema-DifxndJx.mjs} +4 -4
  570. package/dist/{schema-DYr-Vd-L.mjs.map → schema-DifxndJx.mjs.map} +1 -1
  571. package/dist/{scopes-BhWvBavj.mjs → scopes-D5A1OZbq.mjs} +3 -3
  572. package/dist/{scopes-BhWvBavj.mjs.map → scopes-D5A1OZbq.mjs.map} +1 -1
  573. package/dist/{search-C-qDk4kx.mjs → search-DEPFSBFq.mjs} +4 -4
  574. package/dist/{search-C-qDk4kx.mjs.map → search-DEPFSBFq.mjs.map} +1 -1
  575. package/dist/{secrets-rEtHt-6z.mjs → secrets-CdfzLdoO.mjs} +3 -3
  576. package/dist/{secrets-rEtHt-6z.mjs.map → secrets-CdfzLdoO.mjs.map} +1 -1
  577. package/dist/{sections-B_nYvlwn.mjs → sections-3X52kmIR.mjs} +2 -2
  578. package/dist/{sections-B_nYvlwn.mjs.map → sections-3X52kmIR.mjs.map} +1 -1
  579. package/dist/seed/index.d.mts +2 -2
  580. package/dist/seed/index.mjs +26 -24
  581. package/dist/seo/index.d.mts +3 -3
  582. package/dist/seo/index.d.mts.map +1 -1
  583. package/dist/seo/index.mjs +18 -19
  584. package/dist/seo/index.mjs.map +1 -1
  585. package/dist/{seo-926NRIgt.mjs → seo-Bw68KxRc.mjs} +2 -2
  586. package/dist/{seo-926NRIgt.mjs.map → seo-Bw68KxRc.mjs.map} +1 -1
  587. package/dist/{seo-CVWkdv6x.mjs → seo-C4AmbsMU.mjs} +3 -2
  588. package/dist/seo-C4AmbsMU.mjs.map +1 -0
  589. package/dist/{service-CJl3ZAYs.mjs → service-J_-Vgo7R.mjs} +2 -2
  590. package/dist/{service-CJl3ZAYs.mjs.map → service-J_-Vgo7R.mjs.map} +1 -1
  591. package/dist/{session-user-BlMgqCHS.mjs → session-user-CbnMMwk6.mjs} +1 -1
  592. package/dist/{session-user-BlMgqCHS.mjs.map → session-user-CbnMMwk6.mjs.map} +1 -1
  593. package/dist/{settings-Cwm6o2jY.mjs → settings-AnEFYICn.mjs} +3 -3
  594. package/dist/{settings-Cwm6o2jY.mjs.map → settings-AnEFYICn.mjs.map} +1 -1
  595. package/dist/{settings--wobrkkC.mjs → settings-DcMjREe5.mjs} +6 -6
  596. package/dist/{settings--wobrkkC.mjs.map → settings-DcMjREe5.mjs.map} +1 -1
  597. package/dist/{setup-complete-DQbClIN2.mjs → setup-complete-BClXXTvr.mjs} +2 -2
  598. package/dist/{setup-complete-DQbClIN2.mjs.map → setup-complete-BClXXTvr.mjs.map} +1 -1
  599. package/dist/{setup-nonce-DZCFS2sn.mjs → setup-nonce-BheRa4RG.mjs} +1 -1
  600. package/dist/{setup-nonce-DZCFS2sn.mjs.map → setup-nonce-BheRa4RG.mjs.map} +1 -1
  601. package/dist/{single-flight-cache-BPuGPdcN.mjs → single-flight-cache-jaswDzmQ.mjs} +2 -2
  602. package/dist/{single-flight-cache-BPuGPdcN.mjs.map → single-flight-cache-jaswDzmQ.mjs.map} +1 -1
  603. package/dist/{site-url-BrxA_E9H.mjs → site-url-Bqf-ea3N.mjs} +3 -3
  604. package/dist/{site-url-BrxA_E9H.mjs.map → site-url-Bqf-ea3N.mjs.map} +1 -1
  605. package/dist/{snapshot--OCDTqdb.mjs → snapshot-C4CtXntb.mjs} +51 -35
  606. package/dist/snapshot-C4CtXntb.mjs.map +1 -0
  607. package/dist/{ssrf-5sIM5jzl.mjs → ssrf-gl4gFNhw.mjs} +148 -91
  608. package/dist/ssrf-gl4gFNhw.mjs.map +1 -0
  609. package/dist/{state-BpFVsJZB.mjs → state-1F6IOhdQ.mjs} +1 -1
  610. package/dist/{state-BpFVsJZB.mjs.map → state-1F6IOhdQ.mjs.map} +1 -1
  611. package/dist/{status-B777-dXz.mjs → status-Cenfk_r5.mjs} +1 -1
  612. package/dist/{status-B777-dXz.mjs.map → status-Cenfk_r5.mjs.map} +1 -1
  613. package/dist/storage/local.d.mts +1 -1
  614. package/dist/storage/local.mjs +1 -1
  615. package/dist/storage/s3.d.mts +1 -1
  616. package/dist/storage/s3.mjs +1 -1
  617. package/dist/{target-BmR0iTwz.mjs → target-CRzeTs8G.mjs} +1 -1
  618. package/dist/{target-BmR0iTwz.mjs.map → target-CRzeTs8G.mjs.map} +1 -1
  619. package/dist/{taxonomies-DkAkMupr.mjs → taxonomies-BOdxuZpV.mjs} +11 -4
  620. package/dist/taxonomies-BOdxuZpV.mjs.map +1 -0
  621. package/dist/{taxonomies-Wfy_Lg12.mjs → taxonomies-NcFDq5Gg.mjs} +23 -14
  622. package/dist/taxonomies-NcFDq5Gg.mjs.map +1 -0
  623. package/dist/{taxonomy-tJepplLL.mjs → taxonomy-DP1vny4K.mjs} +11 -3
  624. package/dist/{taxonomy-tJepplLL.mjs.map → taxonomy-DP1vny4K.mjs.map} +1 -1
  625. package/dist/{tokens-BCO1oruF.mjs → tokens-CDk8ox9p.mjs} +1 -1
  626. package/dist/{tokens-BCO1oruF.mjs.map → tokens-CDk8ox9p.mjs.map} +1 -1
  627. package/dist/{transport-xh6YKW2G.d.mts → transport-BVn4tVb9.d.mts} +1 -1
  628. package/dist/{transport-xh6YKW2G.d.mts.map → transport-BVn4tVb9.d.mts.map} +1 -1
  629. package/dist/{transport-Dr3qtwXC.mjs → transport-DP0JI-8i.mjs} +1 -1
  630. package/dist/{transport-Dr3qtwXC.mjs.map → transport-DP0JI-8i.mjs.map} +1 -1
  631. package/dist/{trusted-proxy-BR5F1Otp.mjs → trusted-proxy-BTM6UxqD.mjs} +1 -1
  632. package/dist/{trusted-proxy-BR5F1Otp.mjs.map → trusted-proxy-BTM6UxqD.mjs.map} +1 -1
  633. package/dist/{types-CXFkwEGC.d.mts → types-2n848aVW.d.mts} +1 -1
  634. package/dist/{types-CXFkwEGC.d.mts.map → types-2n848aVW.d.mts.map} +1 -1
  635. package/dist/{types-75KIqzL9.mjs → types-BMXnRIrX.mjs} +4 -2
  636. package/dist/types-BMXnRIrX.mjs.map +1 -0
  637. package/dist/{types-B6GrPic4.d.mts → types-BouXpOsa.d.mts} +115 -4
  638. package/dist/types-BouXpOsa.d.mts.map +1 -0
  639. package/dist/{types-3qNFPlci.mjs → types-ByG2coLw.mjs} +1 -1
  640. package/dist/{types-3qNFPlci.mjs.map → types-ByG2coLw.mjs.map} +1 -1
  641. package/dist/types-CQPWhPxE.mjs.map +1 -1
  642. package/dist/{types-CDtkNSFQ.d.mts → types-DEfNJ__A.d.mts} +1 -1
  643. package/dist/{types-CDtkNSFQ.d.mts.map → types-DEfNJ__A.d.mts.map} +1 -1
  644. package/dist/{types-xDMtUFnO.d.mts → types-DKcKSbtB.d.mts} +23 -7
  645. package/dist/types-DKcKSbtB.d.mts.map +1 -0
  646. package/dist/{types-C00oyCZp.d.mts → types-DRYs7uTL.d.mts} +1 -1
  647. package/dist/{types-C00oyCZp.d.mts.map → types-DRYs7uTL.d.mts.map} +1 -1
  648. package/dist/{types-DczELMop.d.mts → types-DaEg7KX2.d.mts} +1 -1
  649. package/dist/{types-DczELMop.d.mts.map → types-DaEg7KX2.d.mts.map} +1 -1
  650. package/dist/{types-BuHW4xDE.d.mts → types-LU8utpP_.d.mts} +6 -3
  651. package/dist/types-LU8utpP_.d.mts.map +1 -0
  652. package/dist/{types-CPeXo1wF.d.mts → types-VpYfPUxN.d.mts} +1 -1
  653. package/dist/{types-CPeXo1wF.d.mts.map → types-VpYfPUxN.d.mts.map} +1 -1
  654. package/dist/{types-DM3vioBY.mjs → types-c9GP7Dj5.mjs} +1 -1
  655. package/dist/{types-DM3vioBY.mjs.map → types-c9GP7Dj5.mjs.map} +1 -1
  656. package/dist/{types-FV23hEoW.d.mts → types-tJWDK__M.d.mts} +14 -1
  657. package/dist/types-tJWDK__M.d.mts.map +1 -0
  658. package/dist/{upload-attempts-BsqoQ1fn.mjs → upload-attempts-C6S2y-lp.mjs} +1 -1
  659. package/dist/{upload-attempts-BsqoQ1fn.mjs.map → upload-attempts-C6S2y-lp.mjs.map} +1 -1
  660. package/dist/{url-pattern-D4c2czpJ.mjs → url-pattern-UYtxVTuj.mjs} +1 -1
  661. package/dist/{url-pattern-D4c2czpJ.mjs.map → url-pattern-UYtxVTuj.mjs.map} +1 -1
  662. package/dist/{user-BTZ40aq6.mjs → user-DIsIXogT.mjs} +2 -2
  663. package/dist/{user-BTZ40aq6.mjs.map → user-DIsIXogT.mjs.map} +1 -1
  664. package/dist/{utils-BKvNjjhY.mjs → utils-BicP5Qbg.mjs} +2 -2
  665. package/dist/{utils-BKvNjjhY.mjs.map → utils-BicP5Qbg.mjs.map} +1 -1
  666. package/dist/{validate-DE_LRwo9.mjs → validate-D8VPn4Hv.mjs} +8 -3
  667. package/dist/validate-D8VPn4Hv.mjs.map +1 -0
  668. package/dist/{validate-DUP27OYD.d.mts → validate-Df6Dvwbw.d.mts} +12 -7
  669. package/dist/validate-Df6Dvwbw.d.mts.map +1 -0
  670. package/dist/{validation-BMImFJ11.mjs → validation-CzMJn9Ku.mjs} +13 -11
  671. package/dist/{validation-BMImFJ11.mjs.map → validation-CzMJn9Ku.mjs.map} +1 -1
  672. package/dist/version-CK67_SXX.mjs +7 -0
  673. package/dist/{version-Bii3suaO.mjs.map → version-CK67_SXX.mjs.map} +1 -1
  674. package/dist/{widgets-D3gJ10xU.mjs → widgets-RFVAxQl3.mjs} +5 -5
  675. package/dist/{widgets-D3gJ10xU.mjs.map → widgets-RFVAxQl3.mjs.map} +1 -1
  676. package/dist/{wxr-taxonomies-B2Og_6rU.d.mts → wxr-taxonomies-BX4yQL9s.d.mts} +1 -1
  677. package/dist/{wxr-taxonomies-B2Og_6rU.d.mts.map → wxr-taxonomies-BX4yQL9s.d.mts.map} +1 -1
  678. package/dist/{wxr-taxonomies-Cxngsjwo.mjs → wxr-taxonomies-Csdp7yde.mjs} +4 -4
  679. package/dist/{wxr-taxonomies-Cxngsjwo.mjs.map → wxr-taxonomies-Csdp7yde.mjs.map} +1 -1
  680. package/dist/{zod-generator-BuYSQJB7.mjs → zod-generator-CNRGdnBY.mjs} +3 -3
  681. package/dist/{zod-generator-BuYSQJB7.mjs.map → zod-generator-CNRGdnBY.mjs.map} +1 -1
  682. package/package.json +12 -10
  683. package/src/api/errors.ts +7 -0
  684. package/src/api/handlers/content.ts +66 -79
  685. package/src/api/handlers/entry-lock.ts +206 -0
  686. package/src/api/handlers/manifest.ts +1 -0
  687. package/src/api/handlers/marketplace.ts +28 -20
  688. package/src/api/handlers/menus.ts +9 -0
  689. package/src/api/handlers/registry.ts +13 -8
  690. package/src/api/handlers/revision.ts +2 -1
  691. package/src/api/handlers/seo.ts +10 -1
  692. package/src/api/handlers/snapshot.ts +84 -72
  693. package/src/api/handlers/taxonomies.ts +9 -0
  694. package/src/api/openapi/document.ts +111 -6
  695. package/src/api/schemas/content.ts +8 -0
  696. package/src/api/schemas/entry-lock.ts +48 -0
  697. package/src/api/schemas/index.ts +1 -0
  698. package/src/api/schemas/schema.ts +10 -1
  699. package/src/api/types.ts +2 -0
  700. package/src/astro/integration/index.ts +9 -6
  701. package/src/astro/integration/routes.ts +5 -0
  702. package/src/astro/integration/runtime.ts +13 -5
  703. package/src/astro/integration/vite-config.ts +30 -0
  704. package/src/astro/middleware.ts +16 -0
  705. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +10 -0
  706. package/src/astro/routes/api/content/[collection]/[id]/lock.ts +133 -0
  707. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +11 -1
  708. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +20 -0
  709. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +10 -0
  710. package/src/astro/routes/api/content/[collection]/[id].ts +27 -2
  711. package/src/astro/routes/api/content/[collection]/index.ts +3 -0
  712. package/src/astro/routes/sitemap-[collection].xml.ts +4 -0
  713. package/src/astro/types.ts +13 -3
  714. package/src/cli/commands/content.ts +31 -5
  715. package/src/cli/commands/export-seed.ts +2 -0
  716. package/src/client/index.ts +34 -7
  717. package/src/components/EmDashBodyEnd.astro +4 -1
  718. package/src/components/EmDashBodyStart.astro +4 -1
  719. package/src/components/EmDashHead.astro +35 -16
  720. package/src/components/Gallery.astro +18 -4
  721. package/src/components/InlineEditor.astro +3 -1
  722. package/src/components/InlinePortableTextEditor.tsx +106 -11
  723. package/src/components/PortableText.astro +4 -0
  724. package/src/components/Table.astro +147 -62
  725. package/src/config/errors.ts +13 -0
  726. package/src/content/converters/portable-text-to-prosemirror.ts +26 -2
  727. package/src/content/converters/prosemirror-to-portable-text.ts +35 -6
  728. package/src/content/converters/types.ts +10 -0
  729. package/src/database/dialect-helpers.ts +125 -0
  730. package/src/database/migrations/075_entry_edit_locks.ts +44 -0
  731. package/src/database/migrations/076_collection_nav_group.ts +22 -0
  732. package/src/database/migrations/077_plugin_storage_revisions.ts +89 -0
  733. package/src/database/migrations/runner.ts +6 -0
  734. package/src/database/repositories/content.ts +170 -1
  735. package/src/database/repositories/entry-locks.ts +257 -0
  736. package/src/database/repositories/options.ts +69 -5
  737. package/src/database/repositories/plugin-storage.ts +159 -0
  738. package/src/database/repositories/redirect.ts +17 -6
  739. package/src/database/repositories/taxonomy.ts +8 -0
  740. package/src/database/repositories/types.ts +3 -0
  741. package/src/database/types.ts +15 -1
  742. package/src/emdash-runtime.ts +117 -50
  743. package/src/i18n/resolve.ts +44 -4
  744. package/src/index.ts +14 -0
  745. package/src/loader.ts +35 -4
  746. package/src/mcp/server.ts +23 -5
  747. package/src/media/responsive.ts +23 -0
  748. package/src/media/usage/content-refresh.ts +2 -1
  749. package/src/menus/index.ts +17 -21
  750. package/src/page/seo-contributions.ts +78 -1
  751. package/src/page/seo-panel.ts +47 -0
  752. package/src/plugin-types.ts +9 -0
  753. package/src/plugins/conditional-storage.ts +30 -0
  754. package/src/plugins/context.ts +49 -17
  755. package/src/plugins/hooks.ts +7 -1
  756. package/src/plugins/index.ts +9 -0
  757. package/src/plugins/manager.ts +5 -2
  758. package/src/plugins/sandbox/types.ts +16 -2
  759. package/src/plugins/storage-query.ts +45 -0
  760. package/src/plugins/storage-update.ts +96 -0
  761. package/src/plugins/types.ts +114 -0
  762. package/src/query.ts +29 -3
  763. package/src/registry/config.ts +130 -27
  764. package/src/registry/types.ts +5 -6
  765. package/src/schema/collection-slugs-cache.ts +157 -0
  766. package/src/schema/registry.ts +19 -0
  767. package/src/schema/types.ts +25 -6
  768. package/src/security/ssrf.ts +167 -141
  769. package/src/seed/apply.ts +4 -0
  770. package/src/seed/types.ts +7 -2
  771. package/src/seed/validate.ts +18 -1
  772. package/src/seo/hreflang.ts +1 -0
  773. package/src/seo/index.ts +5 -10
  774. package/src/seo/media-url.ts +26 -0
  775. package/src/taxonomies/term-counts.ts +22 -5
  776. package/dist/api-Dz6rgoa3.mjs.map +0 -1
  777. package/dist/apply-B4SIOxR1.mjs.map +0 -1
  778. package/dist/config-it29yDLA.mjs.map +0 -1
  779. package/dist/content-DjvM0T92.mjs.map +0 -1
  780. package/dist/context-CX6gxOLW.mjs.map +0 -1
  781. package/dist/dialect-helpers-BSbfaO3F.mjs.map +0 -1
  782. package/dist/errors-DsVoDUjJ.mjs.map +0 -1
  783. package/dist/index-BJNMCWmu.d.mts.map +0 -1
  784. package/dist/loader-Z8vl7zTq.mjs.map +0 -1
  785. package/dist/media-url-DHoPr0hq.mjs.map +0 -1
  786. package/dist/menus-6qSwTNxG.mjs.map +0 -1
  787. package/dist/options-BHPeIbBd.mjs.map +0 -1
  788. package/dist/options-CYb4y7hM.d.mts.map +0 -1
  789. package/dist/query-BZKZcG5b.mjs.map +0 -1
  790. package/dist/redirect-CZkbozu9.mjs.map +0 -1
  791. package/dist/redirects-BLNOWQTn.mjs.map +0 -1
  792. package/dist/registry-AZAsRsor.mjs.map +0 -1
  793. package/dist/relations-DnRK4YIT.d.mts.map +0 -1
  794. package/dist/resolve-prZ3mP7l.mjs.map +0 -1
  795. package/dist/runner-BLIDKpmA.mjs.map +0 -1
  796. package/dist/seo-CVWkdv6x.mjs.map +0 -1
  797. package/dist/snapshot--OCDTqdb.mjs.map +0 -1
  798. package/dist/ssrf-5sIM5jzl.mjs.map +0 -1
  799. package/dist/taxonomies-DkAkMupr.mjs.map +0 -1
  800. package/dist/taxonomies-Wfy_Lg12.mjs.map +0 -1
  801. package/dist/types-75KIqzL9.mjs.map +0 -1
  802. package/dist/types-B6GrPic4.d.mts.map +0 -1
  803. package/dist/types-BuHW4xDE.d.mts.map +0 -1
  804. package/dist/types-FV23hEoW.d.mts.map +0 -1
  805. package/dist/types-xDMtUFnO.d.mts.map +0 -1
  806. package/dist/validate-DE_LRwo9.mjs.map +0 -1
  807. package/dist/validate-DUP27OYD.d.mts.map +0 -1
  808. package/dist/version-Bii3suaO.mjs +0 -7
  809. /package/dist/{api-tokens-BfYts-sq.mjs → api-tokens-B_lfpmH3.mjs} +0 -0
  810. /package/dist/{ssrf-Dg3cIT-b.mjs → ssrf-TQhaljuI.mjs} +0 -0
  811. /package/dist/{types-DfuTR6dL.mjs → types-A2cN6a4a.mjs} +0 -0
@@ -1,69 +1,94 @@
1
1
  /**
2
- * SSRF protection for import URLs.
2
+ * SSRF protection for outbound HTTP requests.
3
3
  *
4
- * Validates that URLs don't target internal/private network addresses.
5
- * Applied before any fetch() call in the import pipeline.
4
+ * Validates that URLs do not target non-public network addresses.
6
5
  */
7
6
 
8
- const IPV4_MAPPED_IPV6_DOTTED_PATTERN = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i;
9
- const IPV4_MAPPED_IPV6_HEX_PATTERN = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
10
- const IPV4_TRANSLATED_HEX_PATTERN = /^::ffff:0:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
11
- const IPV6_EXPANDED_MAPPED_PATTERN =
12
- /^0{0,4}:0{0,4}:0{0,4}:0{0,4}:0{0,4}:ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
13
-
14
- /**
15
- * IPv4-compatible (deprecated) addresses: ::XXXX:XXXX
16
- *
17
- * The WHATWG URL parser normalizes [::127.0.0.1] to [::7f00:1] (no ffff prefix).
18
- * These are deprecated but still parsed, and bypass the ffff-based checks.
19
- */
20
- const IPV4_COMPATIBLE_HEX_PATTERN = /^::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
21
-
22
- /**
23
- * NAT64 prefix (RFC 6052): 64:ff9b::XXXX:XXXX
24
- *
25
- * Used by NAT64 gateways to embed IPv4 addresses in IPv6.
26
- * [64:ff9b::127.0.0.1] normalizes to [64:ff9b::7f00:1].
27
- */
28
- const NAT64_HEX_PATTERN = /^64:ff9b::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
29
-
30
7
  const IPV6_BRACKET_PATTERN = /^\[|\]$/g;
31
-
32
- /** Match fc00::/7 ULA — first byte 0xfc or 0xfd followed by any byte. */
33
- const IPV6_ULA_FC_PATTERN = /^fc[0-9a-f]{2}:/;
34
- const IPV6_ULA_FD_PATTERN = /^fd[0-9a-f]{2}:/;
8
+ const IPV4_PART_PATTERN = /^(?:0|[1-9]\d{0,2})$/;
9
+ const IPV6_PART_PATTERN = /^[0-9a-f]{1,4}$/i;
35
10
 
36
11
  /** Strip trailing dots from an FQDN-form hostname ("localhost." -> "localhost"). */
37
12
  const TRAILING_DOT_PATTERN = /\.+$/;
38
13
 
39
14
  /**
40
- * Private and reserved IP ranges that should never be fetched.
41
- *
42
- * Includes:
43
- * - Loopback (127.0.0.0/8)
44
- * - Private (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
45
- * - Link-local (169.254.0.0/16)
46
- * - Cloud metadata (169.254.169.254 — AWS/GCP/Azure)
47
- * - IPv6 loopback and link-local
15
+ * IPv4 ranges that are not globally reachable unicast destinations.
48
16
  */
49
17
  const BLOCKED_PATTERNS: Array<{ start: number; end: number }> = [
50
- // 127.0.0.0/8 — loopback
51
- { start: ip4ToNum(127, 0, 0, 0), end: ip4ToNum(127, 255, 255, 255) },
52
- // 10.0.0.0/8 — private
18
+ // Current network
19
+ { start: ip4ToNum(0, 0, 0, 0), end: ip4ToNum(0, 255, 255, 255) },
20
+ // Private use
53
21
  { start: ip4ToNum(10, 0, 0, 0), end: ip4ToNum(10, 255, 255, 255) },
54
- // 172.16.0.0/12 — private
22
+ // Shared address space
23
+ { start: ip4ToNum(100, 64, 0, 0), end: ip4ToNum(100, 127, 255, 255) },
24
+ // Loopback
25
+ { start: ip4ToNum(127, 0, 0, 0), end: ip4ToNum(127, 255, 255, 255) },
26
+ // Link-local, including common cloud metadata endpoints
27
+ { start: ip4ToNum(169, 254, 0, 0), end: ip4ToNum(169, 254, 255, 255) },
28
+ // Private use
55
29
  { start: ip4ToNum(172, 16, 0, 0), end: ip4ToNum(172, 31, 255, 255) },
56
- // 192.168.0.0/16 — private
30
+ // IETF protocol assignments. Globally reachable exceptions are handled below.
31
+ { start: ip4ToNum(192, 0, 0, 0), end: ip4ToNum(192, 0, 0, 255) },
32
+ // Documentation
33
+ { start: ip4ToNum(192, 0, 2, 0), end: ip4ToNum(192, 0, 2, 255) },
34
+ // Deprecated 6to4 relay anycast
35
+ { start: ip4ToNum(192, 88, 99, 0), end: ip4ToNum(192, 88, 99, 255) },
36
+ // Private use
57
37
  { start: ip4ToNum(192, 168, 0, 0), end: ip4ToNum(192, 168, 255, 255) },
58
- // 169.254.0.0/16 — link-local (includes cloud metadata endpoint)
59
- { start: ip4ToNum(169, 254, 0, 0), end: ip4ToNum(169, 254, 255, 255) },
60
- // 0.0.0.0/8 — current network
61
- { start: ip4ToNum(0, 0, 0, 0), end: ip4ToNum(0, 255, 255, 255) },
38
+ // Benchmarking
39
+ { start: ip4ToNum(198, 18, 0, 0), end: ip4ToNum(198, 19, 255, 255) },
40
+ // Documentation
41
+ { start: ip4ToNum(198, 51, 100, 0), end: ip4ToNum(198, 51, 100, 255) },
42
+ { start: ip4ToNum(203, 0, 113, 0), end: ip4ToNum(203, 0, 113, 255) },
43
+ // Multicast, reserved, and limited broadcast
44
+ { start: ip4ToNum(224, 0, 0, 0), end: ip4ToNum(255, 255, 255, 255) },
45
+ ];
46
+
47
+ const ALLOWED_IPV4_EXCEPTIONS = new Set([ip4ToNum(192, 0, 0, 9), ip4ToNum(192, 0, 0, 10)]);
48
+
49
+ interface Ipv6Range {
50
+ address: number[];
51
+ prefixLength: number;
52
+ }
53
+
54
+ function ipv6Range(address: string, prefixLength: number): Ipv6Range {
55
+ const parsed = parseIpv6(address);
56
+ if (parsed === null) throw new Error(`Invalid IPv6 range: ${address}/${prefixLength}`);
57
+ return { address: parsed, prefixLength };
58
+ }
59
+
60
+ const IPV6_GLOBAL_UNICAST_RANGE = ipv6Range("2000::", 3);
61
+ const IPV4_COMPATIBLE_IPV6_RANGE = ipv6Range("::", 96);
62
+ const IPV4_EMBEDDED_IPV6_RANGES: Ipv6Range[] = [
63
+ IPV4_COMPATIBLE_IPV6_RANGE,
64
+ ipv6Range("::ffff:0:0", 96),
65
+ ipv6Range("::ffff:0:0:0", 96),
66
+ ipv6Range("64:ff9b::", 96),
67
+ ];
68
+
69
+ /** Globally reachable allocations inside the otherwise reserved 2001::/23 block. */
70
+ const ALLOWED_IPV6_SPECIAL_RANGES: Ipv6Range[] = [
71
+ ipv6Range("2001:1::1", 128),
72
+ ipv6Range("2001:1::2", 128),
73
+ ipv6Range("2001:1::3", 128),
74
+ ipv6Range("2001:3::", 32),
75
+ ipv6Range("2001:4:112::", 48),
76
+ ipv6Range("2001:20::", 28),
77
+ ipv6Range("2001:30::", 28),
78
+ ];
79
+
80
+ /** Non-global allocations inside the ordinary IPv6 global-unicast range. */
81
+ const BLOCKED_IPV6_GLOBAL_UNICAST_RANGES: Ipv6Range[] = [
82
+ ipv6Range("2001::", 23),
83
+ ipv6Range("2001:db8::", 32),
84
+ ipv6Range("2002::", 16),
85
+ ipv6Range("3ffe::", 16),
86
+ ipv6Range("3fff::", 20),
62
87
  ];
63
88
 
64
89
  // Bracket-stripped form is used for lookups (validateExternalUrl strips
65
90
  // brackets from parsed.hostname before checking), so "::1" appears here
66
- // without brackets. The "::1" case is already covered by isPrivateIp, but
91
+ // without brackets. The "::1" case is already covered by isNonPublicIp, but
67
92
  // keeping it here makes the intent explicit and gives a clearer error
68
93
  // message for the common `http://[::1]/` form.
69
94
  const BLOCKED_HOSTNAMES = new Set([
@@ -101,80 +126,78 @@ function parseIpv4(ip: string): number | null {
101
126
  const parts = ip.split(".");
102
127
  if (parts.length !== 4) return null;
103
128
 
104
- const nums = parts.map(Number);
105
- if (nums.some((n) => isNaN(n) || n < 0 || n > 255)) return null;
129
+ const nums = parts.map((part) => (IPV4_PART_PATTERN.test(part) ? Number(part) : Number.NaN));
130
+ if (nums.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
106
131
 
107
132
  return ip4ToNum(nums[0], nums[1], nums[2], nums[3]);
108
133
  }
109
134
 
110
- /**
111
- * Convert IPv4-mapped/translated IPv6 addresses from hex form back to IPv4.
112
- *
113
- * The WHATWG URL parser normalizes dotted-decimal to hex:
114
- * [::ffff:127.0.0.1] -> [::ffff:7f00:1]
115
- * [::ffff:169.254.169.254] -> [::ffff:a9fe:a9fe]
116
- *
117
- * Without this conversion, the hex forms bypass isPrivateIp() regex checks.
118
- */
119
- export function normalizeIPv6MappedToIPv4(ip: string): string | null {
120
- // Match hex-form IPv4-mapped IPv6: ::ffff:XXXX:XXXX
121
- let match = ip.match(IPV4_MAPPED_IPV6_HEX_PATTERN);
122
- if (!match) {
123
- // Match IPv4-translated (RFC 6052): ::ffff:0:XXXX:XXXX
124
- match = ip.match(IPV4_TRANSLATED_HEX_PATTERN);
125
- }
126
- if (!match) {
127
- // Match fully expanded form: 0000:0000:0000:0000:0000:ffff:XXXX:XXXX
128
- match = ip.match(IPV6_EXPANDED_MAPPED_PATTERN);
129
- }
130
- if (!match) {
131
- // Match IPv4-compatible (deprecated) form: ::XXXX:XXXX (no ffff prefix)
132
- match = ip.match(IPV4_COMPATIBLE_HEX_PATTERN);
135
+ function parseIpv6(ip: string): number[] | null {
136
+ let address = ip;
137
+ if (address.includes(".")) {
138
+ const separator = address.lastIndexOf(":");
139
+ if (separator === -1) return null;
140
+ const ipv4 = parseIpv4(address.slice(separator + 1));
141
+ if (ipv4 === null) return null;
142
+ address = `${address.slice(0, separator + 1)}${(ipv4 >>> 16).toString(16)}:${(ipv4 & 0xffff).toString(16)}`;
133
143
  }
134
- if (!match) {
135
- // Match NAT64 prefix (RFC 6052): 64:ff9b::XXXX:XXXX
136
- match = ip.match(NAT64_HEX_PATTERN);
137
- }
138
- if (match) {
139
- const high = parseInt(match[1] ?? "", 16);
140
- const low = parseInt(match[2] ?? "", 16);
141
- return `${(high >> 8) & 0xff}.${high & 0xff}.${(low >> 8) & 0xff}.${low & 0xff}`;
142
- }
143
- return null;
144
+ if (address.includes(":::") || address.split("::").length > 2) return null;
145
+
146
+ const [before = "", after = ""] = address.split("::");
147
+ const head = before === "" ? [] : before.split(":");
148
+ const tail = after === "" ? [] : after.split(":");
149
+ const parts = [...head, ...tail];
150
+ if (parts.some((part) => !IPV6_PART_PATTERN.test(part)) || parts.length > 8) return null;
151
+ if (address.includes("::") ? parts.length >= 8 : parts.length !== 8) return null;
152
+
153
+ const zeroCount = address.includes("::") ? 8 - parts.length : 0;
154
+ return [...head, ...Array.from<string>({ length: zeroCount }).fill("0"), ...tail].map((part) =>
155
+ Number.parseInt(part, 16),
156
+ );
144
157
  }
145
158
 
146
- function isPrivateIp(ip: string): boolean {
147
- // Normalize IPv6 strings to lowercase. `new URL().hostname` already
148
- // lowercases, but resolver output (from DoH or an injected resolver) may
149
- // not. Without this, "FE80::1" bypasses the link-local check.
150
- const normalized = ip.toLowerCase();
151
-
152
- // Handle IPv6 loopback
153
- if (normalized === "::1" || normalized === "::ffff:127.0.0.1") return true;
154
-
155
- // Handle IPv4-mapped IPv6 in hex form (WHATWG URL parser normalizes to this)
156
- // e.g. ::ffff:7f00:1 -> 127.0.0.1, ::ffff:a9fe:a9fe -> 169.254.169.254
157
- const hexIpv4 = normalizeIPv6MappedToIPv4(normalized);
158
- if (hexIpv4) return isPrivateIp(hexIpv4);
159
-
160
- // Handle IPv4-mapped IPv6 in dotted-decimal form
161
- const v4Match = normalized.match(IPV4_MAPPED_IPV6_DOTTED_PATTERN);
162
- const ipv4 = v4Match ? v4Match[1] : normalized;
163
-
164
- const num = parseIpv4(ipv4);
165
- if (num === null) {
166
- // If we can't parse it, block IPv6 addresses that look internal.
167
- // fc00::/7 is Unique Local (first byte 0xfc or 0xfd), fe80::/10 is
168
- // link-local. Only match when followed by hex digit + colon to avoid
169
- // collisions with hypothetical non-address strings.
170
- return (
171
- normalized.startsWith("fe80:") ||
172
- IPV6_ULA_FC_PATTERN.test(normalized) ||
173
- IPV6_ULA_FD_PATTERN.test(normalized)
174
- );
159
+ function isIpv6InRange(address: number[], range: Ipv6Range): boolean {
160
+ const completeParts = Math.floor(range.prefixLength / 16);
161
+ for (let i = 0; i < completeParts; i++) {
162
+ if (address[i] !== range.address[i]) return false;
175
163
  }
176
164
 
177
- return BLOCKED_PATTERNS.some((range) => num >= range.start && num <= range.end);
165
+ const remainingBits = range.prefixLength % 16;
166
+ if (remainingBits === 0) return true;
167
+ const mask = (0xffff << (16 - remainingBits)) & 0xffff;
168
+ return (address[completeParts] & mask) === (range.address[completeParts] & mask);
169
+ }
170
+
171
+ function extractEmbeddedIpv4(address: number[]): number | null {
172
+ if (!IPV4_EMBEDDED_IPV6_RANGES.some((range) => isIpv6InRange(address, range))) return null;
173
+ const ipv4 = ((address[6] << 16) | address[7]) >>> 0;
174
+ // The unspecified and loopback addresses retain their native IPv6 meaning.
175
+ if (ipv4 <= 1 && isIpv6InRange(address, IPV4_COMPATIBLE_IPV6_RANGE)) return null;
176
+ return ipv4;
177
+ }
178
+
179
+ /** Convert a hex-form IPv6 address with an embedded IPv4 destination to dotted decimal. */
180
+ export function normalizeIPv6MappedToIPv4(ip: string): string | null {
181
+ if (ip.includes(".")) return null;
182
+ const address = parseIpv6(ip);
183
+ if (address === null) return null;
184
+ const ipv4 = extractEmbeddedIpv4(address);
185
+ if (ipv4 === null) return null;
186
+ return `${ipv4 >>> 24}.${(ipv4 >>> 16) & 0xff}.${(ipv4 >>> 8) & 0xff}.${ipv4 & 0xff}`;
187
+ }
188
+
189
+ function isNonPublicIp(ip: string): boolean {
190
+ const parsedIpv4 = parseIpv4(ip);
191
+ const ipv6 = parsedIpv4 === null ? parseIpv6(ip) : null;
192
+ const ipv4 = ipv6 === null ? parsedIpv4 : extractEmbeddedIpv4(ipv6);
193
+ if (ipv4 !== null) {
194
+ if (ALLOWED_IPV4_EXCEPTIONS.has(ipv4)) return false;
195
+ return BLOCKED_PATTERNS.some((range) => ipv4 >= range.start && ipv4 <= range.end);
196
+ }
197
+ if (ipv6 === null) return true;
198
+ if (ALLOWED_IPV6_SPECIAL_RANGES.some((range) => isIpv6InRange(ipv6, range))) return false;
199
+ if (!isIpv6InRange(ipv6, IPV6_GLOBAL_UNICAST_RANGE)) return true;
200
+ return BLOCKED_IPV6_GLOBAL_UNICAST_RANGES.some((range) => isIpv6InRange(ipv6, range));
178
201
  }
179
202
 
180
203
  /**
@@ -190,17 +213,15 @@ export class SsrfError extends Error {
190
213
  }
191
214
 
192
215
  /**
193
- * Validate that a URL is safe to fetch (not targeting internal networks).
216
+ * Validate a URL's scheme, hostname, and literal address.
194
217
  *
195
218
  * Checks:
196
219
  * 1. URL is well-formed with http/https scheme
197
220
  * 2. Hostname is not a known internal name (localhost, metadata endpoints)
198
- * 3. If hostname is an IP literal, it's not in a private range
221
+ * 3. If hostname is an IP literal, it is a public address
199
222
  *
200
- * Note: DNS rebinding attacks are not fully mitigated (hostname could resolve
201
- * to a private IP). Full protection requires resolving DNS and checking the IP
202
- * before connecting, which needs a custom fetch implementation. This covers
203
- * the most common SSRF vectors.
223
+ * Hostnames also need DNS validation before dispatch. Resolving and checking
224
+ * addresses does not bind an ordinary fetch() connection to those addresses.
204
225
  *
205
226
  * @throws SsrfError if the URL targets an internal address
206
227
  */
@@ -241,11 +262,11 @@ export function validateExternalUrl(url: string): URL {
241
262
  }
242
263
  }
243
264
 
244
- // Check if hostname is an IP address in a private range. Use the
265
+ // Check if hostname is a non-public IP address. Use the
245
266
  // normalized form so "127.0.0.1.." and friends don't bypass parseIpv4
246
267
  // (which rejects extra trailing dots).
247
- if (isPrivateIp(normalizedHost)) {
248
- throw new SsrfError("URLs targeting private IP addresses are not allowed");
268
+ if (isIpLiteral(normalizedHost) && isNonPublicIp(normalizedHost)) {
269
+ throw new SsrfError("URLs targeting non-public IP addresses are not allowed");
249
270
  }
250
271
 
251
272
  return parsed;
@@ -283,6 +304,7 @@ const DOH_TIMEOUT_MS = 3000;
283
304
  const DEFAULT_DOH_URL = "https://cloudflare-dns.com/dns-query";
284
305
 
285
306
  interface DohAnswer {
307
+ type: number;
286
308
  data: string;
287
309
  }
288
310
 
@@ -307,8 +329,14 @@ function parseDohResponse(raw: unknown): DohResponse {
307
329
  const answers: DohAnswer[] = [];
308
330
  if (hasProperty(raw, "Answer") && Array.isArray(raw.Answer)) {
309
331
  for (const entry of raw.Answer) {
310
- if (hasProperty(entry, "data") && typeof entry.data === "string") {
311
- answers.push({ data: entry.data });
332
+ if (
333
+ hasProperty(entry, "type") &&
334
+ typeof entry.type === "number" &&
335
+ Number.isInteger(entry.type) &&
336
+ hasProperty(entry, "data") &&
337
+ typeof entry.data === "string"
338
+ ) {
339
+ answers.push({ type: entry.type, data: entry.data });
312
340
  }
313
341
  }
314
342
  }
@@ -324,6 +352,7 @@ function parseDohResponse(raw: unknown): DohResponse {
324
352
  */
325
353
  export const cloudflareDohResolver: DnsResolver = async (hostname) => {
326
354
  async function query(type: "A" | "AAAA"): Promise<string[]> {
355
+ const expectedAnswerType = type === "A" ? 1 : 28;
327
356
  const params = new URLSearchParams({ name: hostname, type });
328
357
  const controller = new AbortController();
329
358
  const timeout = setTimeout(() => controller.abort(), DOH_TIMEOUT_MS);
@@ -347,8 +376,10 @@ export const cloudflareDohResolver: DnsResolver = async (hostname) => {
347
376
  }
348
377
  // DoH Answer arrays often include CNAME records alongside A/AAAA
349
378
  // records. Their `data` is a hostname, not an IP. Filter to just
350
- // IP literals so isPrivateIp sees real addresses.
351
- return body.Answer.map((a) => a.data).filter(isIpLiteral);
379
+ // IP literals of the requested record type.
380
+ return body.Answer.filter((answer) => answer.type === expectedAnswerType)
381
+ .map((answer) => answer.data)
382
+ .filter(isIpLiteral);
352
383
  } finally {
353
384
  clearTimeout(timeout);
354
385
  }
@@ -359,14 +390,12 @@ export const cloudflareDohResolver: DnsResolver = async (hostname) => {
359
390
  };
360
391
 
361
392
  /**
362
- * Validate a URL and resolve its hostname to check the actual IPs against
363
- * the private-range blocklist. This catches DNS rebinding attacks using
364
- * attacker-controlled domains that publicly resolve to private addresses,
365
- * and wildcard DNS services like nip.io used by exploit tooling.
393
+ * Validate a URL and reject hostnames that resolve to non-public addresses,
394
+ * including wildcard DNS services like nip.io used by exploit tooling.
366
395
  *
367
396
  * Runs `validateExternalUrl` first for cheap pre-flight checks (scheme,
368
397
  * literal IP, known-bad hostnames). Then resolves the hostname and rejects
369
- * if ANY returned address is private.
398
+ * if ANY returned address is non-public.
370
399
  *
371
400
  * Fails closed: if resolution fails or returns no records, throws SsrfError.
372
401
  *
@@ -381,9 +410,9 @@ export const cloudflareDohResolver: DnsResolver = async (hostname) => {
381
410
  * - Host-file overrides or split-horizon corporate DNS on self-hosted Node.
382
411
  * - Attacker-controlled rebinding services the caller has allowlisted.
383
412
  *
384
- * The only complete defense is a network-layer egress firewall. On
385
- * Cloudflare Workers, the platform fetch pipeline provides most of that.
386
- * On self-hosted Node, operators must restrict egress themselves.
413
+ * Connections must use the addresses from resolveAndValidateExternalUrlTarget
414
+ * to avoid a second lookup. Callers using ordinary fetch() need network-level
415
+ * egress controls to prevent these attacks.
387
416
  */
388
417
  export async function resolveAndValidateExternalUrl(
389
418
  url: string,
@@ -411,7 +440,7 @@ export async function resolveAndValidateExternalUrlTarget(
411
440
  const hostname = parsed.hostname.replace(IPV6_BRACKET_PATTERN, "");
412
441
 
413
442
  // If the hostname is already an IP literal, validateExternalUrl has
414
- // already checked it against the private-range list. Skip DNS.
443
+ // already checked it against the non-public ranges. Skip DNS.
415
444
  if (isIpLiteral(hostname)) {
416
445
  return { url: parsed, addresses: [hostname] };
417
446
  }
@@ -435,20 +464,17 @@ export async function resolveAndValidateExternalUrlTarget(
435
464
  if (!isIpLiteral(ip)) {
436
465
  throw new SsrfError("Hostname resolver returned a non-IP address");
437
466
  }
438
- if (isPrivateIp(ip)) {
439
- throw new SsrfError("Hostname resolves to a private IP address");
467
+ if (isNonPublicIp(ip)) {
468
+ throw new SsrfError("Hostname resolves to a non-public IP address");
440
469
  }
441
470
  }
442
471
 
443
472
  return { url: parsed, addresses };
444
473
  }
445
474
 
446
- /** True when a string looks like an IPv4 or IPv6 literal. */
475
+ /** True when a string is a valid IPv4 or IPv6 literal. */
447
476
  function isIpLiteral(host: string): boolean {
448
- if (parseIpv4(host) !== null) return true;
449
- // Very loose IPv6 heuristic — matches anything with a colon, which is
450
- // never valid in DNS hostnames, so this is safe.
451
- return host.includes(":");
477
+ return parseIpv4(host) !== null || parseIpv6(host) !== null;
452
478
  }
453
479
 
454
480
  /**
package/src/seed/apply.ts CHANGED
@@ -199,7 +199,9 @@ export async function applySeed(
199
199
  routable: collection.routable,
200
200
  hidden: collection.hidden,
201
201
  sortOrder: collection.sortOrder,
202
+ group: collection.group,
202
203
  commentsEnabled: collection.commentsEnabled,
204
+ editLocking: collection.editLocking,
203
205
  });
204
206
  result.collections.updated++;
205
207
 
@@ -277,7 +279,9 @@ export async function applySeed(
277
279
  routable: collection.routable,
278
280
  hidden: collection.hidden,
279
281
  sortOrder: collection.sortOrder,
282
+ group: collection.group,
280
283
  commentsEnabled: collection.commentsEnabled,
284
+ editLocking: collection.editLocking,
281
285
  },
282
286
  fields,
283
287
  );
package/src/seed/types.ts CHANGED
@@ -78,8 +78,9 @@ export interface SeedCollection {
78
78
  /** Require a slug before an entry can be published. Defaults to true. */
79
79
  routable?: boolean;
80
80
  /**
81
- * Omit this collection from the admin sidebar. It stays reachable through
82
- * the API, MCP, plugin hooks, and direct `/content/:collection` URLs.
81
+ * Omit this collection from the admin sidebar and the dashboard quick
82
+ * actions. It stays reachable through the API, MCP, plugin hooks, and
83
+ * direct `/content/:collection` URLs.
83
84
  */
84
85
  hidden?: boolean;
85
86
  /**
@@ -87,8 +88,12 @@ export interface SeedCollection {
87
88
  * a `sortOrder` keep the alphabetical order and follow the ordered ones.
88
89
  */
89
90
  sortOrder?: number;
91
+ /** Admin sidebar folder shared with other collections of the same group. */
92
+ group?: string;
90
93
  /** Enable comments on this collection */
91
94
  commentsEnabled?: boolean;
95
+ /** Take an edit lock when an entry is opened (defaults to true) */
96
+ editLocking?: boolean;
92
97
  /** Field slug powering the admin list Title column (defaults to title display) */
93
98
  titleField?: string;
94
99
  /** Field slug (a datetime field) powering the admin list Date column (defaults to last-updated) */
@@ -5,7 +5,12 @@
5
5
  */
6
6
 
7
7
  import { getI18nConfig, resolveConfiguredLocale } from "../i18n/config.js";
8
- import { FIELD_TYPES, isIndexableFieldType, MAX_COLLECTION_LIST_COLUMNS } from "../schema/types.js";
8
+ import {
9
+ FIELD_TYPES,
10
+ isIndexableFieldType,
11
+ MAX_COLLECTION_GROUP_LENGTH,
12
+ MAX_COLLECTION_LIST_COLUMNS,
13
+ } from "../schema/types.js";
9
14
  import type { SeedFile, SeedMenuItem, ValidationResult } from "./types.js";
10
15
 
11
16
  const COLLECTION_FIELD_SLUG_PATTERN = /^[a-z][a-z0-9_]*$/;
@@ -107,9 +112,21 @@ export function validateSeed(data: unknown): ValidationResult {
107
112
  if (!collection.label) {
108
113
  errors.push(`${prefix}: label is required`);
109
114
  }
115
+ if (collection.editLocking !== undefined && typeof collection.editLocking !== "boolean") {
116
+ errors.push(`${prefix}.editLocking: must be a boolean`);
117
+ }
110
118
  if (collection.routable !== undefined && typeof collection.routable !== "boolean") {
111
119
  errors.push(`${prefix}.routable: must be a boolean`);
112
120
  }
121
+ if (collection.group !== undefined) {
122
+ if (typeof collection.group !== "string") {
123
+ errors.push(`${prefix}.group: must be a string`);
124
+ } else if (collection.group.trim().length > MAX_COLLECTION_GROUP_LENGTH) {
125
+ errors.push(
126
+ `${prefix}.group: must be at most ${MAX_COLLECTION_GROUP_LENGTH} characters`,
127
+ );
128
+ }
129
+ }
113
130
 
114
131
  const declaredFieldSlugs = new Set(
115
132
  Array.isArray(collection.fields)
@@ -167,6 +167,7 @@ export async function getHreflangAlternatesWithDb(
167
167
  collection,
168
168
  slug: variant.slug || variant.id,
169
169
  id: variant.id,
170
+ date: variant.publishedAt,
170
171
  });
171
172
  const localized = await localizePath(path, locale);
172
173
  if (localized === null) continue;
package/src/seo/index.ts CHANGED
@@ -30,13 +30,12 @@
30
30
  */
31
31
 
32
32
  import type { ContentSeo } from "../database/repositories/types.js";
33
- import { buildSeoImageUrl } from "./media-url.js";
33
+ import { buildSeoImageUrl, resolveSeoCanonicalUrl } from "./media-url.js";
34
34
 
35
35
  export { getHreflangAlternates, getHreflangAlternatesWithDb } from "./hreflang.js";
36
36
  export type { HreflangAlternate, HreflangOptions } from "./hreflang.js";
37
37
 
38
38
  const TRAILING_SLASH_RE = /\/$/;
39
- const ABSOLUTE_URL_RE = /^https?:\/\//i;
40
39
 
41
40
  /**
42
41
  * Content input for SEO functions.
@@ -138,16 +137,12 @@ export function getSeoMeta<T>(content: SeoContentInput<T>, options: SeoMetaOptio
138
137
  // OG image: SEO image > default
139
138
  const ogImage = seo.image ? buildSeoImageUrl(seo.image, siteUrl) : (defaultOgImage ?? null);
140
139
 
141
- // Canonical: explicit > path-based > null
140
+ // Canonical: explicit > path-based > null. The explicit value goes
141
+ // through the same resolver as the <EmDashHead> overlay, so a panel
142
+ // canonical renders identically on both paths.
142
143
  let canonical: string | null = null;
143
144
  if (seo.canonical) {
144
- // Ensure relative canonical paths get a leading slash so we don't
145
- // produce "https://example.composts/x" when joined with siteUrl
146
- if (siteUrl && !seo.canonical.startsWith("/") && !ABSOLUTE_URL_RE.test(seo.canonical)) {
147
- canonical = `${siteUrl.replace(TRAILING_SLASH_RE, "")}/${seo.canonical}`;
148
- } else {
149
- canonical = seo.canonical;
150
- }
145
+ canonical = resolveSeoCanonicalUrl(seo.canonical, siteUrl);
151
146
  } else if (siteUrl && path) {
152
147
  const safePath = path.startsWith("/") ? path : `/${path}`;
153
148
  canonical = `${siteUrl.replace(TRAILING_SLASH_RE, "")}${safePath}`;
@@ -20,6 +20,12 @@ export function buildSeoImageUrl(imageRef: string, siteUrl?: string): string {
20
20
  return imageRef;
21
21
  }
22
22
 
23
+ // `//host/path` is protocol-relative — already qualified, not a path
24
+ // to prefix with the site URL.
25
+ if (imageRef.startsWith("//")) {
26
+ return imageRef;
27
+ }
28
+
23
29
  // Root-relative path (already includes the media API prefix). Without
24
30
  // this branch we'd re-prefix and produce a doubled path that 404s.
25
31
  if (imageRef.startsWith("/")) {
@@ -30,3 +36,23 @@ export function buildSeoImageUrl(imageRef: string, siteUrl?: string): string {
30
36
  const mediaPath = `/_emdash/api/media/file/${imageRef}`;
31
37
  return siteUrl ? `${siteUrl.replace(TRAILING_SLASH_RE, "")}${mediaPath}` : mediaPath;
32
38
  }
39
+
40
+ /**
41
+ * Resolve a stored SEO canonical value to a URL.
42
+ *
43
+ * The SEO panel accepts absolute URLs, root-relative paths, and bare
44
+ * relative paths. Relative paths are joined with `siteUrl` (adding a
45
+ * leading slash when missing, so we never produce
46
+ * `https://example.composts/x`). Without a `siteUrl` the value is
47
+ * returned as-is. Absolute output matters here: the resolved value feeds
48
+ * `<link rel="canonical">` and `og:url`, both of which search engines and
49
+ * scrapers expect fully qualified.
50
+ */
51
+ export function resolveSeoCanonicalUrl(canonical: string, siteUrl?: string): string {
52
+ // `//host/path` is protocol-relative — already qualified, not a path.
53
+ if (!siteUrl || ABSOLUTE_URL_RE.test(canonical) || canonical.startsWith("//")) {
54
+ return canonical;
55
+ }
56
+ const path = canonical.startsWith("/") ? canonical : `/${canonical}`;
57
+ return `${siteUrl.replace(TRAILING_SLASH_RE, "")}${path}`;
58
+ }
@@ -19,6 +19,10 @@ import { sql } from "kysely";
19
19
  import { buildStatusCondition, compoundSelectLimit } from "../database/dialect-helpers.js";
20
20
  import type { Database } from "../database/types.js";
21
21
  import { validateIdentifier } from "../database/validate.js";
22
+ import {
23
+ filterToRegisteredCollections,
24
+ noteStaleRegisteredCollections,
25
+ } from "../schema/collection-slugs-cache.js";
22
26
  import { chunks } from "../utils/chunks.js";
23
27
  import { isMissingTableError } from "../utils/db-errors.js";
24
28
 
@@ -100,6 +104,11 @@ async function runBatch(
100
104
  return await runCounts(db, taxonomyName, collections, locale);
101
105
  } catch (error) {
102
106
  if (!isMissingTableError(error)) throw error;
107
+ // The slug filter let a missing table through: the collection was
108
+ // deleted on another isolate (stale cache) or the registry drifted
109
+ // from the physical schema. Window-gated, so the delete case stops
110
+ // sending failing statements within one revalidation window.
111
+ noteStaleRegisteredCollections();
103
112
  }
104
113
 
105
114
  const counts = new Map<string, number>();
@@ -120,10 +129,15 @@ async function runBatch(
120
129
  * it preserves the locale-agnostic API used by legacy callers.
121
130
  *
122
131
  * Counts are scoped to the taxonomy's declared collections — pass
123
- * `TaxonomyDef.collections` (`_emdash_taxonomy_defs.collections`). Collections
124
- * whose `ec_*` table doesn't exist (pre-migration drift, a declared collection
125
- * that was never created) are skipped, yielding a partial-but-correct count
126
- * rather than a throw.
132
+ * `TaxonomyDef.collections` (`_emdash_taxonomy_defs.collections`). Declared
133
+ * collections without a `_emdash_collections` row (the migration-seeded
134
+ * defaults declare `posts` unconditionally) are filtered out before any SQL
135
+ * is built, so no statement referencing a missing `ec_*` table is sent — a
136
+ * failed statement is logged by the database even when the caller recovers,
137
+ * flooding D1 observability with phantom errors. The missing-table guards in
138
+ * `runBatch` stay as the backstop for registry/table drift (e.g. a partially
139
+ * applied D1 create) and for a table dropped mid-flight, yielding a
140
+ * partial-but-correct count rather than a throw.
127
141
  *
128
142
  * One database round-trip for the whole taxonomy (UNION ALL across
129
143
  * collections). On a backend that caps compound-SELECT terms — D1 allows five
@@ -146,8 +160,11 @@ export async function fetchVisibleTermCounts(
146
160
  for (const collection of unique) validateIdentifier(collection, "collection slug");
147
161
  if (unique.length === 0) return new Map();
148
162
 
163
+ const present = await filterToRegisteredCollections(db, unique);
164
+ if (present.length === 0) return new Map();
165
+
149
166
  const limit = compoundSelectLimit(db);
150
- const batched = limit === null ? [unique] : chunks(unique, limit);
167
+ const batched = limit === null ? [present] : chunks(present, limit);
151
168
  const batches = await Promise.all(
152
169
  batched.map((batch) => runBatch(db, taxonomyName, batch, locale)),
153
170
  );