emdash 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (650) hide show
  1. package/dist/{adapters-9DybjTO6.d.mts → adapters-C4yd_UJR.d.mts} +1 -1
  2. package/dist/{adapters-9DybjTO6.d.mts.map → adapters-C4yd_UJR.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-CDdG-4Gd.mjs → allowed-origins-D0fFk9a6.mjs} +2 -2
  4. package/dist/{allowed-origins-CDdG-4Gd.mjs.map → allowed-origins-D0fFk9a6.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +15 -15
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +3 -3
  9. package/dist/{api-BMLZuwM4.mjs → api-BNKqxyFX.mjs} +560 -56
  10. package/dist/api-BNKqxyFX.mjs.map +1 -0
  11. package/dist/{api-tokens-eYymBhIT.mjs → api-tokens-ucpcNXDt.mjs} +2 -2
  12. package/dist/{api-tokens-eYymBhIT.mjs.map → api-tokens-ucpcNXDt.mjs.map} +1 -1
  13. package/dist/{apply-v4DBgjPw.mjs → apply-BOPaD-s9.mjs} +17 -17
  14. package/dist/{apply-v4DBgjPw.mjs.map → apply-BOPaD-s9.mjs.map} +1 -1
  15. package/dist/astro/index.d.mts +10 -10
  16. package/dist/astro/index.d.mts.map +1 -1
  17. package/dist/astro/index.mjs +53 -5
  18. package/dist/astro/index.mjs.map +1 -1
  19. package/dist/astro/middleware/auth.d.mts +9 -9
  20. package/dist/astro/middleware/auth.mjs +6 -6
  21. package/dist/astro/middleware/auth.mjs.map +1 -1
  22. package/dist/astro/middleware/redirect.mjs +4 -4
  23. package/dist/astro/middleware/request-context.mjs +3 -3
  24. package/dist/astro/middleware/request-context.mjs.map +1 -1
  25. package/dist/astro/middleware/setup.mjs +1 -1
  26. package/dist/astro/middleware.d.mts.map +1 -1
  27. package/dist/astro/middleware.mjs +377 -75
  28. package/dist/astro/middleware.mjs.map +1 -1
  29. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  30. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  31. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  32. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  33. package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -1
  34. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -17
  35. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  36. package/dist/astro/routes/api/admin/bylines/_id_/translations.d.mts +9 -0
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.d.mts.map +1 -0
  38. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +70 -0
  39. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -0
  40. package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -1
  41. package/dist/astro/routes/api/admin/bylines/index.mjs +25 -16
  42. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  43. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
  44. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  45. package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
  46. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  47. package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
  48. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  49. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  50. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  51. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  52. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +33 -32
  53. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +33 -32
  55. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  56. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +32 -31
  57. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  58. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +32 -31
  59. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  60. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +34 -32
  61. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  62. package/dist/astro/routes/api/admin/plugins/index.mjs +32 -31
  63. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +32 -31
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +34 -32
  68. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +32 -31
  70. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts +8 -0
  72. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts.map +1 -0
  73. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +59 -0
  74. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -0
  75. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts +8 -0
  76. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -0
  77. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +85 -0
  78. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -0
  79. package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts +8 -0
  80. package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -0
  81. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +301 -0
  82. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -0
  83. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +51 -32
  85. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -1
  87. package/dist/astro/routes/api/admin/plugins/updates.mjs +45 -32
  88. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  89. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +32 -31
  90. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  91. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  92. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +32 -31
  93. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  95. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  96. package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
  97. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  98. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  99. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  100. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  101. package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
  102. package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
  103. package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
  104. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  105. package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
  106. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  107. package/dist/astro/routes/api/auth/me.mjs +5 -5
  108. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  109. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  110. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -1
  111. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  112. package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -1
  113. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  114. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  115. package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
  116. package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
  117. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
  118. package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
  119. package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
  120. package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
  121. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  122. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
  123. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  124. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  125. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  126. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  127. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs.map +1 -1
  128. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  129. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
  130. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
  131. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  132. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  133. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs.map +1 -1
  134. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  135. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
  136. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  137. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +10 -9
  138. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  139. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  140. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -1
  141. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  142. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  143. package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -6
  144. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  145. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  146. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  147. package/dist/astro/routes/api/dashboard.mjs +7 -7
  148. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  149. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  150. package/dist/astro/routes/api/import/probe.mjs +10 -10
  151. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  152. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  153. package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -8
  154. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  155. package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
  156. package/dist/astro/routes/api/import/wordpress/prepare.mjs +8 -8
  157. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
  158. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts +11 -1
  159. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts.map +1 -1
  160. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs +17 -1
  161. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs.map +1 -1
  162. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  163. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +9 -9
  164. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  165. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  166. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
  167. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  168. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +11 -11
  169. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  170. package/dist/astro/routes/api/manifest.mjs +4 -4
  171. package/dist/astro/routes/api/mcp.mjs +29 -29
  172. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  173. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  174. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  175. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  176. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  177. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  178. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  179. package/dist/astro/routes/api/media/upload-url.mjs +7 -7
  180. package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
  181. package/dist/astro/routes/api/media.mjs +8 -8
  182. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
  183. package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
  184. package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
  185. package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
  186. package/dist/astro/routes/api/menus/_name_.mjs +7 -7
  187. package/dist/astro/routes/api/menus/index.mjs +7 -7
  188. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  189. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  190. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  191. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  192. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  193. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  194. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  195. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  196. package/dist/astro/routes/api/openapi.json.mjs +3 -3
  197. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  198. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  199. package/dist/astro/routes/api/redirects/404s/index.mjs +8 -8
  200. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  201. package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
  202. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  203. package/dist/astro/routes/api/redirects/_id_.mjs +9 -9
  204. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  205. package/dist/astro/routes/api/redirects/index.mjs +9 -9
  206. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  207. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  208. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  209. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +32 -31
  210. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  211. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +32 -31
  212. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  213. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +32 -31
  214. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  215. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +32 -31
  216. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  217. package/dist/astro/routes/api/schema/collections/index.mjs +32 -31
  218. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  219. package/dist/astro/routes/api/schema/index.mjs +6 -6
  220. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  221. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +32 -31
  222. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  223. package/dist/astro/routes/api/schema/orphans/index.mjs +32 -31
  224. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  225. package/dist/astro/routes/api/search/enable.mjs +9 -9
  226. package/dist/astro/routes/api/search/index.mjs +8 -8
  227. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  228. package/dist/astro/routes/api/search/stats.mjs +6 -6
  229. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  230. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  231. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  232. package/dist/astro/routes/api/sections/index.mjs +8 -8
  233. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  234. package/dist/astro/routes/api/settings/email.mjs +4 -4
  235. package/dist/astro/routes/api/settings.mjs +10 -10
  236. package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
  237. package/dist/astro/routes/api/setup/admin.mjs +9 -9
  238. package/dist/astro/routes/api/setup/dev-bypass.mjs +22 -22
  239. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  240. package/dist/astro/routes/api/setup/index.mjs +22 -22
  241. package/dist/astro/routes/api/setup/status.mjs +4 -4
  242. package/dist/astro/routes/api/snapshot.mjs +6 -6
  243. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  244. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -10
  245. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  246. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -10
  247. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  248. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -10
  249. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  250. package/dist/astro/routes/api/taxonomies/index.mjs +11 -10
  251. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  252. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  253. package/dist/astro/routes/api/typegen.mjs +5 -5
  254. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  255. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  256. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  257. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  258. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
  259. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
  260. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  261. package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
  262. package/dist/astro/routes/api/widget-components.mjs +3 -3
  263. package/dist/astro/routes/robots.txt.mjs +5 -5
  264. package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
  265. package/dist/astro/routes/sitemap-_collection_.xml.mjs +58 -13
  266. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  267. package/dist/astro/routes/sitemap.xml.mjs +6 -6
  268. package/dist/astro/types.d.mts +20 -12
  269. package/dist/astro/types.d.mts.map +1 -1
  270. package/dist/auth/providers/github.d.mts +1 -1
  271. package/dist/auth/providers/google.d.mts +1 -1
  272. package/dist/{authorize-BlyCH-96.mjs → authorize-Bn4S4DUT.mjs} +2 -2
  273. package/dist/{authorize-BlyCH-96.mjs.map → authorize-Bn4S4DUT.mjs.map} +1 -1
  274. package/dist/byline-BDylH_m4.mjs +404 -0
  275. package/dist/byline-BDylH_m4.mjs.map +1 -0
  276. package/dist/{bylines-BdUP8NuI.d.mts → bylines-B2_XmnSU.d.mts} +73 -28
  277. package/dist/bylines-B2_XmnSU.d.mts.map +1 -0
  278. package/dist/bylines-B7TFEvFf.mjs +118 -0
  279. package/dist/bylines-B7TFEvFf.mjs.map +1 -0
  280. package/dist/bylines-n6nykUyI.mjs +174 -0
  281. package/dist/bylines-n6nykUyI.mjs.map +1 -0
  282. package/dist/{cache-CXCpjWiL.mjs → cache-BcI1yUjR.mjs} +2 -2
  283. package/dist/{cache-CXCpjWiL.mjs.map → cache-BcI1yUjR.mjs.map} +1 -1
  284. package/dist/{challenge-store-CJ0OOHOr.mjs → challenge-store-Dng1SxKT.mjs} +1 -1
  285. package/dist/{challenge-store-CJ0OOHOr.mjs.map → challenge-store-Dng1SxKT.mjs.map} +1 -1
  286. package/dist/{chunks-DyGtu1Bv.mjs → chunks-cYG4SnIP.mjs} +2 -2
  287. package/dist/{chunks-DyGtu1Bv.mjs.map → chunks-cYG4SnIP.mjs.map} +1 -1
  288. package/dist/cli/index.mjs +68 -30
  289. package/dist/cli/index.mjs.map +1 -1
  290. package/dist/client/cf-access.d.mts +1 -1
  291. package/dist/client/index.d.mts +1 -1
  292. package/dist/client/index.mjs +1 -1
  293. package/dist/client/index.mjs.map +1 -1
  294. package/dist/{comment-Dd9MI82-.mjs → comment-C76G-9tz.mjs} +2 -2
  295. package/dist/{comment-Dd9MI82-.mjs.map → comment-C76G-9tz.mjs.map} +1 -1
  296. package/dist/{comments-koGI0FrK.mjs → comments-CCxFFGY1.mjs} +3 -3
  297. package/dist/{comments-koGI0FrK.mjs.map → comments-CCxFFGY1.mjs.map} +1 -1
  298. package/dist/{components-mZem7pbe.mjs → components-Dx3DM0gg.mjs} +1 -1
  299. package/dist/{components-mZem7pbe.mjs.map → components-Dx3DM0gg.mjs.map} +1 -1
  300. package/dist/config-CVssduLe.mjs.map +1 -1
  301. package/dist/{content-D6YG26WG.mjs → content-8voQNTXX.mjs} +3 -3
  302. package/dist/{content-D6YG26WG.mjs.map → content-8voQNTXX.mjs.map} +1 -1
  303. package/dist/{context-qF8d3IPR.mjs → context-B7qiYrz2.mjs} +10 -10
  304. package/dist/context-B7qiYrz2.mjs.map +1 -0
  305. package/dist/{cron-H8eJ46dv.mjs → cron-Bd3b3iuj.mjs} +1 -1
  306. package/dist/{cron-H8eJ46dv.mjs.map → cron-Bd3b3iuj.mjs.map} +1 -1
  307. package/dist/{dashboard-BmWSIUwY.mjs → dashboard-BeaFSPpx.mjs} +4 -4
  308. package/dist/{dashboard-BmWSIUwY.mjs.map → dashboard-BeaFSPpx.mjs.map} +1 -1
  309. package/dist/db/index.d.mts +3 -3
  310. package/dist/db/index.mjs +1 -1
  311. package/dist/db/libsql.d.mts +1 -1
  312. package/dist/db/postgres.d.mts +1 -1
  313. package/dist/db/sqlite.d.mts +1 -1
  314. package/dist/db/sqlite.mjs +1 -1
  315. package/dist/{db-errors-CGN9kJfo.mjs → db-errors-BiYqoX-n.mjs} +14 -2
  316. package/dist/db-errors-BiYqoX-n.mjs.map +1 -0
  317. package/dist/{default-Dbs22Gg4.mjs → default-BvTAYCzx.mjs} +1 -1
  318. package/dist/{default-Dbs22Gg4.mjs.map → default-BvTAYCzx.mjs.map} +1 -1
  319. package/dist/{device-flow-BqJRxa0Q.mjs → device-flow-B9oG8PwP.mjs} +4 -4
  320. package/dist/{device-flow-BqJRxa0Q.mjs.map → device-flow-B9oG8PwP.mjs.map} +1 -1
  321. package/dist/{email-console-Dmp5Q-P2.mjs → email-console-CubRll9q.mjs} +1 -1
  322. package/dist/email-console-CubRll9q.mjs.map +1 -0
  323. package/dist/{error-tSQWIl5U.mjs → error-ChfADBuu.mjs} +19 -9
  324. package/dist/error-ChfADBuu.mjs.map +1 -0
  325. package/dist/errors-9P_FDrJ_.mjs +17 -0
  326. package/dist/errors-9P_FDrJ_.mjs.map +1 -0
  327. package/dist/{escape-B8bdIryO.mjs → escape-Cg6kMELH.mjs} +1 -1
  328. package/dist/{escape-B8bdIryO.mjs.map → escape-Cg6kMELH.mjs.map} +1 -1
  329. package/dist/{fts-manager-B633C-kQ.mjs → fts-manager-C_b-4x8u.mjs} +2 -2
  330. package/dist/{fts-manager-B633C-kQ.mjs.map → fts-manager-C_b-4x8u.mjs.map} +1 -1
  331. package/dist/{import-CNfLOgDE.mjs → import-DG80rC_I.mjs} +3 -3
  332. package/dist/{import-CNfLOgDE.mjs.map → import-DG80rC_I.mjs.map} +1 -1
  333. package/dist/{index-BV8iJ-6s.d.mts → index-BPZFAcgE.d.mts} +384 -123
  334. package/dist/index-BPZFAcgE.d.mts.map +1 -0
  335. package/dist/{index-D2gvztOP.d.mts → index-CC42STEm.d.mts} +3 -3
  336. package/dist/{index-D2gvztOP.d.mts.map → index-CC42STEm.d.mts.map} +1 -1
  337. package/dist/index.d.mts +17 -17
  338. package/dist/index.mjs +53 -52
  339. package/dist/{load-QzYRpVN3.mjs → load-CLFRjk9r.mjs} +2 -2
  340. package/dist/{load-QzYRpVN3.mjs.map → load-CLFRjk9r.mjs.map} +1 -1
  341. package/dist/{loader-Cs6-Bqe6.mjs → loader-D-vIJjfY.mjs} +86 -46
  342. package/dist/loader-D-vIJjfY.mjs.map +1 -0
  343. package/dist/{manifest-schema-HCtSh4Jq.mjs → manifest-schema-Czqf0TLu.mjs} +1 -1
  344. package/dist/{manifest-schema-HCtSh4Jq.mjs.map → manifest-schema-Czqf0TLu.mjs.map} +1 -1
  345. package/dist/media/index.d.mts +1 -1
  346. package/dist/media/local-runtime.d.mts +11 -11
  347. package/dist/media/local-runtime.mjs +4 -4
  348. package/dist/{media-Dg7he9uK.mjs → media-CKQd8AYU.mjs} +2 -2
  349. package/dist/media-CKQd8AYU.mjs.map +1 -0
  350. package/dist/{media-allowlist-B8EX01DH.mjs → media-allowlist-BNloC69x.mjs} +1 -1
  351. package/dist/{media-allowlist-B8EX01DH.mjs.map → media-allowlist-BNloC69x.mjs.map} +1 -1
  352. package/dist/{menus-X4Z-eBA1.mjs → menus-C-nWT5Tu.mjs} +42 -17
  353. package/dist/menus-C-nWT5Tu.mjs.map +1 -0
  354. package/dist/{menus-DOzIecHi.mjs → menus-arUNspyU.mjs} +2 -2
  355. package/dist/menus-arUNspyU.mjs.map +1 -0
  356. package/dist/mime-KV5TqkMN.mjs.map +1 -1
  357. package/dist/{mode-DPRPvJYm.mjs → mode-CaaiebZI.mjs} +1 -1
  358. package/dist/{mode-DPRPvJYm.mjs.map → mode-CaaiebZI.mjs.map} +1 -1
  359. package/dist/{oauth-authorization-62GmpGIH.mjs → oauth-authorization-CTMeVfvj.mjs} +4 -4
  360. package/dist/{oauth-authorization-62GmpGIH.mjs.map → oauth-authorization-CTMeVfvj.mjs.map} +1 -1
  361. package/dist/{oauth-clients-D_B0_-Bz.mjs → oauth-clients-eJCbkVSG.mjs} +1 -1
  362. package/dist/oauth-clients-eJCbkVSG.mjs.map +1 -0
  363. package/dist/{oauth-state-store-DpsZViTu.mjs → oauth-state-store-vOSdOeGe.mjs} +1 -1
  364. package/dist/{oauth-state-store-DpsZViTu.mjs.map → oauth-state-store-vOSdOeGe.mjs.map} +1 -1
  365. package/dist/{oauth-user-lookup-meyS2oB1.mjs → oauth-user-lookup-3JwsVw6N.mjs} +1 -1
  366. package/dist/{oauth-user-lookup-meyS2oB1.mjs.map → oauth-user-lookup-3JwsVw6N.mjs.map} +1 -1
  367. package/dist/options-BL4X94qY.mjs.map +1 -1
  368. package/dist/{options-Cq64Wx0O.d.mts → options-DhV-gwJb.d.mts} +4 -4
  369. package/dist/options-DhV-gwJb.d.mts.map +1 -0
  370. package/dist/page/index.d.mts +2 -2
  371. package/dist/{parse-BFTPon-J.mjs → parse-DHbXfvxO.mjs} +2 -2
  372. package/dist/{parse-BFTPon-J.mjs.map → parse-DHbXfvxO.mjs.map} +1 -1
  373. package/dist/{passkey-config-Cg86_ISa.mjs → passkey-config-BloQOT3y.mjs} +1 -1
  374. package/dist/{passkey-config-Cg86_ISa.mjs.map → passkey-config-BloQOT3y.mjs.map} +1 -1
  375. package/dist/{placeholder-D3cFCU9y.d.mts → placeholder-KCkkCtgQ.d.mts} +1 -1
  376. package/dist/{placeholder-D3cFCU9y.d.mts.map → placeholder-KCkkCtgQ.d.mts.map} +1 -1
  377. package/dist/plugin-types.d.mts +1 -1
  378. package/dist/plugin-utils.d.mts +25 -10
  379. package/dist/plugin-utils.d.mts.map +1 -1
  380. package/dist/plugin-utils.mjs +11 -10
  381. package/dist/plugin-utils.mjs.map +1 -1
  382. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  383. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  384. package/dist/plugins/adapt-sandbox-entry.mjs +26 -15
  385. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  386. package/dist/{preview-C1LOEbWZ.mjs → preview-D4z0WONU.mjs} +2 -2
  387. package/dist/{preview-C1LOEbWZ.mjs.map → preview-D4z0WONU.mjs.map} +1 -1
  388. package/dist/{public-url-CseXl9Fv.mjs → public-url-CUWWFME2.mjs} +1 -1
  389. package/dist/{public-url-CseXl9Fv.mjs.map → public-url-CUWWFME2.mjs.map} +1 -1
  390. package/dist/{query-axZmO6Tn.mjs → query-7m6-l0f_.mjs} +27 -17
  391. package/dist/query-7m6-l0f_.mjs.map +1 -0
  392. package/dist/{rate-limit-t5CVjCO6.mjs → rate-limit-D8RAXN8b.mjs} +2 -2
  393. package/dist/{rate-limit-t5CVjCO6.mjs.map → rate-limit-D8RAXN8b.mjs.map} +1 -1
  394. package/dist/{redirect-DGRsLO2I.mjs → redirect-BINiRYq4.mjs} +1 -1
  395. package/dist/{redirect-DGRsLO2I.mjs.map → redirect-BINiRYq4.mjs.map} +1 -1
  396. package/dist/{redirect-DkaDxq8e.mjs → redirect-CjfDGrTd.mjs} +2 -2
  397. package/dist/{redirect-DkaDxq8e.mjs.map → redirect-CjfDGrTd.mjs.map} +1 -1
  398. package/dist/{redirects-Dmj6KRU3.mjs → redirects-COMLwsV5.mjs} +19 -5
  399. package/dist/redirects-COMLwsV5.mjs.map +1 -0
  400. package/dist/{redirects-D1fdd68T.mjs → redirects-CowoEHdE.mjs} +3 -3
  401. package/dist/{redirects-D1fdd68T.mjs.map → redirects-CowoEHdE.mjs.map} +1 -1
  402. package/dist/{registry-BnCeHYsf.mjs → registry-Cyp-dx6J.mjs} +4 -4
  403. package/dist/{registry-BnCeHYsf.mjs.map → registry-Cyp-dx6J.mjs.map} +1 -1
  404. package/dist/request-cache-dzCt8TZB.mjs.map +1 -1
  405. package/dist/request-context.mjs.map +1 -1
  406. package/dist/{request-meta-CLCwSQOS.mjs → request-meta-C_Cjii-T.mjs} +2 -2
  407. package/dist/{request-meta-CLCwSQOS.mjs.map → request-meta-C_Cjii-T.mjs.map} +1 -1
  408. package/dist/resolve-D6sM-SgF.mjs +143 -0
  409. package/dist/resolve-D6sM-SgF.mjs.map +1 -0
  410. package/dist/{runner-DcfZewkO.d.mts → runner-DSQBurMS.d.mts} +8 -5
  411. package/dist/runner-DSQBurMS.d.mts.map +1 -0
  412. package/dist/{runner-DdnQIwz_.mjs → runner-Drnvs96u.mjs} +491 -188
  413. package/dist/runner-Drnvs96u.mjs.map +1 -0
  414. package/dist/runtime.d.mts +10 -10
  415. package/dist/runtime.mjs +2 -2
  416. package/dist/{schema-BmqagCwG.mjs → schema-CI9mYPX3.mjs} +4 -4
  417. package/dist/{schema-BmqagCwG.mjs.map → schema-CI9mYPX3.mjs.map} +1 -1
  418. package/dist/{search-CPrvO5u8.mjs → search-DKz_mGBP.mjs} +4 -4
  419. package/dist/{search-CPrvO5u8.mjs.map → search-DKz_mGBP.mjs.map} +1 -1
  420. package/dist/{secrets-6pgZyq0K.mjs → secrets-rPdhEBkD.mjs} +1 -1
  421. package/dist/{secrets-6pgZyq0K.mjs.map → secrets-rPdhEBkD.mjs.map} +1 -1
  422. package/dist/{sections-Cm-zb-gZ.mjs → sections-DBbCDIAT.mjs} +3 -3
  423. package/dist/{sections-Cm-zb-gZ.mjs.map → sections-DBbCDIAT.mjs.map} +1 -1
  424. package/dist/seed/index.d.mts +2 -2
  425. package/dist/seed/index.mjs +16 -16
  426. package/dist/seo/index.d.mts +1 -1
  427. package/dist/{seo-DRq9-EPP.mjs → seo-BGCyDlkb.mjs} +2 -2
  428. package/dist/{seo-DRq9-EPP.mjs.map → seo-BGCyDlkb.mjs.map} +1 -1
  429. package/dist/{seo-BoR4wCUh.mjs → seo-Dq707mNQ.mjs} +5 -3
  430. package/dist/seo-Dq707mNQ.mjs.map +1 -0
  431. package/dist/{service-vByySp-2.mjs → service-B0H7U1Y9.mjs} +3 -3
  432. package/dist/{service-vByySp-2.mjs.map → service-B0H7U1Y9.mjs.map} +1 -1
  433. package/dist/{settings-xQKsWnzQ.mjs → settings-BSXRtTzk.mjs} +3 -3
  434. package/dist/settings-BSXRtTzk.mjs.map +1 -0
  435. package/dist/{settings-CBBj7HUd.mjs → settings-DfwNyQkf.mjs} +3 -3
  436. package/dist/{settings-CBBj7HUd.mjs.map → settings-DfwNyQkf.mjs.map} +1 -1
  437. package/dist/{setup-BGAJ2uXs.mjs → setup-Cf_TyOv5.mjs} +2 -2
  438. package/dist/{setup-BGAJ2uXs.mjs.map → setup-Cf_TyOv5.mjs.map} +1 -1
  439. package/dist/{setup-complete-C6ZCLhKo.mjs → setup-complete-MzzN9u0b.mjs} +1 -1
  440. package/dist/{setup-complete-C6ZCLhKo.mjs.map → setup-complete-MzzN9u0b.mjs.map} +1 -1
  441. package/dist/{setup-nonce-CY1gQiAU.mjs → setup-nonce-DXuriHsg.mjs} +1 -1
  442. package/dist/{setup-nonce-CY1gQiAU.mjs.map → setup-nonce-DXuriHsg.mjs.map} +1 -1
  443. package/dist/{site-url-D-M4Fd8O.mjs → site-url-xkhw1tcz.mjs} +1 -1
  444. package/dist/{site-url-D-M4Fd8O.mjs.map → site-url-xkhw1tcz.mjs.map} +1 -1
  445. package/dist/{ssrf-DzFN_qV-.mjs → ssrf-MZ-zrG6-.mjs} +1 -1
  446. package/dist/{ssrf-DzFN_qV-.mjs.map → ssrf-MZ-zrG6-.mjs.map} +1 -1
  447. package/dist/storage/local.d.mts +1 -1
  448. package/dist/storage/local.mjs +1 -1
  449. package/dist/storage/local.mjs.map +1 -1
  450. package/dist/storage/s3.d.mts +1 -1
  451. package/dist/storage/s3.mjs +1 -1
  452. package/dist/storage/s3.mjs.map +1 -1
  453. package/dist/{taxonomies-Dc0mzlms.mjs → taxonomies-4vx0nmMr.mjs} +4 -4
  454. package/dist/{taxonomies-Dc0mzlms.mjs.map → taxonomies-4vx0nmMr.mjs.map} +1 -1
  455. package/dist/{taxonomies-Cn9UpaR2.mjs → taxonomies-CcvrMLbR.mjs} +8 -43
  456. package/dist/taxonomies-CcvrMLbR.mjs.map +1 -0
  457. package/dist/{taxonomy-wPfusMK9.mjs → taxonomy-zqGQUqgu.mjs} +3 -3
  458. package/dist/{taxonomy-wPfusMK9.mjs.map → taxonomy-zqGQUqgu.mjs.map} +1 -1
  459. package/dist/{tokens-DILYNZMi.mjs → tokens-N8otWMmj.mjs} +1 -1
  460. package/dist/{tokens-DILYNZMi.mjs.map → tokens-N8otWMmj.mjs.map} +1 -1
  461. package/dist/{transport-fw-mKJzT.mjs → transport-B6CHddbu.mjs} +1 -1
  462. package/dist/{transport-fw-mKJzT.mjs.map → transport-B6CHddbu.mjs.map} +1 -1
  463. package/dist/{transport-GeXlLscf.d.mts → transport-C2MGqtL6.d.mts} +1 -1
  464. package/dist/{transport-GeXlLscf.d.mts.map → transport-C2MGqtL6.d.mts.map} +1 -1
  465. package/dist/{trusted-proxy-CJhQIk65.mjs → trusted-proxy-97pajC2f.mjs} +1 -1
  466. package/dist/{trusted-proxy-CJhQIk65.mjs.map → trusted-proxy-97pajC2f.mjs.map} +1 -1
  467. package/dist/{types-CwXMEPRr.mjs → types-B0bmgwMG.mjs} +2 -2
  468. package/dist/types-B0bmgwMG.mjs.map +1 -0
  469. package/dist/{types-Dz9CGX_d.mjs → types-Cd9UCu3t.mjs} +1 -1
  470. package/dist/{types-Dz9CGX_d.mjs.map → types-Cd9UCu3t.mjs.map} +1 -1
  471. package/dist/{types-DmxPPXGf.d.mts → types-CkDSF81F.d.mts} +1 -1
  472. package/dist/{types-DmxPPXGf.d.mts.map → types-CkDSF81F.d.mts.map} +1 -1
  473. package/dist/{types-BWhaSS7U.d.mts → types-CpUuGcd5.d.mts} +1 -1
  474. package/dist/{types-BWhaSS7U.d.mts.map → types-CpUuGcd5.d.mts.map} +1 -1
  475. package/dist/{types-DFowNO60.d.mts → types-D599-ruj.d.mts} +1 -1
  476. package/dist/{types-DFowNO60.d.mts.map → types-D599-ruj.d.mts.map} +1 -1
  477. package/dist/{types-B05e2naf.d.mts → types-DGHWRQgr.d.mts} +3 -3
  478. package/dist/{types-B05e2naf.d.mts.map → types-DGHWRQgr.d.mts.map} +1 -1
  479. package/dist/{types-CzvJd1ND.d.mts → types-DaYDYW6g.d.mts} +14 -1
  480. package/dist/types-DaYDYW6g.d.mts.map +1 -0
  481. package/dist/{types-C1KKK4VP.d.mts → types-DaqNzqVt.d.mts} +16 -1
  482. package/dist/{types-C1KKK4VP.d.mts.map → types-DaqNzqVt.d.mts.map} +1 -1
  483. package/dist/{types-DW1l0gCv.d.mts → types-Dgo6y-Ut.d.mts} +1 -1
  484. package/dist/{types-DW1l0gCv.d.mts.map → types-Dgo6y-Ut.d.mts.map} +1 -1
  485. package/dist/{types-Cb2UCDJg.d.mts → types-bYmRn_Uy.d.mts} +1 -1
  486. package/dist/{types-Cb2UCDJg.d.mts.map → types-bYmRn_Uy.d.mts.map} +1 -1
  487. package/dist/{user-Dr1bOCqS.mjs → user-hUSOaIJy.mjs} +2 -2
  488. package/dist/{user-Dr1bOCqS.mjs.map → user-hUSOaIJy.mjs.map} +1 -1
  489. package/dist/{utils-_F-rWBTN.mjs → utils-C3wTAP-P.mjs} +1 -1
  490. package/dist/{utils-_F-rWBTN.mjs.map → utils-C3wTAP-P.mjs.map} +1 -1
  491. package/dist/{validate-BpQGsmd7.d.mts → validate-DQtHw9NT.d.mts} +5 -5
  492. package/dist/{validate-BpQGsmd7.d.mts.map → validate-DQtHw9NT.d.mts.map} +1 -1
  493. package/dist/{validate-DlFxcVVK.mjs → validate-IGltez8n.mjs} +2 -2
  494. package/dist/{validate-DlFxcVVK.mjs.map → validate-IGltez8n.mjs.map} +1 -1
  495. package/dist/{validation-BiFJqUp5.mjs → validation-Bmymau7y.mjs} +6 -6
  496. package/dist/{validation-BiFJqUp5.mjs.map → validation-Bmymau7y.mjs.map} +1 -1
  497. package/dist/version-BTc87L3L.mjs +7 -0
  498. package/dist/{version-DNmQakZO.mjs.map → version-BTc87L3L.mjs.map} +1 -1
  499. package/dist/{widgets-B9j_yzlk.mjs → widgets-yHQa4c6c.mjs} +3 -3
  500. package/dist/widgets-yHQa4c6c.mjs.map +1 -0
  501. package/dist/{zod-generator-DSyz01KE.mjs → zod-generator-B80aap1J.mjs} +2 -2
  502. package/dist/{zod-generator-DSyz01KE.mjs.map → zod-generator-B80aap1J.mjs.map} +1 -1
  503. package/package.json +12 -10
  504. package/src/api/error.ts +18 -3
  505. package/src/api/errors.ts +8 -0
  506. package/src/api/handlers/bylines.ts +161 -0
  507. package/src/api/handlers/content.ts +125 -43
  508. package/src/api/handlers/index.ts +8 -0
  509. package/src/api/handlers/marketplace.ts +27 -5
  510. package/src/api/handlers/oauth-clients.ts +1 -1
  511. package/src/api/handlers/registry.ts +622 -5
  512. package/src/api/handlers/seo.ts +16 -1
  513. package/src/api/handlers/snapshot.ts +1 -1
  514. package/src/api/openapi/document.ts +1 -1
  515. package/src/api/schemas/bylines.ts +46 -0
  516. package/src/astro/integration/index.ts +27 -1
  517. package/src/astro/integration/routes.ts +10 -0
  518. package/src/astro/integration/runtime.ts +20 -1
  519. package/src/astro/integration/virtual-modules.ts +19 -2
  520. package/src/astro/integration/vite-config.ts +2 -2
  521. package/src/astro/middleware/auth.ts +7 -7
  522. package/src/astro/middleware/request-context.ts +1 -1
  523. package/src/astro/middleware.ts +35 -20
  524. package/src/astro/public-plugin-api-routes.ts +41 -0
  525. package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -12
  526. package/src/astro/routes/api/admin/bylines/[id]/translations.ts +99 -0
  527. package/src/astro/routes/api/admin/bylines/index.ts +22 -11
  528. package/src/astro/routes/api/admin/plugins/[id]/update.ts +1 -0
  529. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +6 -1
  530. package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +51 -0
  531. package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +83 -0
  532. package/src/astro/routes/api/admin/plugins/registry/artifact.ts +388 -0
  533. package/src/astro/routes/api/admin/plugins/registry/install.ts +7 -1
  534. package/src/astro/routes/api/admin/plugins/updates.ts +43 -6
  535. package/src/astro/routes/api/admin/themes/marketplace/index.ts +1 -1
  536. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +2 -2
  537. package/src/astro/routes/api/auth/oauth/[provider].ts +2 -2
  538. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +2 -2
  539. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +2 -2
  540. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -2
  541. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +2 -2
  542. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +2 -2
  543. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +6 -6
  544. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
  545. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +2 -2
  546. package/src/astro/routes/api/content/[collection]/[id].ts +6 -6
  547. package/src/astro/routes/api/import/wordpress/execute.ts +1 -1
  548. package/src/astro/routes/api/import/wordpress/prepare.ts +2 -2
  549. package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +22 -0
  550. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +8 -5
  551. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +2 -2
  552. package/src/astro/routes/api/media/upload-url.ts +1 -1
  553. package/src/astro/routes/api/redirects/404s/index.ts +3 -3
  554. package/src/astro/routes/api/redirects/404s/summary.ts +1 -1
  555. package/src/astro/routes/api/redirects/[id].ts +3 -3
  556. package/src/astro/routes/api/redirects/index.ts +2 -2
  557. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +4 -4
  558. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +2 -6
  559. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +1 -1
  560. package/src/astro/routes/api/schema/collections/[slug]/index.ts +6 -6
  561. package/src/astro/routes/api/schema/collections/index.ts +4 -4
  562. package/src/astro/routes/api/schema/index.ts +1 -1
  563. package/src/astro/routes/api/schema/orphans/[slug].ts +1 -1
  564. package/src/astro/routes/api/schema/orphans/index.ts +1 -1
  565. package/src/astro/routes/api/sections/[slug].ts +3 -3
  566. package/src/astro/routes/api/sections/index.ts +2 -2
  567. package/src/astro/routes/sitemap-[collection].xml.ts +114 -14
  568. package/src/astro/types.ts +18 -0
  569. package/src/auth/rate-limit.ts +1 -1
  570. package/src/auth/trusted-proxy.ts +1 -1
  571. package/src/bylines/index.ts +154 -55
  572. package/src/cli/commands/init.ts +4 -8
  573. package/src/client/index.ts +1 -1
  574. package/src/components/InlinePortableTextEditor.tsx +5 -1
  575. package/src/components/inline-code-block.tsx +343 -0
  576. package/src/config/secrets.ts +3 -3
  577. package/src/content/converters/portable-text-to-prosemirror.ts +35 -11
  578. package/src/database/connection.ts +3 -10
  579. package/src/database/errors.ts +14 -0
  580. package/src/database/index.ts +3 -1
  581. package/src/database/migrations/006_taxonomy_defs.ts +1 -1
  582. package/src/database/migrations/014_draft_revisions.ts +6 -6
  583. package/src/database/migrations/040_byline_i18n.ts +497 -0
  584. package/src/database/migrations/runner.ts +33 -22
  585. package/src/database/repositories/audit.ts +2 -2
  586. package/src/database/repositories/byline.ts +320 -50
  587. package/src/database/repositories/media.ts +2 -2
  588. package/src/database/repositories/menu.ts +1 -1
  589. package/src/database/repositories/options.ts +3 -3
  590. package/src/database/repositories/plugin-storage.ts +3 -3
  591. package/src/database/repositories/types.ts +13 -0
  592. package/src/database/types.ts +15 -0
  593. package/src/emdash-runtime.ts +493 -20
  594. package/src/i18n/config.ts +1 -1
  595. package/src/i18n/resolve.ts +152 -0
  596. package/src/index.ts +9 -0
  597. package/src/loader.ts +134 -60
  598. package/src/mcp/server.ts +3 -3
  599. package/src/media/mime.ts +1 -1
  600. package/src/page/absolute-url.ts +1 -1
  601. package/src/plugin-utils.ts +23 -0
  602. package/src/plugins/adapt-sandbox-entry.ts +45 -40
  603. package/src/plugins/email-console.ts +1 -1
  604. package/src/plugins/index.ts +1 -0
  605. package/src/plugins/marketplace.ts +1 -1
  606. package/src/plugins/sandbox/index.ts +1 -0
  607. package/src/plugins/sandbox/noop.ts +11 -3
  608. package/src/plugins/sandbox/types.ts +28 -0
  609. package/src/query.ts +41 -7
  610. package/src/registry/config.ts +1 -1
  611. package/src/request-cache.ts +3 -3
  612. package/src/request-context.ts +1 -1
  613. package/src/settings/index.ts +4 -4
  614. package/src/storage/local.ts +1 -1
  615. package/src/storage/s3.ts +3 -3
  616. package/src/utils/db-errors.ts +24 -0
  617. package/src/widgets/index.ts +1 -1
  618. package/dist/api-BMLZuwM4.mjs.map +0 -1
  619. package/dist/byline-D09BaS4j.mjs +0 -220
  620. package/dist/byline-D09BaS4j.mjs.map +0 -1
  621. package/dist/bylines-BTM2xtP8.mjs +0 -113
  622. package/dist/bylines-BTM2xtP8.mjs.map +0 -1
  623. package/dist/bylines-BdUP8NuI.d.mts.map +0 -1
  624. package/dist/connection-2igzM-AT.mjs +0 -57
  625. package/dist/connection-2igzM-AT.mjs.map +0 -1
  626. package/dist/context-qF8d3IPR.mjs.map +0 -1
  627. package/dist/db-errors-CGN9kJfo.mjs.map +0 -1
  628. package/dist/email-console-Dmp5Q-P2.mjs.map +0 -1
  629. package/dist/error-tSQWIl5U.mjs.map +0 -1
  630. package/dist/index-BV8iJ-6s.d.mts.map +0 -1
  631. package/dist/loader-Cs6-Bqe6.mjs.map +0 -1
  632. package/dist/media-Dg7he9uK.mjs.map +0 -1
  633. package/dist/menus-DOzIecHi.mjs.map +0 -1
  634. package/dist/menus-X4Z-eBA1.mjs.map +0 -1
  635. package/dist/oauth-clients-D_B0_-Bz.mjs.map +0 -1
  636. package/dist/options-Cq64Wx0O.d.mts.map +0 -1
  637. package/dist/query-axZmO6Tn.mjs.map +0 -1
  638. package/dist/redirects-Dmj6KRU3.mjs.map +0 -1
  639. package/dist/runner-DcfZewkO.d.mts.map +0 -1
  640. package/dist/runner-DdnQIwz_.mjs.map +0 -1
  641. package/dist/seo-BoR4wCUh.mjs.map +0 -1
  642. package/dist/settings-xQKsWnzQ.mjs.map +0 -1
  643. package/dist/taxonomies-Cn9UpaR2.mjs.map +0 -1
  644. package/dist/types-CwXMEPRr.mjs.map +0 -1
  645. package/dist/types-CzvJd1ND.d.mts.map +0 -1
  646. package/dist/version-DNmQakZO.mjs +0 -7
  647. package/dist/widgets-B9j_yzlk.mjs.map +0 -1
  648. /package/dist/{api-tokens-D3C9v02m.mjs → api-tokens-iPIHAY8N.mjs} +0 -0
  649. /package/dist/{ssrf-CTul4uQi.mjs → ssrf-BIcd-aXW.mjs} +0 -0
  650. /package/dist/{types-Db67HHlU.mjs → types-1NNkmTIn.mjs} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-D-vIJjfY.mjs","names":[],"sources":["../src/loader.ts"],"sourcesContent":["/**\n * Astro Live Collections loader for EmDash\n *\n * This loader implements the Astro LiveLoader interface to fetch content\n * at runtime from the database, enabling live editing without rebuilds.\n *\n * Architecture:\n * - Single `_emdash` Astro collection handles all content types\n * - Dialect comes from virtual module (configured in astro.config.mjs)\n * - Each content type maps to its own database table: ec_posts, ec_products, etc.\n * - `getEmDashCollection()` / `getEmDashEntry()` wrap Astro's live collection API\n */\n\nimport type { LiveLoader } from \"astro/loaders\";\nimport { Kysely, sql, type Dialect } from \"kysely\";\n\nimport { currentTimestampValue, isPostgres } from \"./database/dialect-helpers.js\";\nimport { kyselyLogOption } from \"./database/instrumentation.js\";\nimport { decodeCursor, encodeCursor } from \"./database/repositories/types.js\";\nimport { validateIdentifier } from \"./database/validate.js\";\nimport type { Database } from \"./index.js\";\nimport { getRequestContext } from \"./request-context.js\";\nimport { isMissingColumnError, isMissingTableError } from \"./utils/db-errors.js\";\n\nconst FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * System columns that are not part of the content data\n */\n/**\n * System columns excluded from entry.data\n * Note: slug is intentionally NOT excluded - it's useful as data.slug in templates\n */\nconst SYSTEM_COLUMNS = new Set([\n\t\"id\",\n\t// \"slug\" - kept in data for template access\n\t\"status\",\n\t\"author_id\",\n\t\"primary_byline_id\",\n\t\"created_at\",\n\t\"updated_at\",\n\t\"published_at\",\n\t\"scheduled_at\",\n\t\"deleted_at\",\n\t\"version\",\n\t\"live_revision_id\",\n\t\"draft_revision_id\",\n\t\"locale\",\n\t\"translation_group\",\n]);\n\n/**\n * Get the table name for a collection type\n */\nfunction getTableName(type: string): string {\n\tvalidateIdentifier(type, \"collection type\");\n\treturn `ec_${type}`;\n}\n\n/**\n * Cache for taxonomy names (only used for the primary database).\n * Skipped when a per-request DB override is active (e.g. preview mode)\n * because the override DB may have different taxonomies.\n */\nlet taxonomyNames: Set<string> | null = null;\n\n/**\n * Get all taxonomy names (cached for the primary DB, bypassed only when\n * the per-request DB is an isolated instance — playground / DO preview).\n * Plain D1 Sessions routing shares schema with the singleton, so the\n * module-scoped cache stays valid.\n */\nasync function getTaxonomyNames(db: Kysely<Database>): Promise<Set<string>> {\n\tconst hasIsolatedDb = getRequestContext()?.dbIsIsolated === true;\n\n\tif (!hasIsolatedDb && taxonomyNames) {\n\t\treturn taxonomyNames;\n\t}\n\n\ttry {\n\t\tconst defs = await db.selectFrom(\"_emdash_taxonomy_defs\").select(\"name\").execute();\n\t\tconst names = new Set(defs.map((d) => d.name));\n\t\tif (!hasIsolatedDb) {\n\t\t\ttaxonomyNames = names;\n\t\t}\n\t\treturn names;\n\t} catch {\n\t\t// Table doesn't exist yet, return empty set\n\t\tconst empty = new Set<string>();\n\t\tif (!hasIsolatedDb) {\n\t\t\ttaxonomyNames = empty;\n\t\t}\n\t\treturn empty;\n\t}\n}\n\n/**\n * System columns to include in data (mapped to camelCase where needed)\n */\nconst INCLUDE_IN_DATA: Record<string, string> = {\n\tid: \"id\",\n\tstatus: \"status\",\n\tauthor_id: \"authorId\",\n\tprimary_byline_id: \"primaryBylineId\",\n\tcreated_at: \"createdAt\",\n\tupdated_at: \"updatedAt\",\n\tpublished_at: \"publishedAt\",\n\tscheduled_at: \"scheduledAt\",\n\tdraft_revision_id: \"draftRevisionId\",\n\tlive_revision_id: \"liveRevisionId\",\n\tlocale: \"locale\",\n\ttranslation_group: \"translationGroup\",\n};\n\n/** System date columns that should be converted to Date objects */\nconst DATE_COLUMNS = new Set([\"created_at\", \"updated_at\", \"published_at\", \"scheduled_at\"]);\n\n/**\n * Hidden, symbol-keyed property on each mapped data record carrying the raw\n * DB string for every date column. Lets cursor encoders downstream reproduce\n * the loader's exact `nextCursor` format without round-tripping through\n * `new Date()`, which loses precision for stored values that aren't already\n * ISO-with-milliseconds (e.g. `2026-01-01T00:00:00Z` becomes\n * `2026-01-01T00:00:00.000Z`).\n */\nexport const CURSOR_RAW_VALUES: unique symbol = Symbol(\"emdash:cursorRawValues\");\n\nconst LOCAL_MEDIA_FILE_PREFIX = \"/_emdash/api/media/file/\";\nconst URL_SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:/;\n\n/** Safely extract a string value from a record, returning fallback if not a string */\nfunction rowStr(row: Record<string, unknown>, key: string, fallback = \"\"): string {\n\tconst val = row[key];\n\treturn typeof val === \"string\" ? val : fallback;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isBareMediaKey(src: string): boolean {\n\treturn !src.startsWith(\"/\") && !URL_SCHEME_PATTERN.test(src);\n}\n\nfunction normalizeLocalMediaValue(value: unknown): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(normalizeLocalMediaValue);\n\t}\n\n\tif (!isRecord(value)) {\n\t\treturn value;\n\t}\n\n\tconst normalized: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(value)) {\n\t\tnormalized[key] = normalizeLocalMediaValue(child);\n\t}\n\n\tif (\n\t\tnormalized.provider === \"local\" &&\n\t\ttypeof normalized.src === \"string\" &&\n\t\tnormalized.src.length > 0\n\t) {\n\t\tconst src = normalized.src;\n\t\tif (src.startsWith(LOCAL_MEDIA_FILE_PREFIX)) {\n\t\t\tconst id = src.slice(LOCAL_MEDIA_FILE_PREFIX.length);\n\t\t\tif (!normalized.id && id) {\n\t\t\t\tnormalized.id = id;\n\t\t\t}\n\t\t} else if (isBareMediaKey(src)) {\n\t\t\tif (!normalized.id) {\n\t\t\t\tnormalized.id = src;\n\t\t\t}\n\t\t\tnormalized.src = `${LOCAL_MEDIA_FILE_PREFIX}${src}`;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n/**\n * Map a database row to entry data\n * Extracts content fields (non-system columns) and parses JSON where needed.\n * System columns needed for templates (id, status, dates) are included with camelCase names.\n */\nfunction mapRowToData(row: Record<string, unknown>): Record<string, unknown> {\n\tconst data: Record<string, unknown> = {};\n\tconst rawDateValues: Record<string, string> = {};\n\n\tfor (const [key, value] of Object.entries(row)) {\n\t\t// Include certain system columns (mapped to camelCase where needed)\n\t\tif (key in INCLUDE_IN_DATA) {\n\t\t\t// Convert date columns from ISO strings to Date objects\n\t\t\tif (DATE_COLUMNS.has(key)) {\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\trawDateValues[key] = value;\n\t\t\t\t\tdata[INCLUDE_IN_DATA[key]] = new Date(value);\n\t\t\t\t} else {\n\t\t\t\t\tdata[INCLUDE_IN_DATA[key]] = null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdata[INCLUDE_IN_DATA[key]] = value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (SYSTEM_COLUMNS.has(key)) continue;\n\n\t\t// Try to parse JSON strings (for portableText, json fields, etc.)\n\t\tif (typeof value === \"string\") {\n\t\t\ttry {\n\t\t\t\t// Only parse if it looks like JSON (starts with { or [)\n\t\t\t\tif (value.startsWith(\"{\") || value.startsWith(\"[\")) {\n\t\t\t\t\tdata[key] = normalizeLocalMediaValue(JSON.parse(value));\n\t\t\t\t} else {\n\t\t\t\t\tdata[key] = value;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tdata[key] = value;\n\t\t\t}\n\t\t} else {\n\t\t\tdata[key] = value;\n\t\t}\n\t}\n\n\tObject.defineProperty(data, CURSOR_RAW_VALUES, {\n\t\tvalue: rawDateValues,\n\t\tenumerable: false,\n\t\tconfigurable: false,\n\t\twritable: false,\n\t});\n\n\treturn data;\n}\n\n/**\n * Map revision data (already-parsed JSON object) to entry data.\n * Strips _-prefixed metadata keys (e.g. _slug) used internally by revisions.\n */\nfunction mapRevisionData(data: Record<string, unknown>): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (key.startsWith(\"_\")) continue; // revision metadata\n\t\tresult[key] = normalizeLocalMediaValue(value);\n\t}\n\treturn result;\n}\n\n// Virtual module imports are lazy-loaded to avoid errors when importing\n// emdash outside of Astro/Vite context (e.g., in astro.config.mjs)\nlet virtualConfig:\n\t| {\n\t\t\tdatabase?: { config: unknown };\n\t\t\ti18n?: { defaultLocale: string; locales: string[]; prefixDefaultLocale?: boolean } | null;\n\t }\n\t| undefined;\nlet virtualCreateDialect: ((config: unknown) => Dialect) | undefined;\n\nasync function loadVirtualModules() {\n\tif (virtualConfig === undefined) {\n\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t// @ts-ignore - virtual module\n\t\tconst configModule = await import(\"virtual:emdash/config\");\n\t\tvirtualConfig = configModule.default;\n\t}\n\tif (virtualCreateDialect === undefined) {\n\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t// @ts-ignore - virtual module\n\t\tconst dialectModule = await import(\"virtual:emdash/dialect\");\n\t\tvirtualCreateDialect = dialectModule.createDialect;\n\t\t// dialectType is no longer needed here — dialect detection is\n\t\t// done via the db adapter instance in dialect-helpers.ts\n\t}\n}\n\n/**\n * Entry data type - generic object\n */\nexport type EntryData = Record<string, unknown>;\n\n/**\n * Sort direction\n */\nexport type SortDirection = \"asc\" | \"desc\";\n\n/**\n * Order by specification - field name to direction\n * @example { created_at: \"desc\" } - Sort by created_at descending\n * @example { title: \"asc\" } - Sort by title ascending\n */\nexport type OrderBySpec = Record<string, SortDirection>;\n\n/**\n * Build WHERE clause for status filtering.\n * When filtering for 'published' status, also include scheduled content\n * whose scheduled_at time has passed (treating it as effectively published).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nfunction buildStatusCondition(\n\tdb: Kysely<any>,\n\tstatus: string,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\tconst statusField = tablePrefix ? `${tablePrefix}.status` : \"status\";\n\tconst scheduledAtField = tablePrefix ? `${tablePrefix}.scheduled_at` : \"scheduled_at\";\n\n\tif (status === \"published\") {\n\t\t// Include both published content AND scheduled content past its publish time.\n\t\t// scheduled_at is stored as text (ISO 8601). On Postgres, we must cast it\n\t\t// to timestamptz for the comparison with CURRENT_TIMESTAMP to work.\n\t\tconst scheduledAtExpr = isPostgres(db)\n\t\t\t? sql`${sql.ref(scheduledAtField)}::timestamptz`\n\t\t\t: sql.ref(scheduledAtField);\n\t\tconst nowExpr = isPostgres(db)\n\t\t\t? currentTimestampValue(db)\n\t\t\t: sql`strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;\n\t\treturn sql`(${sql.ref(statusField)} = 'published' OR (${sql.ref(statusField)} = 'scheduled' AND ${scheduledAtExpr} <= ${nowExpr}))`;\n\t}\n\n\treturn sql`${sql.ref(statusField)} = ${status}`;\n}\n\n/**\n * Resolved primary sort field and direction (used for cursor pagination).\n */\ninterface PrimarySort {\n\tfield: string;\n\tdirection: SortDirection;\n}\n\n/**\n * Get the primary sort field from an orderBy spec (first valid field, or default).\n */\nfunction getPrimarySort(orderBy: OrderBySpec | undefined, tablePrefix?: string): PrimarySort {\n\tif (orderBy) {\n\t\tfor (const [field, direction] of Object.entries(orderBy)) {\n\t\t\tif (FIELD_NAME_PATTERN.test(field)) {\n\t\t\t\tconst fullField = tablePrefix ? `${tablePrefix}.${field}` : field;\n\t\t\t\treturn { field: fullField, direction };\n\t\t\t}\n\t\t}\n\t}\n\tconst defaultField = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\treturn { field: defaultField, direction: \"desc\" };\n}\n\n/**\n * Build ORDER BY clause from orderBy spec\n * Validates field names to prevent SQL injection (alphanumeric + underscore only)\n * Supports multiple sort fields in object key order\n */\nfunction buildOrderByClause(\n\torderBy: OrderBySpec | undefined,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\t// Default to created_at DESC\n\tif (!orderBy || Object.keys(orderBy).length === 0) {\n\t\tconst field = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\t\treturn sql`ORDER BY ${sql.ref(field)} DESC, ${sql.ref(tablePrefix ? `${tablePrefix}.id` : \"id\")} DESC`;\n\t}\n\n\tconst sortParts: ReturnType<typeof sql>[] = [];\n\n\tfor (const [field, direction] of Object.entries(orderBy)) {\n\t\t// Validate field name (alphanumeric + underscore only)\n\t\tif (!FIELD_NAME_PATTERN.test(field)) {\n\t\t\tcontinue; // Skip invalid field names\n\t\t}\n\n\t\tconst fullField = tablePrefix ? `${tablePrefix}.${field}` : field;\n\t\tconst dir = direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\t\tsortParts.push(sql`${sql.ref(fullField)} ${dir}`);\n\t}\n\n\t// If no valid sort fields, fall back to default\n\tif (sortParts.length === 0) {\n\t\tconst defaultField = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\t\treturn sql`ORDER BY ${sql.ref(defaultField)} DESC, ${sql.ref(tablePrefix ? `${tablePrefix}.id` : \"id\")} DESC`;\n\t}\n\n\t// Add id as tiebreaker to ensure stable cursor ordering\n\tconst primary = getPrimarySort(orderBy, tablePrefix);\n\tconst idField = tablePrefix ? `${tablePrefix}.id` : \"id\";\n\tconst idDir = primary.direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\tsortParts.push(sql`${sql.ref(idField)} ${idDir}`);\n\n\treturn sql`ORDER BY ${sql.join(sortParts, sql`, `)}`;\n}\n\n/**\n * Build a cursor WHERE condition for keyset pagination.\n * Uses the primary sort field + id as tiebreaker for stable ordering.\n *\n * Throws `InvalidCursorError` if the cursor is malformed; callers should\n * let this propagate so users see a real error rather than silently\n * falling back to the first page.\n */\nfunction buildCursorCondition(\n\tcursor: string,\n\torderBy: OrderBySpec | undefined,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\tconst { orderValue, id: cursorId } = decodeCursor(cursor);\n\tconst primary = getPrimarySort(orderBy, tablePrefix);\n\tconst idField = tablePrefix ? `${tablePrefix}.id` : \"id\";\n\n\tif (primary.direction === \"desc\") {\n\t\treturn sql`(${sql.ref(primary.field)} < ${orderValue} OR (${sql.ref(primary.field)} = ${orderValue} AND ${sql.ref(idField)} < ${cursorId}))`;\n\t}\n\treturn sql`(${sql.ref(primary.field)} > ${orderValue} OR (${sql.ref(primary.field)} = ${orderValue} AND ${sql.ref(idField)} > ${cursorId}))`;\n}\n\n/** Type guard: is the where value a range object (not a string or array)? */\nfunction isWhereRange(value: WhereValue): value is WhereRange {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * Build AND conditions for non-taxonomy field filters.\n * Returns an array of sql fragments; empty if no field filters apply.\n * Field names are validated against FIELD_NAME_PATTERN to prevent injection.\n */\nfunction buildFieldConditions(\n\tfields: Record<string, WhereValue>,\n\ttablePrefix?: string,\n): ReturnType<typeof sql>[] {\n\tconst conditions: ReturnType<typeof sql>[] = [];\n\n\tfor (const [key, value] of Object.entries(fields)) {\n\t\tif (!FIELD_NAME_PATTERN.test(key)) {\n\t\t\tconsole.warn(`[emdash] where filter: invalid field name \"${key}\" ignored`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (value == null) continue;\n\t\tconst ref = tablePrefix ? sql.ref(`${tablePrefix}.${key}`) : sql.ref(key);\n\n\t\tif (isWhereRange(value)) {\n\t\t\tif (value.gt !== undefined) conditions.push(sql`${ref} > ${value.gt}`);\n\t\t\tif (value.gte !== undefined) conditions.push(sql`${ref} >= ${value.gte}`);\n\t\t\tif (value.lt !== undefined) conditions.push(sql`${ref} < ${value.lt}`);\n\t\t\tif (value.lte !== undefined) conditions.push(sql`${ref} <= ${value.lte}`);\n\t\t} else if (Array.isArray(value)) {\n\t\t\tif (value.length > 0) {\n\t\t\t\tconditions.push(sql`${ref} IN (${sql.join(value.map((v) => sql`${v}`))})`);\n\t\t\t}\n\t\t} else {\n\t\t\tconditions.push(sql`${ref} = ${value}`);\n\t\t}\n\t}\n\n\treturn conditions;\n}\n\n/**\n * Range filter for comparison operators on field values.\n * Values are compared as strings in the database. This works correctly for\n * ISO 8601 dates (e.g. \"2024-01-01T00:00:00Z\") because lexicographic ordering\n * matches chronological ordering. Ensure date values use a consistent format.\n */\nexport interface WhereRange {\n\tgt?: string;\n\tgte?: string;\n\tlt?: string;\n\tlte?: string;\n}\n\n/**\n * A where clause value: exact match, multi-value match, or range comparison.\n */\nexport type WhereValue = string | string[] | WhereRange;\n\n/**\n * Filter for loadCollection - type is required\n */\nexport interface CollectionFilter {\n\ttype: string;\n\tstatus?: \"draft\" | \"published\" | \"archived\";\n\tlimit?: number;\n\t/**\n\t * Opaque cursor for keyset pagination.\n\t * Pass the `nextCursor` value from a previous result to fetch the next page.\n\t */\n\tcursor?: string;\n\t/**\n\t * Filter by field values, taxonomy terms, or ranges.\n\t *\n\t * Taxonomy names are detected automatically and filtered via JOIN.\n\t * Other keys are treated as column filters on the content table.\n\t *\n\t * @example { category: 'news' } - taxonomy term\n\t * @example { series: 'main' } - exact match on a content field\n\t * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - date range\n\t */\n\twhere?: Record<string, WhereValue>;\n\t/**\n\t * Order results by field(s)\n\t * @default { created_at: \"desc\" }\n\t */\n\torderBy?: OrderBySpec;\n\t/**\n\t * Filter by locale (e.g. 'en', 'fr').\n\t * When set, only returns content in this locale.\n\t */\n\tlocale?: string;\n}\n\n/**\n * Filter for loadEntry - type and id are required\n */\nexport interface EntryFilter {\n\ttype: string;\n\tid: string;\n\t/**\n\t * When set, fetch content data from this revision instead of the content table.\n\t * Used by preview mode to serve draft revision data.\n\t */\n\trevisionId?: string;\n\t/**\n\t * Locale to scope slug lookup. Only affects slug resolution;\n\t * IDs are globally unique and always resolve regardless of locale.\n\t */\n\tlocale?: string;\n}\n\n// Cached database instance (shared across calls)\nlet dbInstance: Kysely<Database> | null = null;\n\n/**\n * Get the database instance. Used by query wrapper functions and middleware.\n *\n * Checks the ALS request context first — if a per-request DB override is set\n * (e.g. by DO preview middleware), it takes precedence over the module-level\n * cached instance. This allows preview mode to route queries to an isolated\n * Durable Object database without modifying any calling code.\n *\n * Initializes the default database on first call using config from virtual module.\n */\nexport async function getDb(): Promise<Kysely<Database>> {\n\t// Per-request DB override via ALS (normal mode)\n\tconst ctx = getRequestContext();\n\tif (ctx?.db) {\n\t\treturn ctx.db as Kysely<Database>; // eslint-disable-line typescript/no-unsafe-type-assertion -- db is typed as unknown in RequestContext to avoid circular deps\n\t}\n\n\tif (!dbInstance) {\n\t\tawait loadVirtualModules();\n\t\tif (!virtualConfig?.database || typeof virtualCreateDialect !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"EmDash database not configured. Add database config to emdash() in astro.config.mjs\",\n\t\t\t);\n\t\t}\n\t\tconst dialect = virtualCreateDialect(virtualConfig.database.config);\n\t\tdbInstance = new Kysely<Database>({ dialect, log: kyselyLogOption() });\n\t}\n\treturn dbInstance;\n}\n\n/**\n * Create an EmDash Live Collections loader\n *\n * This loader handles ALL content types in a single Astro collection.\n * Use `getEmDashCollection()` and `getEmDashEntry()` to query\n * specific content types.\n *\n * Database is configured in astro.config.mjs via the emdash() integration.\n *\n * @example\n * ```ts\n * // src/live.config.ts\n * import { defineLiveCollection } from \"astro:content\";\n * import { emdashLoader } from \"emdash\";\n *\n * export const collections = {\n * emdash: defineLiveCollection({\n * loader: emdashLoader(),\n * }),\n * };\n * ```\n */\nexport function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter> {\n\treturn {\n\t\tname: \"emdash\",\n\n\t\t/**\n\t\t * Load all entries for a content type\n\t\t */\n\t\tasync loadCollection({ filter }) {\n\t\t\ttry {\n\t\t\t\t// Get DB instance (initializes on first use)\n\t\t\t\tconst db = await getDb();\n\n\t\t\t\t// Type filter is required\n\t\t\t\tconst type = filter?.type;\n\t\t\t\tif (!type) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\"type filter is required. Use getEmDashCollection() instead of getLiveCollection() directly.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Query the per-collection table (ec_posts, ec_products, etc.)\n\t\t\t\tconst tableName = getTableName(type);\n\n\t\t\t\t// Build query with dynamic table name\n\t\t\t\tconst status = filter?.status || \"published\";\n\t\t\t\tconst limit = filter?.limit;\n\t\t\t\tconst cursor = filter?.cursor;\n\t\t\t\tconst where = filter?.where;\n\t\t\t\tconst orderBy = filter?.orderBy;\n\t\t\t\tconst locale = filter?.locale;\n\n\t\t\t\t// Cursor pagination: over-fetch by 1 to detect next page\n\t\t\t\tconst fetchLimit = limit ? limit + 1 : undefined;\n\n\t\t\t\t// Build cursor condition if cursor is provided\n\t\t\t\tconst cursorCondition = cursor ? buildCursorCondition(cursor, orderBy) : null;\n\t\t\t\tconst cursorConditionPrefixed = cursor\n\t\t\t\t\t? buildCursorCondition(cursor, orderBy, tableName)\n\t\t\t\t\t: null;\n\n\t\t\t\t// Separate taxonomy filters from field filters\n\t\t\t\tlet result: { rows: Record<string, unknown>[] };\n\t\t\t\tlet taxonomyFilter: { name: string; slugs: string[] } | null = null;\n\t\t\t\tconst fieldFilters: Record<string, WhereValue> = {};\n\n\t\t\t\tif (where && Object.keys(where).length > 0) {\n\t\t\t\t\tconst taxNames = await getTaxonomyNames(db);\n\n\t\t\t\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\t\t\t\tif (value == null) continue;\n\t\t\t\t\t\tif (taxNames.has(key)) {\n\t\t\t\t\t\t\tif (isWhereRange(value)) {\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`[emdash] where filter: range operators are not supported on taxonomy \"${key}\", ignored`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (taxonomyFilter) {\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`[emdash] where filter: only one taxonomy is supported per query, \"${key}\" ignored`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst slugs = Array.isArray(value) ? value : [value];\n\t\t\t\t\t\t\ttaxonomyFilter = { name: key, slugs };\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfieldFilters[key] = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (taxonomyFilter) {\n\t\t\t\t\tconst orderByClause = buildOrderByClause(orderBy, tableName);\n\t\t\t\t\tconst statusCondition = buildStatusCondition(db, status, tableName);\n\t\t\t\t\tconst localeCondition = locale\n\t\t\t\t\t\t? sql`AND ${sql.ref(tableName)}.locale = ${locale}`\n\t\t\t\t\t\t: sql``;\n\t\t\t\t\tconst cursorCond = cursorConditionPrefixed ? sql`AND ${cursorConditionPrefixed}` : sql``;\n\t\t\t\t\tconst fieldConds = buildFieldConditions(fieldFilters, tableName);\n\t\t\t\t\tconst fieldCondsSQL =\n\t\t\t\t\t\tfieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;\n\n\t\t\t\t\tresult = await sql<Record<string, unknown>>`\n\t\t\t\t\t\tSELECT DISTINCT ${sql.ref(tableName)}.* FROM ${sql.ref(tableName)}\n\t\t\t\t\t\tINNER JOIN content_taxonomies ct\n\t\t\t\t\t\t\tON ct.collection = ${type}\n\t\t\t\t\t\t\tAND ct.entry_id = ${sql.ref(tableName)}.id\n\t\t\t\t\t\tINNER JOIN taxonomies t\n\t\t\t\t\t\t\tON t.id = ct.taxonomy_id\n\t\t\t\t\t\tWHERE ${sql.ref(tableName)}.deleted_at IS NULL\n\t\t\t\t\t\t\tAND ${statusCondition}\n\t\t\t\t\t\t\t${localeCondition}\n\t\t\t\t\t\t\t${cursorCond}\n\t\t\t\t\t\t\tAND t.name = ${taxonomyFilter.name}\n\t\t\t\t\t\t\tAND t.slug IN (${sql.join(taxonomyFilter.slugs.map((s) => sql`${s}`))})\n\t\t\t\t\t\t\t${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}\n\t\t\t\t\t\t${orderByClause}\n\t\t\t\t\t\t${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}\n\t\t\t\t\t`.execute(db);\n\t\t\t\t} else {\n\t\t\t\t\tconst orderByClause = buildOrderByClause(orderBy);\n\t\t\t\t\tconst statusCondition = buildStatusCondition(db, status);\n\t\t\t\t\tconst localeFilter = locale ? sql`AND locale = ${locale}` : sql``;\n\t\t\t\t\tconst cursorCond = cursorCondition ? sql`AND ${cursorCondition}` : sql``;\n\t\t\t\t\tconst fieldConds = buildFieldConditions(fieldFilters);\n\t\t\t\t\tconst fieldCondsSQL =\n\t\t\t\t\t\tfieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;\n\n\t\t\t\t\tresult = await sql<Record<string, unknown>>`\n\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\tAND ${statusCondition}\n\t\t\t\t\t\t${localeFilter}\n\t\t\t\t\t\t${cursorCond}\n\t\t\t\t\t\t${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}\n\t\t\t\t\t\t${orderByClause}\n\t\t\t\t\t\t${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}\n\t\t\t\t\t`.execute(db);\n\t\t\t\t}\n\n\t\t\t\t// Detect whether there are more results (over-fetched by 1)\n\t\t\t\tconst hasMore = limit ? result.rows.length > limit : false;\n\t\t\t\tconst rows = hasMore ? result.rows.slice(0, limit) : result.rows;\n\n\t\t\t\t// Map rows to entries\n\t\t\t\tconst i18nConfig = virtualConfig?.i18n;\n\t\t\t\tconst i18nEnabled = i18nConfig && i18nConfig.locales.length > 1;\n\t\t\t\tconst entries = rows.map((row) => {\n\t\t\t\t\tconst slug = rowStr(row, \"slug\") || rowStr(row, \"id\");\n\t\t\t\t\tconst rowLocale = rowStr(row, \"locale\");\n\t\t\t\t\tconst shouldPrefix =\n\t\t\t\t\t\ti18nEnabled &&\n\t\t\t\t\t\trowLocale !== \"\" &&\n\t\t\t\t\t\t(rowLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\t\t\t\t\tconst id = shouldPrefix ? `${rowLocale}/${slug}` : slug;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\t\tdata: mapRowToData(row),\n\t\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\t// Encode nextCursor from the last row if there are more results\n\t\t\t\tlet nextCursor: string | undefined;\n\t\t\t\tif (hasMore && rows.length > 0) {\n\t\t\t\t\tconst lastRow = rows.at(-1)!;\n\t\t\t\t\tconst primary = getPrimarySort(orderBy);\n\t\t\t\t\t// Strip table prefix from field name for row lookup\n\t\t\t\t\tconst fieldName = primary.field.includes(\".\")\n\t\t\t\t\t\t? primary.field.split(\".\").pop()!\n\t\t\t\t\t\t: primary.field;\n\t\t\t\t\tconst lastOrderValue = lastRow[fieldName];\n\t\t\t\t\tconst orderStr =\n\t\t\t\t\t\ttypeof lastOrderValue === \"string\" || typeof lastOrderValue === \"number\"\n\t\t\t\t\t\t\t? String(lastOrderValue)\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\tnextCursor = encodeCursor(orderStr, String(lastRow.id));\n\t\t\t\t}\n\n\t\t\t\t// Collection-level cache hint uses the most recent updated_at\n\t\t\t\tlet collectionLastModified: Date | undefined;\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\tif (row.updated_at) {\n\t\t\t\t\t\tconst d = new Date(rowStr(row, \"updated_at\"));\n\t\t\t\t\t\tif (!collectionLastModified || d > collectionLastModified) {\n\t\t\t\t\t\t\tcollectionLastModified = d;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tentries,\n\t\t\t\t\tnextCursor,\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [type],\n\t\t\t\t\t\tlastModified: collectionLastModified,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\t// Handle missing table/column gracefully - return empty collection.\n\t\t\t\t// Missing table happens before migrations have run.\n\t\t\t\t// Missing column happens when a where filter references a non-existent field.\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tif (isMissingTableError(error) || isMissingColumnError(error)) {\n\t\t\t\t\tif (isMissingColumnError(error)) {\n\t\t\t\t\t\tconsole.warn(`[emdash] where filter: ${message}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn { entries: [] };\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\terror: new Error(`Failed to load collection: ${message}`),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load a single entry by type and ID/slug\n\t\t *\n\t\t * When filter.revisionId is set (preview mode), the entry's data\n\t\t * comes from the revisions table instead of the content table columns.\n\t\t */\n\t\tasync loadEntry({ filter }) {\n\t\t\ttry {\n\t\t\t\t// Get DB instance\n\t\t\t\tconst db = await getDb();\n\n\t\t\t\t// Both type and id are required\n\t\t\t\tconst type = filter?.type;\n\t\t\t\tconst id = filter?.id;\n\n\t\t\t\tif (!type || !id) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\"type and id filters are required. Use getEmDashEntry() instead of getLiveEntry() directly.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Query the per-collection table\n\t\t\t\tconst tableName = getTableName(type);\n\t\t\t\tconst locale = filter?.locale;\n\n\t\t\t\t// Use raw SQL for dynamic table name, match by slug or id\n\t\t\t\t// When locale is specified, prefer locale-scoped slug match,\n\t\t\t\t// but IDs are globally unique so always check id without locale scope\n\t\t\t\tconst result = locale\n\t\t\t\t\t? await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\t\tAND ((slug = ${id} AND locale = ${locale}) OR id = ${id})\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t`.execute(db)\n\t\t\t\t\t: await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\t\tAND (slug = ${id} OR id = ${id})\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t`.execute(db);\n\n\t\t\t\tconst row = result.rows[0];\n\t\t\t\tif (!row) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tconst i18nConfig = virtualConfig?.i18n;\n\t\t\t\tconst i18nEnabled = i18nConfig && i18nConfig.locales.length > 1;\n\t\t\t\tconst entrySlug = rowStr(row, \"slug\") || rowStr(row, \"id\");\n\t\t\t\tconst entryLocale = rowStr(row, \"locale\");\n\t\t\t\tconst shouldPrefixEntry =\n\t\t\t\t\ti18nEnabled &&\n\t\t\t\t\tentryLocale !== \"\" &&\n\t\t\t\t\t(entryLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\t\t\t\tconst entryId = shouldPrefixEntry ? `${entryLocale}/${entrySlug}` : entrySlug;\n\n\t\t\t\t// Preview mode: override content fields with revision data,\n\t\t\t\t// keeping system metadata from the content table row.\n\t\t\t\tconst revisionId = filter?.revisionId;\n\t\t\t\tif (revisionId) {\n\t\t\t\t\tconst revRow = await sql<{ data: string }>`\n\t\t\t\t\t\tSELECT data FROM revisions\n\t\t\t\t\t\tWHERE id = ${revisionId}\n\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t`.execute(db);\n\n\t\t\t\t\tconst revData = revRow.rows[0];\n\t\t\t\t\tif (revData) {\n\t\t\t\t\t\tconst parsed: Record<string, unknown> = JSON.parse(revData.data);\n\t\t\t\t\t\t// System metadata from content table + content fields from revision\n\t\t\t\t\t\tconst systemData: Record<string, unknown> = {};\n\t\t\t\t\t\tfor (const [key, mappedKey] of Object.entries(INCLUDE_IN_DATA)) {\n\t\t\t\t\t\t\tif (key in row) {\n\t\t\t\t\t\t\t\tif (DATE_COLUMNS.has(key)) {\n\t\t\t\t\t\t\t\t\tsystemData[mappedKey] = typeof row[key] === \"string\" ? new Date(row[key]) : null;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tsystemData[mappedKey] = row[key];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Use slug from revision metadata if present, else from content table\n\t\t\t\t\t\tconst slug = typeof parsed._slug === \"string\" ? parsed._slug : rowStr(row, \"slug\");\n\t\t\t\t\t\tconst revSlug = slug || rowStr(row, \"id\");\n\t\t\t\t\t\tconst revLocale = rowStr(row, \"locale\");\n\t\t\t\t\t\tconst shouldPrefixRev =\n\t\t\t\t\t\t\ti18nEnabled &&\n\t\t\t\t\t\t\trevLocale !== \"\" &&\n\t\t\t\t\t\t\t(revLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\t\t\t\t\t\tconst revId = shouldPrefixRev ? `${revLocale}/${revSlug}` : revSlug;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tid: revId,\n\t\t\t\t\t\t\tslug,\n\t\t\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\t\t\tdata: { ...systemData, slug, ...mapRevisionData(parsed) },\n\t\t\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tid: entryId,\n\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\tdata: mapRowToData(row),\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\t// Handle missing table gracefully - return undefined (not found).\n\t\t\t\t// This happens before migrations have run.\n\t\t\t\tif (isMissingTableError(error)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\treturn {\n\t\t\t\t\terror: new Error(`Failed to load entry: ${message}`),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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"}
