emdash 0.26.0 → 0.27.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 (366) hide show
  1. package/dist/{adapters-DAAjOID4.d.mts → adapters-u037EnTR.d.mts} +1 -1
  2. package/dist/{adapters-DAAjOID4.d.mts.map → adapters-u037EnTR.d.mts.map} +1 -1
  3. package/dist/api/route-utils.mjs +10 -10
  4. package/dist/api/schemas/index.d.mts +1 -1
  5. package/dist/{api-BMfveMoB.mjs → api-80kycR9o.mjs} +84 -28
  6. package/dist/api-80kycR9o.mjs.map +1 -0
  7. package/dist/{apply--IVNSdXn.mjs → apply-DSypk6Iu.mjs} +19 -19
  8. package/dist/apply-DSypk6Iu.mjs.map +1 -0
  9. package/dist/astro/index.d.mts +7 -6
  10. package/dist/astro/index.d.mts.map +1 -1
  11. package/dist/astro/index.mjs +11 -3
  12. package/dist/astro/index.mjs.map +1 -1
  13. package/dist/astro/middleware/auth.d.mts +6 -5
  14. package/dist/astro/middleware/auth.d.mts.map +1 -1
  15. package/dist/astro/middleware/auth.mjs +4 -3
  16. package/dist/astro/middleware/auth.mjs.map +1 -1
  17. package/dist/astro/middleware/redirect.mjs +4 -4
  18. package/dist/astro/middleware.d.mts +1 -8
  19. package/dist/astro/middleware.d.mts.map +1 -1
  20. package/dist/astro/middleware.mjs +44 -43
  21. package/dist/astro/middleware.mjs.map +1 -1
  22. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +3 -3
  23. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +3 -3
  24. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
  25. package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
  26. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
  27. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +4 -4
  28. package/dist/astro/routes/api/admin/byline-fields/index.mjs +4 -4
  29. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +4 -4
  30. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +9 -9
  31. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +9 -9
  32. package/dist/astro/routes/api/admin/bylines/index.mjs +9 -9
  33. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +7 -7
  34. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  35. package/dist/astro/routes/api/admin/comments/bulk.mjs +6 -6
  36. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  37. package/dist/astro/routes/api/admin/comments/index.mjs +6 -6
  38. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  39. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  40. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  41. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  42. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +27 -27
  43. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  44. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +27 -27
  45. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  46. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +27 -27
  47. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  48. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +26 -26
  49. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +26 -26
  50. package/dist/astro/routes/api/admin/plugins/index.mjs +27 -27
  51. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  52. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  53. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +26 -26
  54. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +26 -26
  55. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +26 -26
  56. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +26 -26
  57. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +27 -27
  58. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +26 -26
  59. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +27 -27
  60. package/dist/astro/routes/api/admin/plugins/updates.mjs +26 -26
  61. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +26 -26
  62. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  63. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +26 -26
  64. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  65. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  66. package/dist/astro/routes/api/admin/users/_id_/index.mjs +3 -3
  67. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  68. package/dist/astro/routes/api/admin/users/index.mjs +3 -3
  69. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  70. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  71. package/dist/astro/routes/api/auth/invite/complete.mjs +3 -3
  72. package/dist/astro/routes/api/auth/invite/index.mjs +3 -3
  73. package/dist/astro/routes/api/auth/invite/register-options.mjs +3 -3
  74. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  75. package/dist/astro/routes/api/auth/magic-link/send.mjs +4 -4
  76. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  77. package/dist/astro/routes/api/auth/me.mjs +4 -4
  78. package/dist/astro/routes/api/auth/passkey/_id_.mjs +3 -3
  79. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  80. package/dist/astro/routes/api/auth/passkey/options.mjs +4 -4
  81. package/dist/astro/routes/api/auth/passkey/register/options.mjs +3 -3
  82. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +3 -3
  83. package/dist/astro/routes/api/auth/passkey/verify.mjs +3 -3
  84. package/dist/astro/routes/api/auth/signup/complete.mjs +3 -3
  85. package/dist/astro/routes/api/auth/signup/request.mjs +4 -4
  86. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  87. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +6 -6
  88. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +6 -6
  89. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  90. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  91. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  92. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  93. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +4 -4
  94. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +4 -4
  95. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  96. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  97. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +4 -4
  98. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +8 -8
  99. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  100. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  101. package/dist/astro/routes/api/content/_collection_/_id_.mjs +4 -4
  102. package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
  103. package/dist/astro/routes/api/content/_collection_/index.mjs +4 -4
  104. package/dist/astro/routes/api/content/_collection_/trash.mjs +4 -4
  105. package/dist/astro/routes/api/dashboard.mjs +7 -7
  106. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  107. package/dist/astro/routes/api/import/probe.d.mts +2 -2
  108. package/dist/astro/routes/api/import/probe.mjs +4 -4
  109. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  110. package/dist/astro/routes/api/import/wordpress/execute.d.mts +6 -5
  111. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  112. package/dist/astro/routes/api/import/wordpress/execute.mjs +8 -8
  113. package/dist/astro/routes/api/import/wordpress/media.d.mts +6 -5
  114. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  115. package/dist/astro/routes/api/import/wordpress/media.mjs +4 -4
  116. package/dist/astro/routes/api/import/wordpress/prepare.mjs +6 -6
  117. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +5 -5
  118. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  119. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +4 -4
  120. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  121. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +6 -6
  122. package/dist/astro/routes/api/manifest.d.mts.map +1 -1
  123. package/dist/astro/routes/api/manifest.mjs +13 -4
  124. package/dist/astro/routes/api/manifest.mjs.map +1 -1
  125. package/dist/astro/routes/api/mcp.mjs +34 -34
  126. package/dist/astro/routes/api/media/_id_/confirm.mjs +4 -4
  127. package/dist/astro/routes/api/media/_id_.mjs +4 -4
  128. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  129. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  130. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  131. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  132. package/dist/astro/routes/api/media/upload-url.mjs +4 -4
  133. package/dist/astro/routes/api/media.mjs +5 -5
  134. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +5 -5
  135. package/dist/astro/routes/api/menus/_name_/items.mjs +5 -5
  136. package/dist/astro/routes/api/menus/_name_/reorder.mjs +5 -5
  137. package/dist/astro/routes/api/menus/_name_/translations.mjs +5 -5
  138. package/dist/astro/routes/api/menus/_name_.mjs +5 -5
  139. package/dist/astro/routes/api/menus/index.mjs +5 -5
  140. package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
  141. package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
  142. package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
  143. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  144. package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
  145. package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
  146. package/dist/astro/routes/api/oauth/token.mjs +2 -2
  147. package/dist/astro/routes/api/openapi.json.mjs +2 -2
  148. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
  149. package/dist/astro/routes/api/redirects/404s/index.mjs +6 -6
  150. package/dist/astro/routes/api/redirects/404s/summary.mjs +6 -6
  151. package/dist/astro/routes/api/redirects/_id_.mjs +7 -7
  152. package/dist/astro/routes/api/redirects/index.mjs +7 -7
  153. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  154. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  155. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +26 -26
  156. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +26 -26
  157. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +26 -26
  158. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +26 -26
  159. package/dist/astro/routes/api/schema/collections/index.mjs +26 -26
  160. package/dist/astro/routes/api/schema/index.mjs +6 -6
  161. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +26 -26
  162. package/dist/astro/routes/api/schema/orphans/index.mjs +26 -26
  163. package/dist/astro/routes/api/search/enable.mjs +7 -7
  164. package/dist/astro/routes/api/search/index.mjs +6 -6
  165. package/dist/astro/routes/api/search/rebuild.mjs +7 -7
  166. package/dist/astro/routes/api/search/stats.mjs +6 -6
  167. package/dist/astro/routes/api/search/suggest.mjs +6 -6
  168. package/dist/astro/routes/api/sections/_slug_.mjs +6 -6
  169. package/dist/astro/routes/api/sections/index.mjs +6 -6
  170. package/dist/astro/routes/api/settings/email.mjs +4 -4
  171. package/dist/astro/routes/api/settings.mjs +8 -8
  172. package/dist/astro/routes/api/setup/admin-verify.mjs +3 -3
  173. package/dist/astro/routes/api/setup/admin.mjs +3 -3
  174. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
  175. package/dist/astro/routes/api/setup/dev-bypass.mjs +19 -17
  176. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  177. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  178. package/dist/astro/routes/api/setup/index.mjs +17 -17
  179. package/dist/astro/routes/api/setup/status.mjs +3 -3
  180. package/dist/astro/routes/api/snapshot.mjs +3 -3
  181. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +8 -8
  182. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +8 -8
  183. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +8 -8
  184. package/dist/astro/routes/api/taxonomies/index.mjs +8 -8
  185. package/dist/astro/routes/api/themes/preview.mjs +3 -3
  186. package/dist/astro/routes/api/typegen.mjs +5 -5
  187. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +4 -4
  188. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +6 -6
  189. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +6 -6
  190. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  191. package/dist/astro/routes/api/widget-areas/index.mjs +6 -6
  192. package/dist/astro/routes/api/widget-components.mjs +2 -2
  193. package/dist/astro/routes/robots.txt.mjs +4 -4
  194. package/dist/astro/routes/sitemap-_collection_.xml.mjs +4 -4
  195. package/dist/astro/routes/sitemap.xml.mjs +4 -4
  196. package/dist/astro/types.d.mts +8 -6
  197. package/dist/astro/types.d.mts.map +1 -1
  198. package/dist/auth/providers/github.d.mts +1 -1
  199. package/dist/auth/providers/google.d.mts +1 -1
  200. package/dist/{authorize-BZnOGJFo.mjs → authorize-C3a_zGsM.mjs} +2 -2
  201. package/dist/{authorize-BZnOGJFo.mjs.map → authorize-C3a_zGsM.mjs.map} +1 -1
  202. package/dist/{byline-LL8lyqdb.mjs → byline-DEKSVPTy.mjs} +5 -5
  203. package/dist/{byline-LL8lyqdb.mjs.map → byline-DEKSVPTy.mjs.map} +1 -1
  204. package/dist/{byline-fields-KD3JFRuH.d.mts → byline-fields-CtQ6blXd.d.mts} +32 -32
  205. package/dist/{byline-fields-KD3JFRuH.d.mts.map → byline-fields-CtQ6blXd.d.mts.map} +1 -1
  206. package/dist/{bylines-DE47vP8d.mjs → bylines-CiqgTHWF.mjs} +5 -5
  207. package/dist/{bylines-DE47vP8d.mjs.map → bylines-CiqgTHWF.mjs.map} +1 -1
  208. package/dist/{bylines-BmJ7Vg7J.mjs → bylines-Ds4-otXl.mjs} +4 -4
  209. package/dist/{bylines-BmJ7Vg7J.mjs.map → bylines-Ds4-otXl.mjs.map} +1 -1
  210. package/dist/{cache-D9jF5bYw.mjs → cache-Ciu3e3AF.mjs} +2 -2
  211. package/dist/{cache-D9jF5bYw.mjs.map → cache-Ciu3e3AF.mjs.map} +1 -1
  212. package/dist/{chunks-OCG163rN.mjs → chunks-CZFiauig.mjs} +2 -2
  213. package/dist/{chunks-OCG163rN.mjs.map → chunks-CZFiauig.mjs.map} +1 -1
  214. package/dist/cli/index.mjs +15 -15
  215. package/dist/cli/index.mjs.map +1 -1
  216. package/dist/client/cf-access.d.mts +1 -1
  217. package/dist/client/index.d.mts +1 -1
  218. package/dist/{comment-D9BLDpZI.mjs → comment-CH1IrFFs.mjs} +2 -2
  219. package/dist/{comment-D9BLDpZI.mjs.map → comment-CH1IrFFs.mjs.map} +1 -1
  220. package/dist/{comment-reaction-Drl9SkNu.mjs → comment-reaction-kruNY-kP.mjs} +2 -2
  221. package/dist/{comment-reaction-Drl9SkNu.mjs.map → comment-reaction-kruNY-kP.mjs.map} +1 -1
  222. package/dist/{comments-BjJ9SKGU.mjs → comments-BUJyXbgq.mjs} +3 -3
  223. package/dist/{comments-BjJ9SKGU.mjs.map → comments-BUJyXbgq.mjs.map} +1 -1
  224. package/dist/{content-ncUWWjna.mjs → content-RmfHoWqK.mjs} +3 -3
  225. package/dist/{content-ncUWWjna.mjs.map → content-RmfHoWqK.mjs.map} +1 -1
  226. package/dist/{context-C_g-iJVA.mjs → context-CzUU_WzL.mjs} +7 -7
  227. package/dist/{context-C_g-iJVA.mjs.map → context-CzUU_WzL.mjs.map} +1 -1
  228. package/dist/{dashboard-CotyqQrW.mjs → dashboard-CVyGhift.mjs} +4 -4
  229. package/dist/{dashboard-CotyqQrW.mjs.map → dashboard-CVyGhift.mjs.map} +1 -1
  230. package/dist/db/index.d.mts +1 -1
  231. package/dist/db/index.mjs +1 -1
  232. package/dist/db/libsql.d.mts +1 -1
  233. package/dist/db/postgres.d.mts +1 -1
  234. package/dist/db/sqlite.d.mts +1 -1
  235. package/dist/{error-rVGiqWDt.mjs → error-BHkLZk-w.mjs} +2 -2
  236. package/dist/{error-rVGiqWDt.mjs.map → error-BHkLZk-w.mjs.map} +1 -1
  237. package/dist/{field-defs-cache-ljXzJCfc.mjs → field-defs-cache-BA-8ZPiT.mjs} +2 -2
  238. package/dist/{field-defs-cache-ljXzJCfc.mjs.map → field-defs-cache-BA-8ZPiT.mjs.map} +1 -1
  239. package/dist/{fts-manager-BbCCbEKA.mjs → fts-manager-Db9jGavf.mjs} +2 -2
  240. package/dist/{fts-manager-BbCCbEKA.mjs.map → fts-manager-Db9jGavf.mjs.map} +1 -1
  241. package/dist/{index-BRNabKrx.d.mts → index-CDZZjrLT.d.mts} +2407 -2365
  242. package/dist/index-CDZZjrLT.d.mts.map +1 -0
  243. package/dist/{index-Dt0OKJB4.d.mts → index-DGIjmUXQ.d.mts} +2 -2
  244. package/dist/{index-Dt0OKJB4.d.mts.map → index-DGIjmUXQ.d.mts.map} +1 -1
  245. package/dist/index.d.mts +11 -10
  246. package/dist/index.mjs +36 -36
  247. package/dist/{load-DMjXghbZ.mjs → load-DpHICVPh.mjs} +2 -2
  248. package/dist/{load-DMjXghbZ.mjs.map → load-DpHICVPh.mjs.map} +1 -1
  249. package/dist/{loader-BA_zhkS_.mjs → loader-4K37qA-y.mjs} +3 -3
  250. package/dist/{loader-BA_zhkS_.mjs.map → loader-4K37qA-y.mjs.map} +1 -1
  251. package/dist/media/local-runtime.d.mts +7 -6
  252. package/dist/media/local-runtime.d.mts.map +1 -1
  253. package/dist/media/local-runtime.mjs +4 -4
  254. package/dist/{media-C5t_eCnk.mjs → media-C0nRRfs1.mjs} +2 -2
  255. package/dist/{media-C5t_eCnk.mjs.map → media-C0nRRfs1.mjs.map} +1 -1
  256. package/dist/{menus-CYH09a41.mjs → menus-DzRyC1ID.mjs} +5 -5
  257. package/dist/{menus-CYH09a41.mjs.map → menus-DzRyC1ID.mjs.map} +1 -1
  258. package/dist/{menus-CBb6UrMU.mjs → menus-SL2K0xq2.mjs} +2 -2
  259. package/dist/{menus-CBb6UrMU.mjs.map → menus-SL2K0xq2.mjs.map} +1 -1
  260. package/dist/object-cache/memory.d.mts +1 -1
  261. package/dist/page/index.d.mts +1 -1
  262. package/dist/{parse-BwAdS7FZ.mjs → parse-CqyZj3Hp.mjs} +2 -2
  263. package/dist/{parse-BwAdS7FZ.mjs.map → parse-CqyZj3Hp.mjs.map} +1 -1
  264. package/dist/plugin-utils.d.mts +6 -5
  265. package/dist/plugin-utils.d.mts.map +1 -1
  266. package/dist/plugins/adapt-sandbox-entry.d.mts +6 -5
  267. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  268. package/dist/{query-BpQb-blG.mjs → query-B0M-9LYR.mjs} +13 -13
  269. package/dist/{query-BpQb-blG.mjs.map → query-B0M-9LYR.mjs.map} +1 -1
  270. package/dist/{rate-limit-Dap6HMNM.mjs → rate-limit-BwoUdIpC.mjs} +2 -2
  271. package/dist/{rate-limit-Dap6HMNM.mjs.map → rate-limit-BwoUdIpC.mjs.map} +1 -1
  272. package/dist/{redirect-_M0trWoo.mjs → redirect-lMOzG04S.mjs} +2 -2
  273. package/dist/{redirect-_M0trWoo.mjs.map → redirect-lMOzG04S.mjs.map} +1 -1
  274. package/dist/{redirects-w0V9vj_j.mjs → redirects-9218MmYl.mjs} +3 -3
  275. package/dist/{redirects-w0V9vj_j.mjs.map → redirects-9218MmYl.mjs.map} +1 -1
  276. package/dist/{registry-g8yYt4cC.mjs → registry-DP-iEtdR.mjs} +4 -4
  277. package/dist/{registry-g8yYt4cC.mjs.map → registry-DP-iEtdR.mjs.map} +1 -1
  278. package/dist/runner-BbR3DfrL.d.mts.map +1 -1
  279. package/dist/{runner-DPdt_Wpa.mjs → runner-CFngB4WZ.mjs} +232 -199
  280. package/dist/runner-CFngB4WZ.mjs.map +1 -0
  281. package/dist/runtime.d.mts +6 -5
  282. package/dist/runtime.d.mts.map +1 -1
  283. package/dist/runtime.mjs +2 -2
  284. package/dist/scheduled-publish-BMljtY5G.d.mts +11 -0
  285. package/dist/scheduled-publish-BMljtY5G.d.mts.map +1 -0
  286. package/dist/{schema-DoLd3j2e.mjs → schema-BfJ7bIXH.mjs} +4 -4
  287. package/dist/{schema-DoLd3j2e.mjs.map → schema-BfJ7bIXH.mjs.map} +1 -1
  288. package/dist/{search-BR0ZeZmh.mjs → search-C7t3PH1J.mjs} +6 -4
  289. package/dist/search-C7t3PH1J.mjs.map +1 -0
  290. package/dist/{sections-5J2YJPqJ.mjs → sections-Dm0CVX23.mjs} +3 -3
  291. package/dist/{sections-5J2YJPqJ.mjs.map → sections-Dm0CVX23.mjs.map} +1 -1
  292. package/dist/seed/index.d.mts +1 -1
  293. package/dist/seed/index.mjs +14 -14
  294. package/dist/{seo-DKeXHkzE.mjs → seo-Dd3tbY_k.mjs} +2 -2
  295. package/dist/{seo-DKeXHkzE.mjs.map → seo-Dd3tbY_k.mjs.map} +1 -1
  296. package/dist/{service-BbO2s8gT.mjs → service-CTrqp_Jy.mjs} +2 -2
  297. package/dist/{service-BbO2s8gT.mjs.map → service-CTrqp_Jy.mjs.map} +1 -1
  298. package/dist/{settings-DJeki-97.mjs → settings-BX8cWBus.mjs} +3 -3
  299. package/dist/{settings-DJeki-97.mjs.map → settings-BX8cWBus.mjs.map} +1 -1
  300. package/dist/{settings-BMNr9Dmi.mjs → settings-CZ7ZP9cW.mjs} +3 -3
  301. package/dist/{settings-BMNr9Dmi.mjs.map → settings-CZ7ZP9cW.mjs.map} +1 -1
  302. package/dist/storage/local.d.mts +1 -1
  303. package/dist/storage/s3.d.mts +1 -1
  304. package/dist/{taxonomies-CM_fUqLU.mjs → taxonomies-DChKcVxf.mjs} +4 -4
  305. package/dist/{taxonomies-CM_fUqLU.mjs.map → taxonomies-DChKcVxf.mjs.map} +1 -1
  306. package/dist/{taxonomies-D13i2ctt.mjs → taxonomies-ckPjz-6d.mjs} +5 -5
  307. package/dist/{taxonomies-D13i2ctt.mjs.map → taxonomies-ckPjz-6d.mjs.map} +1 -1
  308. package/dist/{taxonomy-BU0LjdVb.mjs → taxonomy-Cru-he6s.mjs} +3 -3
  309. package/dist/{taxonomy-BU0LjdVb.mjs.map → taxonomy-Cru-he6s.mjs.map} +1 -1
  310. package/dist/{transport-BZ-03aFT.d.mts → transport-Blrl2k_o.d.mts} +1 -1
  311. package/dist/{transport-BZ-03aFT.d.mts.map → transport-Blrl2k_o.d.mts.map} +1 -1
  312. package/dist/{types-BG8_XTLj.d.mts → types-BkZ8DUEI.d.mts} +1 -1
  313. package/dist/{types-BG8_XTLj.d.mts.map → types-BkZ8DUEI.d.mts.map} +1 -1
  314. package/dist/{types-DrYMm9s5.d.mts → types-ByChcBgE.d.mts} +1 -1
  315. package/dist/{types-DrYMm9s5.d.mts.map → types-ByChcBgE.d.mts.map} +1 -1
  316. package/dist/{types-BWqGVhFn.d.mts → types-CvuKO5Pn.d.mts} +1 -1
  317. package/dist/{types-BWqGVhFn.d.mts.map → types-CvuKO5Pn.d.mts.map} +1 -1
  318. package/dist/{types-CZgK3EMW.mjs → types-DU4TSFS5.mjs} +2 -2
  319. package/dist/{types-CZgK3EMW.mjs.map → types-DU4TSFS5.mjs.map} +1 -1
  320. package/dist/{types-CUsXGRVj.d.mts → types-Dbqff978.d.mts} +1 -1
  321. package/dist/{types-CUsXGRVj.d.mts.map → types-Dbqff978.d.mts.map} +1 -1
  322. package/dist/{types-fS7-VTdR.d.mts → types-Y09-wtyU.d.mts} +1 -1
  323. package/dist/{types-fS7-VTdR.d.mts.map → types-Y09-wtyU.d.mts.map} +1 -1
  324. package/dist/{user-DkG2jKCp.mjs → user-DgGbKL9s.mjs} +3 -3
  325. package/dist/{user-DkG2jKCp.mjs.map → user-DgGbKL9s.mjs.map} +1 -1
  326. package/dist/{validate-CG0V0wNR.d.mts → validate-9ECmtEpJ.d.mts} +9 -4
  327. package/dist/{validate-CG0V0wNR.d.mts.map → validate-9ECmtEpJ.d.mts.map} +1 -1
  328. package/dist/{validate-CuJ1Ps9j.mjs → validate-CRkcYZAR.mjs} +2 -2
  329. package/dist/{validate-CuJ1Ps9j.mjs.map → validate-CRkcYZAR.mjs.map} +1 -1
  330. package/dist/{validation-CwUfTdGF.mjs → validation-sR26SOwD.mjs} +5 -5
  331. package/dist/{validation-CwUfTdGF.mjs.map → validation-sR26SOwD.mjs.map} +1 -1
  332. package/dist/version-CrqhKGWn.mjs +7 -0
  333. package/dist/{version-BoNBItP_.mjs.map → version-CrqhKGWn.mjs.map} +1 -1
  334. package/dist/{widgets-BfOZ-ajY.mjs → widgets-DRgtn7Cl.mjs} +2 -2
  335. package/dist/{widgets-BfOZ-ajY.mjs.map → widgets-DRgtn7Cl.mjs.map} +1 -1
  336. package/dist/{zod-generator-gFsRuNNy.mjs → zod-generator-C5JaV--i.mjs} +2 -2
  337. package/dist/{zod-generator-gFsRuNNy.mjs.map → zod-generator-C5JaV--i.mjs.map} +1 -1
  338. package/package.json +8 -8
  339. package/src/api/handlers/content.ts +59 -16
  340. package/src/api/handlers/plugins.ts +77 -10
  341. package/src/astro/integration/vite-config.ts +19 -1
  342. package/src/astro/middleware/auth.ts +1 -0
  343. package/src/astro/middleware.ts +1 -0
  344. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +6 -1
  345. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +6 -1
  346. package/src/astro/routes/api/admin/plugins/[id]/index.ts +1 -0
  347. package/src/astro/routes/api/admin/plugins/index.ts +1 -0
  348. package/src/astro/routes/api/manifest.ts +20 -1
  349. package/src/astro/routes/api/setup/dev-bypass.ts +7 -2
  350. package/src/astro/types.ts +4 -0
  351. package/src/cli/commands/seed.ts +1 -1
  352. package/src/components/LiveSearch.astro +40 -4
  353. package/src/components/live-search-routing.ts +30 -0
  354. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +23 -18
  355. package/src/database/migrations/048_restore_content_taxonomies_term_index.ts +32 -0
  356. package/src/database/migrations/runner.ts +2 -0
  357. package/src/search/query.ts +3 -0
  358. package/src/search/types.ts +2 -0
  359. package/src/seed/apply.ts +2 -2
  360. package/src/seed/types.ts +6 -1
  361. package/dist/api-BMfveMoB.mjs.map +0 -1
  362. package/dist/apply--IVNSdXn.mjs.map +0 -1
  363. package/dist/index-BRNabKrx.d.mts.map +0 -1
  364. package/dist/runner-DPdt_Wpa.mjs.map +0 -1
  365. package/dist/search-BR0ZeZmh.mjs.map +0 -1
  366. package/dist/version-BoNBItP_.mjs +0 -7
@@ -5,6 +5,7 @@
5
5
  import type { Kysely } from "kysely";
6
6
 
7
7
  import type { Database } from "../../database/types.js";
8
+ import type { SandboxedPluginEntry } from "../../emdash-runtime.js";
8
9
  import { PluginStateRepository, type PluginState, type PluginStatus } from "../../plugins/state.js";
9
10
  import type { ResolvedPlugin } from "../../plugins/types.js";
10
11
  import type { ApiResult } from "../types.js";
@@ -17,6 +18,8 @@ export interface PluginInfo {
17
18
  enabled: boolean;
18
19
  status: PluginStatus;
19
20
  source?: "config" | "marketplace" | "registry";
21
+ /** True for statically-sandboxed plugins (registered via `sandboxed: []`) */
22
+ sandboxed?: boolean;
20
23
  marketplaceVersion?: string;
21
24
  /** Publisher DID, for registry-source plugins */
22
25
  registryPublisherDid?: string;
@@ -84,12 +87,43 @@ function buildPluginInfo(
84
87
  };
85
88
  }
86
89
 
90
+ /**
91
+ * Build plugin info for a statically-sandboxed plugin entry
92
+ */
93
+ function buildSandboxedPluginInfo(
94
+ entry: SandboxedPluginEntry,
95
+ state: PluginState | null,
96
+ ): PluginInfo {
97
+ const status = state?.status ?? "active";
98
+ const enabled = status === "active";
99
+
100
+ return {
101
+ id: entry.id,
102
+ name: state?.displayName || entry.id,
103
+ version: entry.version,
104
+ package: undefined, // v2 doesn't have package field
105
+ enabled,
106
+ status,
107
+ source: "config",
108
+ sandboxed: true,
109
+ capabilities: entry.capabilities,
110
+ hasAdminPages: (entry.adminPages?.length ?? 0) > 0,
111
+ hasDashboardWidgets: (entry.adminWidgets?.length ?? 0) > 0,
112
+ hasHooks: false,
113
+ installedAt: state?.installedAt?.toISOString(),
114
+ activatedAt: state?.activatedAt?.toISOString() ?? undefined,
115
+ deactivatedAt: state?.deactivatedAt?.toISOString() ?? undefined,
116
+ description: state?.description ?? undefined,
117
+ };
118
+ }
119
+
87
120
  /**
88
121
  * List all configured plugins with their state
89
122
  */