@@ -226,4 +226,4 @@ function normalizeManifestRoute(entry) {
226
226
 
227
227
  //#endregion
228
228
  export { pluginManifestSchema as i, PLUGIN_CAPABILITIES as n, normalizeManifestRoute as r, HOOK_NAMES as t };
229
- //# sourceMappingURL=manifest-schema-HCtSh4Jq.mjs.map
229
+ //# sourceMappingURL=manifest-schema-Czqf0TLu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-schema-HCtSh4Jq.mjs","names":[],"sources":["../src/plugins/manifest-schema.ts"],"sourcesContent":["/**\n * Zod schema for PluginManifest validation\n *\n * Used to validate manifest.json from plugin bundles at every parse site:\n * - Client-side download (marketplace.ts extractBundle)\n * - R2 load (api/handlers/marketplace.ts loadBundleFromR2)\n * - CLI publish preview (cli/commands/publish.ts readManifestFromTarball)\n * - Marketplace ingest extends this with publishing-specific fields\n */\n\nimport { z } from \"zod\";\n\n// ── Enum values (must stay in sync with types.ts) ───────────────\n\n/**\n * Current capability names — the ones authors should use going forward.\n * See `PluginCapability` in `types.ts` for documentation of each.\n */\nexport const CURRENT_PLUGIN_CAPABILITIES = [\n\t\"network:request\",\n\t\"network:request:unrestricted\",\n\t\"content:read\",\n\t\"content:write\",\n\t\"media:read\",\n\t\"media:write\",\n\t\"users:read\",\n\t\"email:send\",\n\t\"hooks.email-transport:register\",\n\t\"hooks.email-events:register\",\n\t\"hooks.page-fragments:register\",\n] as const;\n\n/**\n * Legacy capability names accepted during the deprecation window.\n * Normalized to current names via `normalizeCapability()` in types.ts\n * before reaching the runtime. Plugin authors are warned at bundle/validate\n * and hard-failed at publish.\n */\nexport const DEPRECATED_PLUGIN_CAPABILITIES = [\n\t\"network:fetch\",\n\t\"network:fetch:any\",\n\t\"read:content\",\n\t\"write:content\",\n\t\"read:media\",\n\t\"write:media\",\n\t\"read:users\",\n\t\"email:provide\",\n\t\"email:intercept\",\n\t\"page:inject\",\n] as const;\n\n/**\n * Full set of accepted capability strings — current + deprecated.\n *\n * The manifest schema accepts both during the transition. The runtime only\n * ever sees current names because `normalizeCapability()` rewrites legacy\n * names at every external boundary (definePlugin, adaptSandboxEntry).\n */\nexport const PLUGIN_CAPABILITIES = [\n\t...CURRENT_PLUGIN_CAPABILITIES,\n\t...DEPRECATED_PLUGIN_CAPABILITIES,\n] as const;\n\n/** Must stay in sync with FieldType in schema/types.ts */\nconst FIELD_TYPES = [\n\t\"string\",\n\t\"text\",\n\t\"number\",\n\t\"integer\",\n\t\"boolean\",\n\t\"datetime\",\n\t\"select\",\n\t\"multiSelect\",\n\t\"portableText\",\n\t\"image\",\n\t\"file\",\n\t\"reference\",\n\t\"json\",\n\t\"slug\",\n\t\"repeater\",\n] as const;\n\nexport const HOOK_NAMES = [\n\t\"plugin:install\",\n\t\"plugin:activate\",\n\t\"plugin:deactivate\",\n\t\"plugin:uninstall\",\n\t\"content:beforeSave\",\n\t\"content:afterSave\",\n\t\"content:beforeDelete\",\n\t\"content:afterDelete\",\n\t\"content:afterPublish\",\n\t\"content:afterUnpublish\",\n\t\"media:beforeUpload\",\n\t\"media:afterUpload\",\n\t\"cron\",\n\t\"email:beforeSend\",\n\t\"email:deliver\",\n\t\"email:afterSend\",\n\t\"comment:beforeCreate\",\n\t\"comment:moderate\",\n\t\"comment:afterCreate\",\n\t\"comment:afterModerate\",\n\t\"page:metadata\",\n\t\"page:fragments\",\n] as const;\n\n/**\n * Structured hook entry for manifest — name plus optional metadata.\n * During a transition period, both plain strings and objects are accepted.\n */\nconst manifestHookEntrySchema = z.object({\n\tname: z.enum(HOOK_NAMES),\n\texclusive: z.boolean().optional(),\n\tpriority: z.number().int().optional(),\n\ttimeout: z.number().int().positive().optional(),\n});\n\n/**\n * Structured route entry for manifest — name plus optional metadata.\n * Both plain strings and objects are accepted; strings are normalized\n * to `{ name }` objects via `normalizeManifestRoute()`.\n */\n/** Route names must be safe path segments — alphanumeric, hyphens, underscores, forward slashes */\nconst routeNamePattern = /^[a-zA-Z0-9][a-zA-Z0-9_\\-/]*$/;\n\nconst manifestRouteEntrySchema = z.object({\n\tname: z.string().min(1).regex(routeNamePattern, \"Route name must be a safe path segment\"),\n\tpublic: z.boolean().optional(),\n});\n\n// ── Sub-schemas ─────────────────────────────────────────────────\n\n/** Index field names must be valid identifiers to prevent SQL injection via JSON path expressions */\nconst indexFieldName = z.string().regex(/^[a-zA-Z][a-zA-Z0-9_]*$/);\n\nconst storageCollectionSchema = z.object({\n\tindexes: z.array(z.union([indexFieldName, z.array(indexFieldName)])),\n\tuniqueIndexes: z.array(z.union([indexFieldName, z.array(indexFieldName)])).optional(),\n});\n\nconst baseSettingFields = {\n\tlabel: z.string(),\n\tdescription: z.string().optional(),\n};\n\nconst settingFieldSchema = z.discriminatedUnion(\"type\", [\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"string\"),\n\t\tdefault: z.string().optional(),\n\t\tmultiline: z.boolean().optional(),\n\t}),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"number\"),\n\t\tdefault: z.number().optional(),\n\t\tmin: z.number().optional(),\n\t\tmax: z.number().optional(),\n\t}),\n\tz.object({ ...baseSettingFields, type: z.literal(\"boolean\"), default: z.boolean().optional() }),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"select\"),\n\t\toptions: z.array(z.object({ value: z.string(), label: z.string() })),\n\t\tdefault: z.string().optional(),\n\t}),\n\tz.object({ ...baseSettingFields, type: z.literal(\"secret\") }),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"url\"),\n\t\tdefault: z.string().optional(),\n\t\tplaceholder: z.string().optional(),\n\t}),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"email\"),\n\t\tdefault: z.string().optional(),\n\t\tplaceholder: z.string().optional(),\n\t}),\n]);\n\nconst adminPageSchema = z.object({\n\tpath: z.string(),\n\tlabel: z.string(),\n\ticon: z.string().optional(),\n});\n\nconst dashboardWidgetSchema = z.object({\n\tid: z.string(),\n\tsize: z.enum([\"full\", \"half\", \"third\"]).optional(),\n\ttitle: z.string().optional(),\n});\n\nconst pluginAdminConfigSchema = z.object({\n\tentry: z.string().optional(),\n\tsettingsSchema: z.record(z.string(), settingFieldSchema).optional(),\n\tpages: z.array(adminPageSchema).optional(),\n\twidgets: z.array(dashboardWidgetSchema).optional(),\n\tfieldWidgets: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tname: z.string().min(1),\n\t\t\t\tlabel: z.string().min(1),\n\t\t\t\tfieldTypes: z.array(z.enum(FIELD_TYPES)),\n\t\t\t\telements: z\n\t\t\t\t\t.array(\n\t\t\t\t\t\tz\n\t\t\t\t\t\t\t.object({\n\t\t\t\t\t\t\t\ttype: z.string(),\n\t\t\t\t\t\t\t\taction_id: z.string(),\n\t\t\t\t\t\t\t\tlabel: z.string().optional(),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.passthrough(),\n\t\t\t\t\t)\n\t\t\t\t\t.optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\n// ── Main schema ─────────────────────────────────────────────────\n\n/**\n * Zod schema matching the PluginManifest interface from types.ts.\n *\n * Every JSON.parse of a manifest.json should validate through this.\n */\nexport const pluginManifestSchema = z.object({\n\tid: z.string().min(1),\n\tversion: z.string().min(1),\n\tcapabilities: z.array(z.enum(PLUGIN_CAPABILITIES)),\n\tallowedHosts: z.array(z.string()),\n\tstorage: z.record(z.string(), storageCollectionSchema),\n\t/**\n\t * Hook declarations — accepts both plain name strings (legacy) and\n\t * structured objects with exclusive/priority/timeout metadata.\n\t * Plain strings are normalized to `{ name }` objects after parsing.\n\t */\n\thooks: z.array(z.union([z.enum(HOOK_NAMES), manifestHookEntrySchema])),\n\t/**\n\t * Route declarations — accepts both plain name strings and\n\t * structured objects with public metadata.\n\t * Plain strings are normalized to `{ name }` objects after parsing.\n\t */\n\troutes: z.array(\n\t\tz.union([\n\t\t\tz.string().min(1).regex(routeNamePattern, \"Route name must be a safe path segment\"),\n\t\t\tmanifestRouteEntrySchema,\n\t\t]),\n\t),\n\tadmin: pluginAdminConfigSchema,\n});\n\nexport type ValidatedPluginManifest = z.infer<typeof pluginManifestSchema>;\n\n/**\n * Normalize a manifest hook entry — plain strings become `{ name }` objects.\n */\nexport function normalizeManifestHook(\n\tentry: string | { name: string; exclusive?: boolean; priority?: number; timeout?: number },\n): { name: string; exclusive?: boolean; priority?: number; timeout?: number } {\n\tif (typeof entry === \"string\") {\n\t\treturn { name: entry };\n\t}\n\treturn entry;\n}\n\n/**\n * Normalize a manifest route entry — plain strings become `{ name }` objects.\n */\nexport function normalizeManifestRoute(entry: string | { name: string; public?: boolean }): {\n\tname: string;\n\tpublic?: boolean;\n} {\n\tif (typeof entry === \"string\") {\n\t\treturn { name: entry };\n\t}\n\treturn entry;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manifest-schema-Czqf0TLu.mjs","names":[],"sources":["../src/plugins/manifest-schema.ts"],"sourcesContent":["/**\n * Zod schema for PluginManifest validation\n *\n * Used to validate manifest.json from plugin bundles at every parse site:\n * - Client-side download (marketplace.ts extractBundle)\n * - R2 load (api/handlers/marketplace.ts loadBundleFromR2)\n * - CLI publish preview (cli/commands/publish.ts readManifestFromTarball)\n * - Marketplace ingest extends this with publishing-specific fields\n */\n\nimport { z } from \"zod\";\n\n// ── Enum values (must stay in sync with types.ts) ───────────────\n\n/**\n * Current capability names — the ones authors should use going forward.\n * See `PluginCapability` in `types.ts` for documentation of each.\n */\nexport const CURRENT_PLUGIN_CAPABILITIES = [\n\t\"network:request\",\n\t\"network:request:unrestricted\",\n\t\"content:read\",\n\t\"content:write\",\n\t\"media:read\",\n\t\"media:write\",\n\t\"users:read\",\n\t\"email:send\",\n\t\"hooks.email-transport:register\",\n\t\"hooks.email-events:register\",\n\t\"hooks.page-fragments:register\",\n] as const;\n\n/**\n * Legacy capability names accepted during the deprecation window.\n * Normalized to current names via `normalizeCapability()` in types.ts\n * before reaching the runtime. Plugin authors are warned at bundle/validate\n * and hard-failed at publish.\n */\nexport const DEPRECATED_PLUGIN_CAPABILITIES = [\n\t\"network:fetch\",\n\t\"network:fetch:any\",\n\t\"read:content\",\n\t\"write:content\",\n\t\"read:media\",\n\t\"write:media\",\n\t\"read:users\",\n\t\"email:provide\",\n\t\"email:intercept\",\n\t\"page:inject\",\n] as const;\n\n/**\n * Full set of accepted capability strings — current + deprecated.\n *\n * The manifest schema accepts both during the transition. The runtime only\n * ever sees current names because `normalizeCapability()` rewrites legacy\n * names at every external boundary (definePlugin, adaptSandboxEntry).\n */\nexport const PLUGIN_CAPABILITIES = [\n\t...CURRENT_PLUGIN_CAPABILITIES,\n\t...DEPRECATED_PLUGIN_CAPABILITIES,\n] as const;\n\n/** Must stay in sync with FieldType in schema/types.ts */\nconst FIELD_TYPES = [\n\t\"string\",\n\t\"text\",\n\t\"number\",\n\t\"integer\",\n\t\"boolean\",\n\t\"datetime\",\n\t\"select\",\n\t\"multiSelect\",\n\t\"portableText\",\n\t\"image\",\n\t\"file\",\n\t\"reference\",\n\t\"json\",\n\t\"slug\",\n\t\"repeater\",\n] as const;\n\nexport const HOOK_NAMES = [\n\t\"plugin:install\",\n\t\"plugin:activate\",\n\t\"plugin:deactivate\",\n\t\"plugin:uninstall\",\n\t\"content:beforeSave\",\n\t\"content:afterSave\",\n\t\"content:beforeDelete\",\n\t\"content:afterDelete\",\n\t\"content:afterPublish\",\n\t\"content:afterUnpublish\",\n\t\"media:beforeUpload\",\n\t\"media:afterUpload\",\n\t\"cron\",\n\t\"email:beforeSend\",\n\t\"email:deliver\",\n\t\"email:afterSend\",\n\t\"comment:beforeCreate\",\n\t\"comment:moderate\",\n\t\"comment:afterCreate\",\n\t\"comment:afterModerate\",\n\t\"page:metadata\",\n\t\"page:fragments\",\n] as const;\n\n/**\n * Structured hook entry for manifest — name plus optional metadata.\n * During a transition period, both plain strings and objects are accepted.\n */\nconst manifestHookEntrySchema = z.object({\n\tname: z.enum(HOOK_NAMES),\n\texclusive: z.boolean().optional(),\n\tpriority: z.number().int().optional(),\n\ttimeout: z.number().int().positive().optional(),\n});\n\n/**\n * Structured route entry for manifest — name plus optional metadata.\n * Both plain strings and objects are accepted; strings are normalized\n * to `{ name }` objects via `normalizeManifestRoute()`.\n */\n/** Route names must be safe path segments — alphanumeric, hyphens, underscores, forward slashes */\nconst routeNamePattern = /^[a-zA-Z0-9][a-zA-Z0-9_\\-/]*$/;\n\nconst manifestRouteEntrySchema = z.object({\n\tname: z.string().min(1).regex(routeNamePattern, \"Route name must be a safe path segment\"),\n\tpublic: z.boolean().optional(),\n});\n\n// ── Sub-schemas ─────────────────────────────────────────────────\n\n/** Index field names must be valid identifiers to prevent SQL injection via JSON path expressions */\nconst indexFieldName = z.string().regex(/^[a-zA-Z][a-zA-Z0-9_]*$/);\n\nconst storageCollectionSchema = z.object({\n\tindexes: z.array(z.union([indexFieldName, z.array(indexFieldName)])),\n\tuniqueIndexes: z.array(z.union([indexFieldName, z.array(indexFieldName)])).optional(),\n});\n\nconst baseSettingFields = {\n\tlabel: z.string(),\n\tdescription: z.string().optional(),\n};\n\nconst settingFieldSchema = z.discriminatedUnion(\"type\", [\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"string\"),\n\t\tdefault: z.string().optional(),\n\t\tmultiline: z.boolean().optional(),\n\t}),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"number\"),\n\t\tdefault: z.number().optional(),\n\t\tmin: z.number().optional(),\n\t\tmax: z.number().optional(),\n\t}),\n\tz.object({ ...baseSettingFields, type: z.literal(\"boolean\"), default: z.boolean().optional() }),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"select\"),\n\t\toptions: z.array(z.object({ value: z.string(), label: z.string() })),\n\t\tdefault: z.string().optional(),\n\t}),\n\tz.object({ ...baseSettingFields, type: z.literal(\"secret\") }),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"url\"),\n\t\tdefault: z.string().optional(),\n\t\tplaceholder: z.string().optional(),\n\t}),\n\tz.object({\n\t\t...baseSettingFields,\n\t\ttype: z.literal(\"email\"),\n\t\tdefault: z.string().optional(),\n\t\tplaceholder: z.string().optional(),\n\t}),\n]);\n\nconst adminPageSchema = z.object({\n\tpath: z.string(),\n\tlabel: z.string(),\n\ticon: z.string().optional(),\n});\n\nconst dashboardWidgetSchema = z.object({\n\tid: z.string(),\n\tsize: z.enum([\"full\", \"half\", \"third\"]).optional(),\n\ttitle: z.string().optional(),\n});\n\nconst pluginAdminConfigSchema = z.object({\n\tentry: z.string().optional(),\n\tsettingsSchema: z.record(z.string(), settingFieldSchema).optional(),\n\tpages: z.array(adminPageSchema).optional(),\n\twidgets: z.array(dashboardWidgetSchema).optional(),\n\tfieldWidgets: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tname: z.string().min(1),\n\t\t\t\tlabel: z.string().min(1),\n\t\t\t\tfieldTypes: z.array(z.enum(FIELD_TYPES)),\n\t\t\t\telements: z\n\t\t\t\t\t.array(\n\t\t\t\t\t\tz\n\t\t\t\t\t\t\t.object({\n\t\t\t\t\t\t\t\ttype: z.string(),\n\t\t\t\t\t\t\t\taction_id: z.string(),\n\t\t\t\t\t\t\t\tlabel: z.string().optional(),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.passthrough(),\n\t\t\t\t\t)\n\t\t\t\t\t.optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\n// ── Main schema ─────────────────────────────────────────────────\n\n/**\n * Zod schema matching the PluginManifest interface from types.ts.\n *\n * Every JSON.parse of a manifest.json should validate through this.\n */\nexport const pluginManifestSchema = z.object({\n\tid: z.string().min(1),\n\tversion: z.string().min(1),\n\tcapabilities: z.array(z.enum(PLUGIN_CAPABILITIES)),\n\tallowedHosts: z.array(z.string()),\n\tstorage: z.record(z.string(), storageCollectionSchema),\n\t/**\n\t * Hook declarations — accepts both plain name strings (legacy) and\n\t * structured objects with exclusive/priority/timeout metadata.\n\t * Plain strings are normalized to `{ name }` objects after parsing.\n\t */\n\thooks: z.array(z.union([z.enum(HOOK_NAMES), manifestHookEntrySchema])),\n\t/**\n\t * Route declarations — accepts both plain name strings and\n\t * structured objects with public metadata.\n\t * Plain strings are normalized to `{ name }` objects after parsing.\n\t */\n\troutes: z.array(\n\t\tz.union([\n\t\t\tz.string().min(1).regex(routeNamePattern, \"Route name must be a safe path segment\"),\n\t\t\tmanifestRouteEntrySchema,\n\t\t]),\n\t),\n\tadmin: pluginAdminConfigSchema,\n});\n\nexport type ValidatedPluginManifest = z.infer<typeof pluginManifestSchema>;\n\n/**\n * Normalize a manifest hook entry — plain strings become `{ name }` objects.\n */\nexport function normalizeManifestHook(\n\tentry: string | { name: string; exclusive?: boolean; priority?: number; timeout?: number },\n): { name: string; exclusive?: boolean; priority?: number; timeout?: number } {\n\tif (typeof entry === \"string\") {\n\t\treturn { name: entry };\n\t}\n\treturn entry;\n}\n\n/**\n * Normalize a manifest route entry — plain strings become `{ name }` objects.\n */\nexport function normalizeManifestRoute(entry: string | { name: string; public?: boolean }): {\n\tname: string;\n\tpublic?: boolean;\n} {\n\tif (typeof entry === \"string\") {\n\t\treturn { name: entry };\n\t}\n\treturn entry;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { _ as MediaValue, a as ComponentEmbed, b as mediaItemToValue, c as EmbedResult, d as MediaListResult, f as MediaProvider, g as MediaUploadInput, h as MediaProviderItem, i as AudioEmbed, l as ImageEmbed, m as MediaProviderDescriptor, n as generatePlaceholder, o as CreateMediaProviderFn, p as MediaProviderCapabilities, r as normalizeMediaValue, s as EmbedOptions, t as PlaceholderData, u as MediaListOptions, v as ThumbnailOptions, y as VideoEmbed } from "../placeholder-D3cFCU9y.mjs";
1
+ import { _ as MediaValue, a as ComponentEmbed, b as mediaItemToValue, c as EmbedResult, d as MediaListResult, f as MediaProvider, g as MediaUploadInput, h as MediaProviderItem, i as AudioEmbed, l as ImageEmbed, m as MediaProviderDescriptor, n as generatePlaceholder, o as CreateMediaProviderFn, p as MediaProviderCapabilities, r as normalizeMediaValue, s as EmbedOptions, t as PlaceholderData, u as MediaListOptions, v as ThumbnailOptions, y as VideoEmbed } from "../placeholder-KCkkCtgQ.mjs";
2
2
 
3
3
  //#region src/media/local.d.ts
4
4
  interface LocalMediaConfig {
@@ -1,14 +1,14 @@
1
- import "../options-Cq64Wx0O.mjs";
2
- import { t as Database } from "../types-C1KKK4VP.mjs";
3
- import "../types-B05e2naf.mjs";
4
- import "../bylines-BdUP8NuI.mjs";
5
- import { h as MediaProviderItem, o as CreateMediaProviderFn } from "../placeholder-D3cFCU9y.mjs";
6
- import "../index-BV8iJ-6s.mjs";
7
- import "../runner-DcfZewkO.mjs";
8
- import "../index-D2gvztOP.mjs";
9
- import { d as Storage } from "../types-DmxPPXGf.mjs";
10
- import "../types-Cb2UCDJg.mjs";
11
- import "../validate-BpQGsmd7.mjs";
1
+ import "../options-DhV-gwJb.mjs";
2
+ import { t as Database } from "../types-DaqNzqVt.mjs";
3
+ import "../types-DGHWRQgr.mjs";
4
+ import "../bylines-B2_XmnSU.mjs";
5
+ import { h as MediaProviderItem, o as CreateMediaProviderFn } from "../placeholder-KCkkCtgQ.mjs";
6
+ import "../index-BPZFAcgE.mjs";
7
+ import "../runner-DSQBurMS.mjs";
8
+ import "../index-CC42STEm.mjs";
9
+ import { d as Storage } from "../types-CkDSF81F.mjs";
10
+ import "../types-bYmRn_Uy.mjs";
11
+ import "../validate-DQtHw9NT.mjs";
12
12
  import "../index.mjs";
13
13
  import { Kysely } from "kysely";
14
14
 
@@ -1,11 +1,11 @@
1
1
  import "../dialect-helpers-BKCvISIQ.mjs";
2
2
  import "../base64-CqR-7kqF.mjs";
3
- import "../types-CwXMEPRr.mjs";
4
- import { t as MediaRepository } from "../media-Dg7he9uK.mjs";
3
+ import "../types-B0bmgwMG.mjs";
4
+ import { t as MediaRepository } from "../media-CKQd8AYU.mjs";
5
5
  import "../options-BL4X94qY.mjs";
6
6
  import "../request-cache-dzCt8TZB.mjs";
7
- import "../loader-Cs6-Bqe6.mjs";
8
- import { o as invalidateSiteSettingsCache } from "../settings-xQKsWnzQ.mjs";
7
+ import "../loader-D-vIJjfY.mjs";
8
+ import { o as invalidateSiteSettingsCache } from "../settings-BSXRtTzk.mjs";
9
9
 
10
10
  //#region src/media/local-runtime.ts
11
11
  /**
@@ -1,4 +1,4 @@
1
- import { i as encodeCursor, r as decodeCursor } from "./types-CwXMEPRr.mjs";
1
+ import { i as encodeCursor, r as decodeCursor } from "./types-B0bmgwMG.mjs";
2
2
  import { sql } from "kysely";
3
3
  import { ulid } from "ulidx";
4
4
 
@@ -206,4 +206,4 @@ var MediaRepository = class {
206
206
 
207
207
  //#endregion
208
208
  export { MediaRepository as t };
209
- //# sourceMappingURL=media-Dg7he9uK.mjs.map
209
+ //# sourceMappingURL=media-CKQd8AYU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-CKQd8AYU.mjs","names":[],"sources":["../src/database/repositories/media.ts"],"sourcesContent":["import { sql, type ExpressionBuilder, type Kysely, type SqlBool } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport type { Database, MediaRow } from \"../types.js\";\nimport type { FindManyResult } from \"./types.js\";\nimport { encodeCursor, decodeCursor } from \"./types.js\";\n\n/** Escape LIKE wildcard characters and the escape char itself in user-supplied values */\nfunction escapeLike(value: string): string {\n\treturn value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\");\n}\n\n/**\n * Normalize a mimeType filter (string or array) into a clean string[].\n * Entries that are empty strings are dropped.\n */\nfunction normalizeMimeFilter(input?: string | readonly string[]): string[] {\n\tif (!input) return [];\n\tconst arr = Array.isArray(input) ? input : [input];\n\treturn arr\n\t\t.filter((entry): entry is string => typeof entry === \"string\" && entry.length > 0)\n\t\t.map((entry) =>\n\t\t\tentry.endsWith(\"/\") ? entry.toLowerCase() : entry.split(\";\")[0].trim().toLowerCase(),\n\t\t);\n}\n\n/**\n * Build a WHERE clause that matches `mime_type` against any of the given\n * filter entries — exact equality for full MIMEs, LIKE prefix for entries\n * ending in \"/\".\n */\nfunction mimeMatchExpr(eb: ExpressionBuilder<Database, \"media\">, filters: string[]) {\n\treturn eb.or(\n\t\tfilters.map((entry) =>\n\t\t\tentry.endsWith(\"/\")\n\t\t\t\t? sql<SqlBool>`mime_type LIKE ${`${escapeLike(entry)}%`} ESCAPE '\\\\'`\n\t\t\t\t: eb(\"mime_type\", \"=\", entry),\n\t\t),\n\t);\n}\n\nexport type MediaStatus = \"pending\" | \"ready\" | \"failed\";\n\nexport interface MediaItem {\n\tid: string;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number | null;\n\twidth: number | null;\n\theight: number | null;\n\talt: string | null;\n\tcaption: string | null;\n\tstorageKey: string;\n\tstatus: MediaStatus;\n\tcontentHash: string | null;\n\tblurhash: string | null;\n\tdominantColor: string | null;\n\tcreatedAt: string;\n\tauthorId: string | null;\n}\n\nexport interface CreateMediaInput {\n\tfilename: string;\n\tmimeType: string;\n\tsize?: number;\n\twidth?: number;\n\theight?: number;\n\talt?: string;\n\tcaption?: string;\n\tstorageKey: string;\n\tcontentHash?: string;\n\tblurhash?: string;\n\tdominantColor?: string;\n\tstatus?: MediaStatus;\n\tauthorId?: string;\n}\n\nexport interface FindManyMediaOptions {\n\tlimit?: number;\n\tcursor?: string;\n\t/** Filter by MIME type. Pass a string for a single prefix/exact, or an array to match any. Strings ending with \"/\" are treated as LIKE prefix matches; others are exact equality. */\n\tmimeType?: string | readonly string[];\n\tstatus?: MediaStatus | \"all\"; // Filter by status, defaults to \"ready\"\n}\n\n/**\n * Media repository for database operations\n */\nexport class MediaRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new media item\n\t */\n\tasync create(input: CreateMediaInput): Promise<MediaItem> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tconst row: Omit<MediaRow, \"rowid\"> = {\n\t\t\tid,\n\t\t\tfilename: input.filename,\n\t\t\tmime_type: input.mimeType,\n\t\t\tsize: input.size ?? null,\n\t\t\twidth: input.width ?? null,\n\t\t\theight: input.height ?? null,\n\t\t\talt: input.alt ?? null,\n\t\t\tcaption: input.caption ?? null,\n\t\t\tstorage_key: input.storageKey,\n\t\t\tcontent_hash: input.contentHash ?? null,\n\t\t\tblurhash: input.blurhash ?? null,\n\t\t\tdominant_color: input.dominantColor ?? null,\n\t\t\tstatus: input.status ?? \"ready\",\n\t\t\tcreated_at: now,\n\t\t\tauthor_id: input.authorId ?? null,\n\t\t};\n\n\t\tawait this.db.insertInto(\"media\").values(row).execute();\n\n\t\treturn this.rowToItem(row as MediaRow);\n\t}\n\n\t/**\n\t * Create a pending media item (for signed URL upload flow)\n\t */\n\tasync createPending(input: {\n\t\tfilename: string;\n\t\tmimeType: string;\n\t\tsize?: number;\n\t\tstorageKey: string;\n\t\tcontentHash?: string;\n\t\tauthorId?: string;\n\t}): Promise<MediaItem> {\n\t\treturn this.create({\n\t\t\t...input,\n\t\t\tstatus: \"pending\",\n\t\t});\n\t}\n\n\t/**\n\t * Confirm upload (mark as ready)\n\t */\n\tasync confirmUpload(\n\t\tid: string,\n\t\tmetadata?: { width?: number; height?: number; size?: number },\n\t): Promise<MediaItem | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst updates: Partial<MediaRow> = {\n\t\t\tstatus: \"ready\",\n\t\t};\n\t\tif (metadata?.width !== undefined) updates.width = metadata.width;\n\t\tif (metadata?.height !== undefined) updates.height = metadata.height;\n\t\tif (metadata?.size !== undefined) updates.size = metadata.size;\n\n\t\tawait this.db.updateTable(\"media\").set(updates).where(\"id\", \"=\", id).execute();\n\n\t\treturn this.findById(id);\n\t}\n\n\t/**\n\t * Mark upload as failed\n\t */\n\tasync markFailed(id: string): Promise<MediaItem | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) {\n\t\t\treturn null;\n\t\t}\n\n\t\tawait this.db.updateTable(\"media\").set({ status: \"failed\" }).where(\"id\", \"=\", id).execute();\n\n\t\treturn this.findById(id);\n\t}\n\n\t/**\n\t * Find media by ID\n\t */\n\tasync findById(id: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by filename\n\t * Useful for idempotent imports\n\t */\n\tasync findByFilename(filename: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"filename\", \"=\", filename)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by content hash\n\t * Used for deduplication - same content = same hash\n\t */\n\tasync findByContentHash(contentHash: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"content_hash\", \"=\", contentHash)\n\t\t\t.where(\"status\", \"=\", \"ready\")\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find many media items with cursor pagination\n\t *\n\t * Uses keyset pagination (cursor-based) for consistent results.\n\t * The cursor encodes the created_at and id of the last item.\n\t */\n\tasync findMany(options: FindManyMediaOptions = {}): Promise<FindManyResult<MediaItem>> {\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\t// Handle cursor-based pagination — throws on invalid cursor.\n\t\tif (options.cursor) {\n\t\t\tconst { orderValue: createdAt, id: cursorId } = decodeCursor(options.cursor);\n\n\t\t\t// Keyset pagination: get items where (created_at, id) < cursor\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"created_at\", \"<\", createdAt),\n\t\t\t\t\teb.and([eb(\"created_at\", \"=\", createdAt), eb(\"id\", \"<\", cursorId)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst mimeFilters = normalizeMimeFilter(options.mimeType);\n\t\tif (mimeFilters.length > 0) {\n\t\t\tquery = query.where((eb) => mimeMatchExpr(eb, mimeFilters));\n\t\t}\n\n\t\t// Default to only showing ready items\n\t\tif (options.status !== \"all\") {\n\t\t\tquery = query.where(\"status\", \"=\", options.status ?? \"ready\");\n\t\t}\n\n\t\tconst rows = await query.execute();\n\n\t\tconst hasMore = rows.length > limit;\n\t\tconst items = rows.slice(0, limit).map((row) => this.rowToItem(row));\n\n\t\tlet nextCursor: string | undefined;\n\t\tif (hasMore && items.length > 0) {\n\t\t\tconst lastItem = items.at(-1)!;\n\t\t\tnextCursor = encodeCursor(lastItem.createdAt, lastItem.id);\n\t\t}\n\n\t\treturn { items, nextCursor };\n\t}\n\n\t/**\n\t * Update media metadata\n\t */\n\tasync update(\n\t\tid: string,\n\t\tinput: Partial<Pick<CreateMediaInput, \"alt\" | \"caption\" | \"width\" | \"height\">>,\n\t): Promise<MediaItem | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst updates: Partial<MediaRow> = {};\n\t\tif (input.alt !== undefined) updates.alt = input.alt;\n\t\tif (input.caption !== undefined) updates.caption = input.caption;\n\t\tif (input.width !== undefined) updates.width = input.width;\n\t\tif (input.height !== undefined) updates.height = input.height;\n\n\t\tif (Object.keys(updates).length > 0) {\n\t\t\tawait this.db.updateTable(\"media\").set(updates).where(\"id\", \"=\", id).execute();\n\t\t}\n\n\t\treturn this.findById(id);\n\t}\n\n\t/**\n\t * Delete media item\n\t */\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst result = await this.db.deleteFrom(\"media\").where(\"id\", \"=\", id).executeTakeFirst();\n\n\t\treturn (result.numDeletedRows ?? 0) > 0;\n\t}\n\n\t/**\n\t * Count media items\n\t */\n\tasync count(mimeType?: string | readonly string[]): Promise<number> {\n\t\tconst filters = normalizeMimeFilter(mimeType);\n\t\tlet query = this.db.selectFrom(\"media\").select((eb) => eb.fn.count<number>(\"id\").as(\"count\"));\n\n\t\tif (filters.length > 0) {\n\t\t\tquery = query.where((eb) => mimeMatchExpr(eb, filters));\n\t\t}\n\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result?.count || 0);\n\t}\n\n\t/**\n\t * Delete pending uploads older than the given age.\n\t * Pending uploads that were never confirmed indicate abandoned upload flows.\n\t *\n\t * Returns the storage keys of deleted rows so callers can remove the\n\t * corresponding files from object storage.\n\t */\n\tasync cleanupPendingUploads(maxAgeMs: number = 60 * 60 * 1000): Promise<string[]> {\n\t\tconst cutoff = new Date(Date.now() - maxAgeMs).toISOString();\n\n\t\t// Select the storage keys first -- SQLite doesn't support RETURNING\n\t\t// on DELETE in all drivers, and Kysely's RETURNING isn't universal.\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.select(\"storage_key\")\n\t\t\t.where(\"status\", \"=\", \"pending\")\n\t\t\t.where(\"created_at\", \"<\", cutoff)\n\t\t\t.execute();\n\n\t\tif (rows.length === 0) return [];\n\n\t\tawait this.db\n\t\t\t.deleteFrom(\"media\")\n\t\t\t.where(\"status\", \"=\", \"pending\")\n\t\t\t.where(\"created_at\", \"<\", cutoff)\n\t\t\t.execute();\n\n\t\treturn rows.map((r) => r.storage_key);\n\t}\n\n\t/**\n\t * Convert database row to MediaItem\n\t */\n\tprivate rowToItem(row: MediaRow): MediaItem {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tfilename: row.filename,\n\t\t\tmimeType: row.mime_type,\n\t\t\tsize: row.size,\n\t\t\twidth: row.width,\n\t\t\theight: row.height,\n\t\t\talt: row.alt,\n\t\t\tcaption: row.caption,\n\t\t\tstorageKey: row.storage_key,\n\t\t\tcontentHash: row.content_hash,\n\t\t\tblurhash: row.blurhash,\n\t\t\tdominantColor: row.dominant_color,\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- DB stores string; validated at insert but linter can't follow\n\t\t\tstatus: row.status as MediaStatus,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tauthorId: row.author_id,\n\t\t};\n\t}\n}\n"],"mappings":"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"}
@@ -29,4 +29,4 @@ async function resolveFieldAllowlist(db, fieldId) {
29
29
 
30
30
  //#endregion
31
31
  export { resolveFieldAllowlist as n, GLOBAL_UPLOAD_ALLOWLIST as t };
32
- //# sourceMappingURL=media-allowlist-B8EX01DH.mjs.map
32
+ //# sourceMappingURL=media-allowlist-BNloC69x.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"media-allowlist-B8EX01DH.mjs","names":[],"sources":["../src/api/handlers/media-allowlist.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { parseAllowedMimeTypes } from \"../../media/mime.js\";\n\n/**\n * MIME types allowed for upload by default (when no field-specific list\n * overrides this). Entries ending with \"/\" are prefix-matched (e.g.\n * \"image/\" matches \"image/jpeg\", \"image/png\", etc.).\n */\nexport const GLOBAL_UPLOAD_ALLOWLIST: readonly string[] = [\n\t\"image/\",\n\t\"video/\",\n\t\"audio/\",\n\t\"application/pdf\",\n];\n\n/**\n * Resolve the MIME allowlist for a specific field.\n *\n * Returns the field's `allowedMimeTypes` list when the field exists, is of\n * type \"file\" or \"image\", and has a non-empty list configured. Returns null\n * in all other cases — callers should fall back to GLOBAL_UPLOAD_ALLOWLIST.\n *\n * Authentication is the caller's responsibility (the upload routes already\n * gate on `media:upload`).\n */\nexport async function resolveFieldAllowlist(\n\tdb: Kysely<Database>,\n\tfieldId: string,\n): Promise<string[] | null> {\n\tconst row = await db\n\t\t.selectFrom(\"_emdash_fields\")\n\t\t.select([\"type\", \"validation\"])\n\t\t.where(\"id\", \"=\", fieldId)\n\t\t.where(\"type\", \"in\", [\"file\", \"image\"])\n\t\t.executeTakeFirst();\n\n\treturn row ? parseAllowedMimeTypes(row.validation) : null;\n}\n"],"mappings":";;;;;;;;AAUA,MAAa,0BAA6C;CACzD;CACA;CACA;CACA;CACA;;;;;;;;;;;AAYD,eAAsB,sBACrB,IACA,SAC2B;CAC3B,MAAM,MAAM,MAAM,GAChB,WAAW,iBAAiB,CAC5B,OAAO,CAAC,QAAQ,aAAa,CAAC,CAC9B,MAAM,MAAM,KAAK,QAAQ,CACzB,MAAM,QAAQ,MAAM,CAAC,QAAQ,QAAQ,CAAC,CACtC,kBAAkB;AAEpB,QAAO,MAAM,sBAAsB,IAAI,WAAW,GAAG"}
1
+ {"version":3,"file":"media-allowlist-BNloC69x.mjs","names":[],"sources":["../src/api/handlers/media-allowlist.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { parseAllowedMimeTypes } from \"../../media/mime.js\";\n\n/**\n * MIME types allowed for upload by default (when no field-specific list\n * overrides this). Entries ending with \"/\" are prefix-matched (e.g.\n * \"image/\" matches \"image/jpeg\", \"image/png\", etc.).\n */\nexport const GLOBAL_UPLOAD_ALLOWLIST: readonly string[] = [\n\t\"image/\",\n\t\"video/\",\n\t\"audio/\",\n\t\"application/pdf\",\n];\n\n/**\n * Resolve the MIME allowlist for a specific field.\n *\n * Returns the field's `allowedMimeTypes` list when the field exists, is of\n * type \"file\" or \"image\", and has a non-empty list configured. Returns null\n * in all other cases — callers should fall back to GLOBAL_UPLOAD_ALLOWLIST.\n *\n * Authentication is the caller's responsibility (the upload routes already\n * gate on `media:upload`).\n */\nexport async function resolveFieldAllowlist(\n\tdb: Kysely<Database>,\n\tfieldId: string,\n): Promise<string[] | null> {\n\tconst row = await db\n\t\t.selectFrom(\"_emdash_fields\")\n\t\t.select([\"type\", \"validation\"])\n\t\t.where(\"id\", \"=\", fieldId)\n\t\t.where(\"type\", \"in\", [\"file\", \"image\"])\n\t\t.executeTakeFirst();\n\n\treturn row ? parseAllowedMimeTypes(row.validation) : null;\n}\n"],"mappings":";;;;;;;;AAUA,MAAa,0BAA6C;CACzD;CACA;CACA;CACA;CACA;;;;;;;;;;;AAYD,eAAsB,sBACrB,IACA,SAC2B;CAC3B,MAAM,MAAM,MAAM,GAChB,WAAW,iBAAiB,CAC5B,OAAO,CAAC,QAAQ,aAAa,CAAC,CAC9B,MAAM,MAAM,KAAK,QAAQ,CACzB,MAAM,QAAQ,MAAM,CAAC,QAAQ,QAAQ,CAAC,CACtC,kBAAkB;AAEpB,QAAO,MAAM,sBAAsB,IAAI,WAAW,GAAG"}
@@ -1,18 +1,18 @@
1
1
  import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
2
- import { t as CommentRepository } from "./comment-Dd9MI82-.mjs";
2
+ import { t as CommentRepository } from "./comment-C76G-9tz.mjs";
3
3
  import { t as OptionsRepository } from "./options-BL4X94qY.mjs";
4
- import { t as PluginContextFactory } from "./context-qF8d3IPR.mjs";
4
+ import { t as PluginContextFactory } from "./context-B7qiYrz2.mjs";
5
5
  import { n as requestCached } from "./request-cache-dzCt8TZB.mjs";
6
- import { r as getDb } from "./loader-Cs6-Bqe6.mjs";
7
- import { d as resolveLocale, f as resolveLocaleChain } from "./taxonomies-Cn9UpaR2.mjs";
8
- import { r as normalizeCapabilities } from "./types-Db67HHlU.mjs";
9
- import { dt as sanitizeHref } from "./redirects-Dmj6KRU3.mjs";
10
- import { t as extractRequestMeta } from "./request-meta-CLCwSQOS.mjs";
11
- import { r as setCronTasksEnabled } from "./cron-H8eJ46dv.mjs";
6
+ import { r as getDb } from "./loader-D-vIJjfY.mjs";
7
+ import { i as resolveLocaleChain, r as resolveLocale } from "./resolve-D6sM-SgF.mjs";
8
+ import { r as normalizeCapabilities } from "./types-1NNkmTIn.mjs";
9
+ import { dt as sanitizeHref } from "./redirects-COMLwsV5.mjs";
10
+ import { t as extractRequestMeta } from "./request-meta-C_Cjii-T.mjs";
11
+ import { r as setCronTasksEnabled } from "./cron-Bd3b3iuj.mjs";
12
12
  import { sql } from "kysely";
13
- import { AsyncLocalStorage } from "node:async_hooks";
14
13
  import { ulid } from "ulidx";
15
14
  import { z } from "astro/zod";
15
+ import { AsyncLocalStorage } from "node:async_hooks";
16
16
 
17
17
  //#region src/fields/image.ts
18
18
  const imageSchema = z.object({
@@ -374,7 +374,8 @@ function portableTextToProsemirror(blocks) {
374
374
  const listType = block.listItem;
375
375
  while (i < blocks.length) {
376
376
  const current = blocks[i];
377
- if (isTextBlock(current) && current.listItem === listType) {
377
+ if (!isTextBlock(current) || !current.listItem) break;
378
+ if ((current.level || 1) > 1 || current.listItem === listType) {
378
379
  listBlocks.push(current);
379
380
  i++;
380
381
  } else break;
@@ -497,20 +498,25 @@ function convertListItem(item, nestedItems, parentListType) {
497
498
  content: spans.length > 0 ? spans : void 0
498
499
  });
499
500
  if (nestedItems.length > 0) {
501
+ let minLevel = Infinity;
502
+ for (const ni of nestedItems) {
503
+ const level = ni.level || 2;
504
+ if (level < minLevel) minLevel = level;
505
+ }
500
506
  let j = 0;
501
507
  while (j < nestedItems.length) {
502
- const nestedListType = nestedItems[j].listItem || parentListType;
508
+ const anchorType = nestedItems[j].listItem || parentListType;
503
509
  const nestedGroup = [];
504
- while (j < nestedItems.length && (nestedItems[j].listItem || parentListType) === nestedListType) {
510
+ do {
505
511
  nestedGroup.push(nestedItems[j]);
506
512
  j++;
507
- }
513
+ } while (j < nestedItems.length && ((nestedItems[j].level || 2) > minLevel || (nestedItems[j].listItem || parentListType) === anchorType));
508
514
  if (nestedGroup.length > 0) {
509
515
  const adjustedGroup = nestedGroup.map((ni) => ({
510
516
  ...ni,
511
517
  level: (ni.level || 2) - 1
512
518
  }));
513
- content.push(convertList(adjustedGroup, nestedListType));
519
+ content.push(convertList(adjustedGroup, anchorType));
514
520
  }
515
521
  }
516
522
  }
@@ -2472,7 +2478,7 @@ function createPluginManager(options) {
2472
2478
  */
2473
2479
  var SandboxNotAvailableError = class extends Error {
2474
2480
  constructor() {
2475
- super("Plugin sandboxing is not available on this platform. Sandboxed plugins require Cloudflare Workers with Worker Loader. Use trusted plugins (from config) instead, or deploy to Cloudflare.");
2481
+ super("Plugin sandboxing is not available. Configure a sandbox runner: use @emdash-cms/cloudflare/sandbox on Cloudflare, or @emdash-cms/sandbox-workerd/sandbox on Node.js (requires workerd). Without sandboxing, use trusted plugins (from config) instead.");
2476
2482
  this.name = "SandboxNotAvailableError";
2477
2483
  }
2478
2484
  };
@@ -2493,6 +2499,12 @@ var NoopSandboxRunner = class {
2493
2499
  return false;
2494
2500
  }
2495
2501
  /**
2502
+ * Always returns false - no sandbox runtime to be healthy.
2503
+ */
2504
+ isHealthy() {
2505
+ return false;
2506
+ }
2507
+ /**
2496
2508
  * Always throws - can't load sandboxed plugins without isolation.
2497
2509
  */
2498
2510
  async load(_manifest, _code) {
@@ -2515,6 +2527,19 @@ function createNoopSandboxRunner(_options) {
2515
2527
  return new NoopSandboxRunner();
2516
2528
  }
2517
2529
 
2530
+ //#endregion
2531
+ //#region src/plugins/sandbox/types.ts
2532
+ /**
2533
+ * Error thrown when the sandbox runtime is unavailable.
2534
+ * This happens when the sidecar process has crashed or hasn't started.
2535
+ */
2536
+ var SandboxUnavailableError = class extends Error {
2537
+ constructor(pluginId, reason) {
2538
+ super(`Plugin sandbox unavailable for ${pluginId}: ${reason}`);
2539
+ this.name = "SandboxUnavailableError";
2540
+ }
2541
+ };
2542
+
2518
2543
  //#endregion
2519
2544
  //#region src/comments/query.ts
2520
2545
  /**
@@ -2784,5 +2809,5 @@ async function resolveTaxonomyUrl(referenceGroup, db, locale) {
2784
2809
  }
2785
2810
 
2786
2811
  //#endregion
2787
- export { image as C, file as S, after as _, NoopSandboxRunner as a, portableText as b, PluginManager as c, PluginRouteRegistry as d, EmailPipeline as f, definePlugin as g, resolveExclusiveHooks as h, getComments as i, createPluginManager as l, createHookPipeline as m, getMenus as n, SandboxNotAvailableError as o, HookPipeline as p, getCommentCount as r, createNoopSandboxRunner as s, getMenu as t, PluginRouteError as u, portableTextToProsemirror as v, reference as x, prosemirrorToPortableText as y };
2788
- //# sourceMappingURL=menus-X4Z-eBA1.mjs.map
2812
+ export { file as C, reference as S, definePlugin as _, SandboxUnavailableError as a, prosemirrorToPortableText as b, createNoopSandboxRunner as c, PluginRouteError as d, PluginRouteRegistry as f, resolveExclusiveHooks as g, createHookPipeline as h, getComments as i, PluginManager as l, HookPipeline as m, getMenus as n, NoopSandboxRunner as o, EmailPipeline as p, getCommentCount as r, SandboxNotAvailableError as s, getMenu as t, createPluginManager as u, after as v, image as w, portableText as x, portableTextToProsemirror as y };
2813
+ //# sourceMappingURL=menus-C-nWT5Tu.mjs.map