90
123
  export async function handlePluginList(
91
124
  db: Kysely<Database>,
92
125
  configuredPlugins: ResolvedPlugin[],
126
+ sandboxedPluginEntries: SandboxedPluginEntry[],
93
127
  marketplaceUrl?: string,
94
128
  ): Promise<ApiResult<PluginListResponse>> {
95
129
  try {
@@ -104,6 +138,14 @@ export async function handlePluginList(
104
138
  return buildPluginInfo(plugin, state, marketplaceUrl);
105
139
  });
106
140
 
141
+ // Include statically-sandboxed plugins (registered via `sandboxed: []`
142
+ // in astro.config.mjs).
143
+ for (const entry of sandboxedPluginEntries) {
144
+ if (configuredIds.has(entry.id)) continue;
145
+ configuredIds.add(entry.id);
146
+ items.push(buildSandboxedPluginInfo(entry, stateMap.get(entry.id) ?? null));
147
+ }
148
+
107
149
  // Include runtime-installed plugins (marketplace or registry) that
108
150
  // aren't in the configured plugins list.
109
151
  for (const state of allStates) {
@@ -156,27 +198,37 @@ export async function handlePluginList(
156
198
  export async function handlePluginGet(
157
199
  db: Kysely<Database>,
158
200
  configuredPlugins: ResolvedPlugin[],
201
+ sandboxedPluginEntries: SandboxedPluginEntry[],
159
202
  pluginId: string,
160
203
  marketplaceUrl?: string,
161
204
  ): Promise<ApiResult<PluginResponse>> {
162
205
  try {
206
+ const stateRepo = new PluginStateRepository(db);
163
207
  const plugin = configuredPlugins.find((p) => p.id === pluginId);
164
- if (!plugin) {
208
+
209
+ if (plugin) {
210
+ const state = await stateRepo.get(pluginId);
165
211
  return {
166
- success: false,
167
- error: {
168
- code: "NOT_FOUND",
169
- message: `Plugin not found: ${pluginId}`,
170
- },
212
+ success: true,
213
+ data: { item: buildPluginInfo(plugin, state, marketplaceUrl) },
171
214
  };
172
215
  }
173
216
 
174
- const stateRepo = new PluginStateRepository(db);
175
- const state = await stateRepo.get(pluginId);
217
+ const sandboxed = sandboxedPluginEntries.find((e) => e.id === pluginId);
218
+ if (sandboxed) {
219
+ const state = await stateRepo.get(pluginId);
220
+ return {
221
+ success: true,
222
+ data: { item: buildSandboxedPluginInfo(sandboxed, state) },
223
+ };
224
+ }
176
225
 
177
226
  return {
178
- success: true,
179
- data: { item: buildPluginInfo(plugin, state, marketplaceUrl) },
227
+ success: false,
228
+ error: {
229
+ code: "NOT_FOUND",
230
+ message: `Plugin not found: ${pluginId}`,
231
+ },
180
232
  };
181
233
  } catch {
182
234
  return {
@@ -227,6 +279,7 @@ function buildStateOnlyPluginInfo(
227
279
  export async function handlePluginEnable(
228
280
  db: Kysely<Database>,
229
281
  configuredPlugins: ResolvedPlugin[],
282
+ sandboxedPluginEntries: SandboxedPluginEntry[],
230
283
  pluginId: string,
231
284
  ): Promise<ApiResult<PluginResponse>> {
232
285
  try {
@@ -239,6 +292,13 @@ export async function handlePluginEnable(
239
292
  return { success: true, data: { item: buildPluginInfo(plugin, state) } };
240
293
  }
241
294
 
295
+ // Statically-sandboxed plugin: addressable via its build-time entry.
296
+ const sandboxed = sandboxedPluginEntries.find((e) => e.id === pluginId);
297
+ if (sandboxed) {
298
+ const state = await stateRepo.enable(pluginId, sandboxed.version);
299
+ return { success: true, data: { item: buildSandboxedPluginInfo(sandboxed, state) } };
300
+ }
301
+
242
302
  // Runtime-installed plugin (marketplace or registry): only
243
303
  // addressable through the state row. Fall back to the existing
244
304
  // version recorded there.
@@ -268,6 +328,7 @@ export async function handlePluginEnable(
268
328
  export async function handlePluginDisable(
269
329
  db: Kysely<Database>,
270
330
  configuredPlugins: ResolvedPlugin[],
331
+ sandboxedPluginEntries: SandboxedPluginEntry[],
271
332
  pluginId: string,
272
333
  ): Promise<ApiResult<PluginResponse>> {
273
334
  try {
@@ -279,6 +340,12 @@ export async function handlePluginDisable(
279
340
  return { success: true, data: { item: buildPluginInfo(plugin, state) } };
280
341
  }
281
342
 
343
+ const sandboxed = sandboxedPluginEntries.find((e) => e.id === pluginId);
344
+ if (sandboxed) {
345
+ const state = await stateRepo.disable(pluginId, sandboxed.version);
346
+ return { success: true, data: { item: buildSandboxedPluginInfo(sandboxed, state) } };
347
+ }
348
+
282
349
  const existing = await stateRepo.get(pluginId);
283
350
  if (!existing || (existing.source !== "marketplace" && existing.source !== "registry")) {
284
351
  return {
@@ -444,7 +444,18 @@ export function createViteConfig(
444
444
  // during pre-bundling and can't resolve them. Vite's exclude
445
445
  // uses prefix matching (id.startsWith(m + "/")), so
446
446
  // "virtual:emdash" matches all "virtual:emdash/*" imports.
447
- exclude: ["virtual:emdash"],
447
+ //
448
+ // First-party packages must also stay excluded. In a
449
+ // real install (unlike the workspace symlink, which Vite never
450
+ // optimizes), the optimizer bundles their dist and code-splits
451
+ // lazily-executed dynamic imports (MCP tools, content
452
+ // validation) into hashed chunks. A mid-session re-optimization
453
+ // deletes those chunks while loaded modules still reference
454
+ // them, so every content write fails with "The file does not
455
+ // exist at .../deps_ssr/..." until the dev server restarts.
456
+ // Their CJS deps are still pre-bundled via the "parent > dep"
457
+ // include entries below, which resolve through excluded parents.
458
+ exclude: ["virtual:emdash", "emdash", "@emdash-cms/admin", "@emdash-cms/cloudflare"],
448
459
  include: [
449
460
  // EmDash direct deps
450
461
  "emdash > @portabletext/toolkit",
@@ -455,6 +466,9 @@ export function createViteConfig(
455
466
  "emdash > jose",
456
467
  "emdash > jpeg-js",
457
468
  "emdash > kysely",
469
+ // Only imported by the migration runner, so the first
470
+ // dev-bypass/setup request would otherwise discover it.
471
+ "emdash > kysely/migration",
458
472
  "emdash > mime/lite",
459
473
  "emdash > modern-tar",
460
474
  "emdash > sanitize-html",
@@ -496,6 +510,7 @@ export function createViteConfig(
496
510
  // Top-level deps (use astro > path for pnpm compat)
497
511
  "astro > zod/v4",
498
512
  "astro > zod/v4/core",
513
+ "astro/zod",
499
514
  // zod-generator imports the bare `zod` entry, not `zod/v4`
500
515
  "emdash > zod",
501
516
  "@emdash-cms/cloudflare > kysely-d1",
@@ -507,6 +522,9 @@ export function createViteConfig(
507
522
  "astro/assets/fonts/runtime.js",
508
523
  "astro/assets/services/noop",
509
524
  "@astrojs/cloudflare/image-service",
525
+ // Only imported by the /_image route, so the first image
526
+ // request would otherwise discover it.
527
+ "@astrojs/cloudflare/image-transform-endpoint",
510
528
  ],
511
529
  },
512
530
  }
@@ -120,6 +120,7 @@ const PUBLIC_API_EXACT = new Set([
120
120
  // so unauthenticated callers only see published content. Admin endpoints
121
121
  // (/enable, /rebuild, /stats) remain private because they're not in this set.
122
122
  "/_emdash/api/search",
123
+ "/_emdash/api/search/suggest",
123
124
  ]);
124
125
 
125
126
  // Build merged public routes at module load from auth provider descriptors.
@@ -752,6 +752,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
752
752
  hooks: runtime.hooks,
753
753
  email: runtime.email,
754
754
  configuredPlugins: runtime.configuredPlugins,
755
+ sandboxedPluginEntries: runtime.sandboxedPluginEntries,
755
756
 
756
757
  // Configuration (for checking database type, auth mode, etc.)
757
758
  config,
@@ -28,7 +28,12 @@ export const POST: APIRoute = async ({ params, locals }) => {
28
28
  return apiError("INVALID_REQUEST", "Plugin ID required", 400);
29
29
  }
30
30
 
31
- const result = await handlePluginDisable(emdash.db, emdash.configuredPlugins, id);
31
+ const result = await handlePluginDisable(
32
+ emdash.db,
33
+ emdash.configuredPlugins,
34
+ emdash.sandboxedPluginEntries,
35
+ id,
36
+ );
32
37
 
33
38
  if (!result.success) return unwrapResult(result);
34
39
 
@@ -28,7 +28,12 @@ export const POST: APIRoute = async ({ params, locals }) => {
28
28
  return apiError("INVALID_REQUEST", "Plugin ID required", 400);
29
29
  }
30
30
 
31
- const result = await handlePluginEnable(emdash.db, emdash.configuredPlugins, id);
31
+ const result = await handlePluginEnable(
32
+ emdash.db,
33
+ emdash.configuredPlugins,
34
+ emdash.sandboxedPluginEntries,
35
+ id,
36
+ );
32
37
 
33
38
  if (!result.success) return unwrapResult(result);
34
39
 
@@ -30,6 +30,7 @@ export const GET: APIRoute = async ({ params, locals }) => {
30
30
  const result = await handlePluginGet(
31
31
  emdash.db,
32
32
  emdash.configuredPlugins,
33
+ emdash.sandboxedPluginEntries,
33
34
  id,
34
35
  emdash.config.marketplace,
35
36
  );
@@ -25,6 +25,7 @@ export const GET: APIRoute = async ({ locals }) => {
25
25
  const result = await handlePluginList(
26
26
  emdash.db,
27
27
  emdash.configuredPlugins,
28
+ emdash.sandboxedPluginEntries,
28
29
  emdash.config.marketplace,
29
30
  );
30
31
 
@@ -11,6 +11,7 @@ import type { APIRoute } from "astro";
11
11
 
12
12
  import { handleError } from "#api/error.js";
13
13
  import { getAuthMode } from "#auth/mode.js";
14
+ import { OptionsRepository } from "#db/repositories/options.js";
14
15
 
15
16
  import { COMMIT, VERSION } from "../../../version.js";
16
17
  import type { EmDashManifest } from "../../types.js";
@@ -39,7 +40,25 @@ export const GET: APIRoute = async ({ locals }) => {
39
40
  // doesn't assign it to globalThis, so getStoredConfig() always returned
40
41
  // null and the React SPA never received custom logo/siteName/favicon.
41
42
  // See issue #835.
42
- const adminBranding = emdash?.config?.admin;
43
+ let adminBranding = emdash?.config?.admin;
44
+
45
+ // When no build-time `admin.siteName` is configured, brand the admin with
46
+ // the site's own title so multi-site operators can tell backends apart
47
+ // (WordPress-style: wp-admin always shows the site name). Precedence:
48
+ // explicit `admin.siteName` → Site Title (Settings → General) → the title
49
+ // captured by the setup wizard → the bundled "EmDash" default in the SPA.
50
+ if (!adminBranding?.siteName && emdash?.db) {
51
+ try {
52
+ const options = new OptionsRepository(emdash.db);
53
+ const titles = await options.getMany<string>(["site:title", "emdash:site_title"]);
54
+ const siteTitle = titles.get("site:title") || titles.get("emdash:site_title");
55
+ if (siteTitle) {
56
+ adminBranding = { ...adminBranding, siteName: siteTitle };
57
+ }
58
+ } catch {
59
+ // options table may not exist yet (pre-setup) — keep the default.
60
+ }
61
+ }
43
62
 
44
63
  // Check if self-signup is enabled (any allowed domain with enabled = 1)
45
64
  // Only relevant for passkey auth — external auth providers handle their own signup
@@ -10,6 +10,8 @@
10
10
  * Usage:
11
11
  * - GET with redirect: /_emdash/api/setup/dev-bypass?redirect=/_emdash/admin
12
12
  * - POST for API: Returns JSON with setup info
13
+ * - ?content=0 (or ?content=false): apply schema/structure only, skipping
14
+ * sample content entries, bylines, and taxonomy terms
13
15
  *
14
16
  * For agent/browser testing, navigate to:
15
17
  * /_emdash/api/setup/dev-bypass?redirect=/_emdash/admin
@@ -57,12 +59,15 @@ async function handleDevBypass(context: Parameters<APIRoute>[0]): Promise<Respon
57
59
  const migrations = await runMigrations(emdash.db);
58
60
  console.log("[setup-dev-bypass] Migrations applied:", migrations.applied);
59
61
 
60
- // Apply seed (user seed or built-in default)
62
+ // Apply seed (user seed or built-in default). `?content=0` (or `false`)
63
+ // applies schema/structure only — no sample content, bylines, or terms.
64
+ const contentParam = url.searchParams.get("content");
65
+ const includeContent = contentParam !== "0" && contentParam !== "false";
61
66
  const seed = await loadSeed();
62
67
  const validation = validateSeed(seed);
63
68
  if (validation.valid) {
64
69
  const seedResult = await applySeed(emdash.db, seed, {
65
- includeContent: true,
70
+ includeContent,
66
71
  onConflict: "skip",
67
72
  storage: emdash.storage ?? undefined,
68
73
  });
@@ -434,6 +434,10 @@ export interface EmDashHandlers {
434
434
  // Configured plugins (for plugin management)
435
435
  configuredPlugins: import("../plugins/types.js").ResolvedPlugin[];
436
436
 
437
+ // Statically-sandboxed plugin entries (registered via `sandboxed: []`),
438
+ // surfaced through the admin plugin management API alongside configured plugins.
439
+ sandboxedPluginEntries: import("../emdash-runtime.js").SandboxedPluginEntry[];
440
+
437
441
  // Configuration (for checking database type, auth mode, etc.)
438
442
  config: import("./integration/runtime.js").EmDashConfig;
439
443
 
@@ -108,7 +108,7 @@ export const seedCommand = defineCommand({
108
108
  },
109
109
  "no-content": {
110
110
  type: "boolean",
111
- description: "Skip sample content",
111
+ description: "Skip sample data (content entries, bylines, taxonomy terms)",
112
112
  default: false,
113
113
  },
114
114
  "on-conflict": {
@@ -34,6 +34,8 @@ export interface Props {
34
34
  limit?: number;
35
35
  /** CSS class for the container */
36
36
  class?: string;
37
+ /** Inline style for the container */
38
+ style?: string;
37
39
  /** CSS class for the input */
38
40
  inputClass?: string;
39
41
  /** CSS class for the results container */
@@ -48,6 +50,10 @@ export interface Props {
48
50
  suggestMode?: boolean;
49
51
  /** Expand input width on focus (provide collapsed and expanded widths) */
50
52
  expandOnFocus?: { collapsed: string; expanded: string };
53
+ /** Search results page to navigate to when pressing Enter without a focused result */
54
+ searchPage?: string;
55
+ /** Per-collection URL templates, e.g. { posts: "/blog/:path" } */
56
+ routeMap?: Record<string, string>;
51
57
  }
52
58
 
53
59
  const {
@@ -57,6 +63,7 @@ const {
57
63
  debounce = 300,
58
64
  limit = 10,
59
65
  class: className = "",
66
+ style: styleAttr = "",
60
67
  inputClass = "",
61
68
  resultsClass = "",
62
69
  resultClass = "",
@@ -64,6 +71,8 @@ const {
64
71
  autofocus = false,
65
72
  suggestMode = false,
66
73
  expandOnFocus,
74
+ searchPage = "",
75
+ routeMap = {},
67
76
  } = Astro.props;
68
77
 
69
78
  const config = {
@@ -74,11 +83,14 @@ const config = {
74
83
  showSnippets,
75
84
  suggestMode,
76
85
  expandOnFocus: expandOnFocus ?? null,
86
+ searchPage,
87
+ routeMap,
77
88
  };
78
89
  ---
79
90
 
80
91
  <emdash-live-search
81
92
  class:list={["emdash-live-search", className]}
93
+ style={styleAttr}
82
94
  data-config={JSON.stringify(config)}
83
95
  >
84
96
  <input
@@ -109,6 +121,12 @@ const config = {
109
121
  </emdash-live-search>
110
122
 
111
123
  <script>
124
+ import {
125
+ buildLiveSearchResultUrl,
126
+ type LiveSearchRouteMap,
127
+ type LiveSearchRoutableResult,
128
+ } from "./live-search-routing.js";
129
+
112
130
  interface SearchResult {
113
131
  collection: string;
114
132
  id: string;
@@ -121,6 +139,7 @@ const config = {
121
139
  interface Suggestion {
122
140
  collection: string;
123
141
  id: string;
142
+ slug?: string | null;
124
143
  title: string;
125
144
  }
126
145
 
@@ -132,6 +151,8 @@ const config = {
132
151
  showSnippets: boolean;
133
152
  suggestMode: boolean;
134
153
  expandOnFocus: { collapsed: string; expanded: string } | null;
154
+ searchPage: string;
155
+ routeMap: LiveSearchRouteMap;
135
156
  }
136
157
 
137
158
  class EmDashLiveSearch extends HTMLElement {
@@ -149,6 +170,8 @@ const config = {
149
170
  showSnippets: true,
150
171
  suggestMode: false,
151
172
  expandOnFocus: null,
173
+ searchPage: "",
174
+ routeMap: {},
152
175
  };
153
176
  private debounceTimer: ReturnType<typeof setTimeout> | null = null;
154
177
  private abortController: AbortController | null = null;
@@ -268,11 +291,25 @@ const config = {
268
291
  ".emdash-live-search-result:focus, .emdash-live-search-result.focused"
269
292
  ) as HTMLAnchorElement | null;
270
293
  if (focused?.href) {
294
+ e.preventDefault();
271
295
  window.location.href = focused.href;
296
+ return;
297
+ }
298
+
299
+ const query = this.input?.value.trim();
300
+ if (query && this.config.searchPage) {
301
+ e.preventDefault();
302
+ const url = new URL(this.config.searchPage, window.location.origin);
303
+ url.searchParams.set("q", query);
304
+ window.location.href = url.toString();
272
305
  }
273
306
  }
274
307
  }
275
308
 
309
+ private buildResultUrl(result: LiveSearchRoutableResult): string {
310
+ return buildLiveSearchResultUrl(result, this.config.routeMap);
311
+ }
312
+
276
313
  private navigateResults(direction: number) {
277
314
  if (!this.resultsList) return;
278
315
 
@@ -369,9 +406,7 @@ const config = {
369
406
  const link = clone.querySelector("a");
370
407
 
371
408
  if (link) {
372
- // Build URL - use slug if available, otherwise id
373
- const path = result.slug ?? result.id;
374
- link.href = `/${result.collection}/${path}`;
409
+ link.href = this.buildResultUrl(result);
375
410
 
376
411
  // Fill in title
377
412
  const titleEl = link.querySelector(
@@ -430,7 +465,7 @@ const config = {
430
465
  const link = clone.querySelector("a");
431
466
 
432
467
  if (link) {
433
- link.href = `/${suggestion.collection}/${suggestion.id}`;
468
+ link.href = this.buildResultUrl(suggestion);
434
469
 
435
470
  const titleEl = link.querySelector(
436
471
  ".emdash-live-search-result-title"
@@ -456,6 +491,7 @@ const config = {
456
491
 
457
492
  link.dataset.id = suggestion.id;
458
493
  link.dataset.collection = suggestion.collection;
494
+ link.dataset.slug = suggestion.slug ?? "";
459
495
  }
460
496
 
461
497
  this.resultsList.appendChild(clone);
@@ -0,0 +1,30 @@
1
+ export interface LiveSearchRoutableResult {
2
+ collection: string;
3
+ id: string;
4
+ slug?: string | null;
5
+ }
6
+
7
+ export type LiveSearchRouteMap = Record<string, string>;
8
+
9
+ function replaceRouteToken(template: string, token: string, value: string): string {
10
+ return template.split(token).join(value);
11
+ }
12
+
13
+ export function buildLiveSearchResultUrl(
14
+ result: LiveSearchRoutableResult,
15
+ routeMap: LiveSearchRouteMap = {},
16
+ ): string {
17
+ const path = result.slug ?? result.id;
18
+ const template = routeMap[result.collection];
19
+
20
+ if (!template) {
21
+ return `/${result.collection}/${path}`;
22
+ }
23
+
24
+ return [
25
+ [":collection", result.collection],
26
+ [":id", result.id],
27
+ [":slug", result.slug ?? result.id],
28
+ [":path", path],
29
+ ].reduce((url, [token, value]) => replaceRouteToken(url, token, value), template);
30
+ }
@@ -259,27 +259,32 @@ async function rebuildContentTaxonomies(db: Kysely<unknown>): Promise<void> {
259
259
  // is load-bearing — if the translation_group seed ever changes, this needs
260
260
  // an explicit remap *after* `rebuildTaxonomies` runs.
261
261
  const fks = await sql<{ id: number }>`PRAGMA foreign_key_list(content_taxonomies)`.execute(db);
262
- if (fks.rows.length === 0) return;
262
+ if (fks.rows.length > 0) {
263
+ await sql.raw(`DROP TABLE IF EXISTS "content_taxonomies_new"`).execute(db);
264
+ await db.schema
265
+ .createTable("content_taxonomies_new")
266
+ .addColumn("collection", "text", (c) => c.notNull())
267
+ .addColumn("entry_id", "text", (c) => c.notNull())
268
+ .addColumn("taxonomy_id", "text", (c) => c.notNull())
269
+ .addPrimaryKeyConstraint("content_taxonomies_pk", ["collection", "entry_id", "taxonomy_id"])
270
+ .execute();
263
271
 
264
- await sql.raw(`DROP TABLE IF EXISTS "content_taxonomies_new"`).execute(db);
265
- await db.schema
266
- .createTable("content_taxonomies_new")
267
- .addColumn("collection", "text", (c) => c.notNull())
268
- .addColumn("entry_id", "text", (c) => c.notNull())
269
- .addColumn("taxonomy_id", "text", (c) => c.notNull())
270
- .addPrimaryKeyConstraint("content_taxonomies_pk", ["collection", "entry_id", "taxonomy_id"])
271
- .execute();
272
-
273
- await sql`
274
- INSERT OR IGNORE INTO content_taxonomies_new (collection, entry_id, taxonomy_id)
275
- SELECT collection, entry_id, taxonomy_id FROM content_taxonomies
276
- `.execute(db);
272
+ await sql`
273
+ INSERT OR IGNORE INTO content_taxonomies_new (collection, entry_id, taxonomy_id)
274
+ SELECT collection, entry_id, taxonomy_id FROM content_taxonomies
275
+ `.execute(db);
277
276
 
278
- await db.schema.dropTable("content_taxonomies").execute();
279
- await sql`ALTER TABLE content_taxonomies_new RENAME TO content_taxonomies`.execute(db);
277
+ await db.schema.dropTable("content_taxonomies").execute();
278
+ await sql`ALTER TABLE content_taxonomies_new RENAME TO content_taxonomies`.execute(db);
279
+ }
280
280
 
281
- // SQLite drops indexes when the underlying table is dropped. Restore the
282
- // taxonomy_id index from migration 015.
281
+ // Recreate the taxonomy_id index from migration 015 unconditionally, OUTSIDE
282
+ // the FK-presence guard above. The rebuild both strips the FK and drops the
283
+ // old table's indexes, but D1 auto-commits each DDL statement — so a first
284
+ // run that failed after the drop leaves the table with no FK and no index.
285
+ // The retry then finds zero FKs and skips the rebuild; if the index recreate
286
+ // lived inside that guard it would never run and the index would be lost for
287
+ // good (#1701). `IF NOT EXISTS` keeps this a no-op once present.
283
288
  await sql`CREATE INDEX IF NOT EXISTS idx_content_taxonomies_term ON content_taxonomies(taxonomy_id)`.execute(
284
289
  db,
285
290
  );
@@ -0,0 +1,32 @@
1
+ import type { Kysely } from "kysely";
2
+
3
+ /**
4
+ * Restore `idx_content_taxonomies_term` on `content_taxonomies(taxonomy_id)` (#1701).
5
+ *
6
+ * Migration 015 created this index. 036's SQLite/D1 table rebuild recreated it,
7
+ * but the recreate was gated behind an FK-presence early-return: if a first run
8
+ * committed the rebuild (stripping the FK and dropping the old index) and then
9
+ * failed before the recreate, the retry saw zero FKs, skipped the whole body,
10
+ * and never restored the index — while 036 was still recorded as applied. The
11
+ * result was an install missing only this one index, with no forward migration
12
+ * to recover it (the sibling `idx_taxonomies_parent` case was fixed by 047).
13
+ *
14
+ * 036 has since been fixed to recreate the index unconditionally, so fresh
15
+ * installs are fine. This recovers the index on installs that hit the trap
16
+ * before that fix. The Postgres path in 036 alters in place and keeps its
17
+ * indexes, so it is unaffected; `ifNotExists` makes this a no-op there.
18
+ *
19
+ * Forward-only.
20
+ */
21
+ export async function up(db: Kysely<unknown>): Promise<void> {
22
+ await db.schema
23
+ .createIndex("idx_content_taxonomies_term")
24
+ .ifNotExists()
25
+ .on("content_taxonomies")
26
+ .column("taxonomy_id")
27
+ .execute();
28
+ }
29
+
30
+ export async function down(db: Kysely<unknown>): Promise<void> {
31
+ await db.schema.dropIndex("idx_content_taxonomies_term").ifExists().execute();
32
+ }
@@ -49,6 +49,7 @@ import * as m044 from "./044_comment_reactions.js";
49
49
  import * as m045 from "./045_taxonomy_parent_group.js";
50
50
  import * as m046 from "./046_media_usage_index.js";
51
51
  import * as m047 from "./047_restore_taxonomy_parent_index.js";
52
+ import * as m048 from "./048_restore_content_taxonomies_term_index.js";
52
53
 
53
54
  const MIGRATIONS: Readonly<Record<string, Migration>> = Object.freeze({
54
55
  "001_initial": m001,
@@ -97,6 +98,7 @@ const MIGRATIONS: Readonly<Record<string, Migration>> = Object.freeze({
97
98
  "045_taxonomy_parent_group": m045,
98
99
  "046_media_usage_index": m046,
99
100
  "047_restore_taxonomy_parent_index": m047,
101
+ "048_restore_content_taxonomies_term_index": m048,
100
102
  });
101
103
 
102
104
  /** Total number of registered migrations. Exported for use in tests. */
@@ -359,10 +359,12 @@ export async function getSuggestions(
359
359
  try {
360
360
  results = await sql<{
361
361
  id: string;
362
+ slug: string | null;
362
363
  title: string;
363
364
  }>`
364
365
  SELECT
365
366
  c.id,
367
+ c.slug,
366
368
  c.title
367
369
  FROM "${sql.raw(ftsTable)}" f
368
370
  JOIN "${sql.raw(contentTable)}" c ON f.id = c.id
@@ -389,6 +391,7 @@ export async function getSuggestions(
389
391
  suggestions.push({
390
392
  collection,
391
393
  id: row.id,
394
+ slug: row.slug,
392
395
  title: row.title,
393
396
  });
394
397
  }
@@ -101,6 +101,8 @@ export interface Suggestion {
101
101
  collection: string;
102
102
  /** Entry ID */
103
103
  id: string;
104
+ /** Entry slug, when available */
105
+ slug?: string | null;
104
106
  /** Entry title */
105
107
  title: string;
106
108
  }