emdash 0.6.0 → 1.0.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 (263) hide show
  1. package/dist/{adapters-Di31kZ28.d.mts → adapters-BKSf3T9R.d.mts} +1 -1
  2. package/dist/{adapters-Di31kZ28.d.mts.map → adapters-BKSf3T9R.d.mts.map} +1 -1
  3. package/dist/{apply-B4MsLM-w.mjs → apply-x0eMK1lX.mjs} +186 -28
  4. package/dist/apply-x0eMK1lX.mjs.map +1 -0
  5. package/dist/astro/index.d.mts +6 -6
  6. package/dist/astro/index.d.mts.map +1 -1
  7. package/dist/astro/index.mjs +92 -17
  8. package/dist/astro/index.mjs.map +1 -1
  9. package/dist/astro/middleware/auth.d.mts +5 -5
  10. package/dist/astro/middleware/auth.d.mts.map +1 -1
  11. package/dist/astro/middleware/auth.mjs +22 -2
  12. package/dist/astro/middleware/auth.mjs.map +1 -1
  13. package/dist/astro/middleware/redirect.mjs +2 -2
  14. package/dist/astro/middleware/request-context.mjs +7 -2
  15. package/dist/astro/middleware/request-context.mjs.map +1 -1
  16. package/dist/astro/middleware/setup.mjs +1 -1
  17. package/dist/astro/middleware.d.mts.map +1 -1
  18. package/dist/astro/middleware.mjs +263 -74
  19. package/dist/astro/middleware.mjs.map +1 -1
  20. package/dist/astro/types.d.mts +25 -8
  21. package/dist/astro/types.d.mts.map +1 -1
  22. package/dist/{byline-C4OVd8b3.mjs → byline-Chbr2GoP.mjs} +3 -3
  23. package/dist/byline-Chbr2GoP.mjs.map +1 -0
  24. package/dist/{bylines-hPTW79hw.mjs → bylines-CRNsVG88.mjs} +4 -4
  25. package/dist/{bylines-hPTW79hw.mjs.map → bylines-CRNsVG88.mjs.map} +1 -1
  26. package/dist/cli/index.mjs +17 -13
  27. package/dist/cli/index.mjs.map +1 -1
  28. package/dist/client/cf-access.d.mts +1 -1
  29. package/dist/client/index.d.mts +1 -1
  30. package/dist/client/index.mjs +1 -1
  31. package/dist/{content-BsBoyj8G.mjs → content-BcQPYxdV.mjs} +39 -15
  32. package/dist/content-BcQPYxdV.mjs.map +1 -0
  33. package/dist/db/index.d.mts +3 -3
  34. package/dist/db/index.mjs +1 -1
  35. package/dist/db/libsql.d.mts +1 -1
  36. package/dist/db/postgres.d.mts +1 -1
  37. package/dist/db/sqlite.d.mts +1 -1
  38. package/dist/{db-errors-D0UT85nC.mjs → db-errors-l1Qh2RPR.mjs} +1 -1
  39. package/dist/{db-errors-D0UT85nC.mjs.map → db-errors-l1Qh2RPR.mjs.map} +1 -1
  40. package/dist/{default-CME5YdZ3.mjs → default-DCVqE5ib.mjs} +1 -1
  41. package/dist/{default-CME5YdZ3.mjs.map → default-DCVqE5ib.mjs.map} +1 -1
  42. package/dist/{error-CiYn9yDu.mjs → error-zG5T1UGA.mjs} +1 -1
  43. package/dist/error-zG5T1UGA.mjs.map +1 -0
  44. package/dist/{index-BYv0mB9g.d.mts → index-DIb-CzNx.d.mts} +232 -15
  45. package/dist/index-DIb-CzNx.d.mts.map +1 -0
  46. package/dist/index.d.mts +11 -11
  47. package/dist/index.mjs +23 -21
  48. package/dist/{load-CBcmDIot.mjs → load-CyEoextb.mjs} +1 -1
  49. package/dist/{load-CBcmDIot.mjs.map → load-CyEoextb.mjs.map} +1 -1
  50. package/dist/{loader-DeiBJEMe.mjs → loader-CndGj8kM.mjs} +8 -6
  51. package/dist/loader-CndGj8kM.mjs.map +1 -0
  52. package/dist/{manifest-schema-V30qsMft.mjs → manifest-schema-DH9xhc6t.mjs} +13 -1
  53. package/dist/manifest-schema-DH9xhc6t.mjs.map +1 -0
  54. package/dist/media/index.d.mts +1 -1
  55. package/dist/media/local-runtime.d.mts +7 -7
  56. package/dist/media/local-runtime.mjs +2 -2
  57. package/dist/{media-DqHVh136.mjs → media-D8FbNsl0.mjs} +4 -7
  58. package/dist/media-D8FbNsl0.mjs.map +1 -0
  59. package/dist/{mode-CpNnGkPz.mjs → mode-BnAOqItE.mjs} +1 -1
  60. package/dist/mode-BnAOqItE.mjs.map +1 -0
  61. package/dist/page/index.d.mts +2 -2
  62. package/dist/placeholder-C-fk5hYI.mjs.map +1 -1
  63. package/dist/{placeholder-tzpqGWII.d.mts → placeholder-D29tWZ7o.d.mts} +1 -1
  64. package/dist/{placeholder-tzpqGWII.d.mts.map → placeholder-D29tWZ7o.d.mts.map} +1 -1
  65. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  66. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  67. package/dist/{query-Bk_3vKvU.mjs → query-fqEdLFms.mjs} +9 -9
  68. package/dist/{query-Bk_3vKvU.mjs.map → query-fqEdLFms.mjs.map} +1 -1
  69. package/dist/{redirect-7lGhLBNZ.mjs → redirect-D_pshWdf.mjs} +69 -13
  70. package/dist/redirect-D_pshWdf.mjs.map +1 -0
  71. package/dist/{registry-Ci3WxVAr.mjs → registry-C3Mr0ODu.mjs} +33 -9
  72. package/dist/registry-C3Mr0ODu.mjs.map +1 -0
  73. package/dist/{request-cache-DiR961CV.mjs → request-cache-Ci7f5pBb.mjs} +1 -1
  74. package/dist/request-cache-Ci7f5pBb.mjs.map +1 -0
  75. package/dist/{runner-Fl2NcUUz.d.mts → runner-OURCaApa.d.mts} +2 -2
  76. package/dist/{runner-Fl2NcUUz.d.mts.map → runner-OURCaApa.d.mts.map} +1 -1
  77. package/dist/{runner-Cd-_WyDo.mjs → runner-tQ7BJ4T7.mjs} +211 -134
  78. package/dist/runner-tQ7BJ4T7.mjs.map +1 -0
  79. package/dist/runtime.d.mts +6 -6
  80. package/dist/runtime.mjs +2 -2
  81. package/dist/{search-DI4bM2w9.mjs → search-BoZYFuUk.mjs} +339 -102
  82. package/dist/search-BoZYFuUk.mjs.map +1 -0
  83. package/dist/seed/index.d.mts +2 -2
  84. package/dist/seed/index.mjs +12 -12
  85. package/dist/seo/index.d.mts +1 -1
  86. package/dist/storage/local.d.mts +1 -1
  87. package/dist/storage/local.mjs +1 -1
  88. package/dist/storage/s3.d.mts +1 -1
  89. package/dist/storage/s3.d.mts.map +1 -1
  90. package/dist/storage/s3.mjs +4 -4
  91. package/dist/storage/s3.mjs.map +1 -1
  92. package/dist/{taxonomies-DbrKzDju.mjs → taxonomies-B4IAshV8.mjs} +5 -5
  93. package/dist/{taxonomies-DbrKzDju.mjs.map → taxonomies-B4IAshV8.mjs.map} +1 -1
  94. package/dist/{tokens-BFPFx3CA.mjs → tokens-D9vnZqYS.mjs} +1 -1
  95. package/dist/{tokens-BFPFx3CA.mjs.map → tokens-D9vnZqYS.mjs.map} +1 -1
  96. package/dist/{transport-BykRfpyy.mjs → transport-C9ugt2Nr.mjs} +1 -1
  97. package/dist/{transport-BykRfpyy.mjs.map → transport-C9ugt2Nr.mjs.map} +1 -1
  98. package/dist/{transport-H4Iwx7tC.d.mts → transport-CUnEL3Vs.d.mts} +1 -1
  99. package/dist/{transport-H4Iwx7tC.d.mts.map → transport-CUnEL3Vs.d.mts.map} +1 -1
  100. package/dist/types-BIgulNsW.mjs +68 -0
  101. package/dist/types-BIgulNsW.mjs.map +1 -0
  102. package/dist/{types-DDS4MxsT.mjs → types-Bm1dn-q3.mjs} +1 -1
  103. package/dist/{types-DDS4MxsT.mjs.map → types-Bm1dn-q3.mjs.map} +1 -1
  104. package/dist/{types-CnZYHyLW.d.mts → types-BmPPSUEx.d.mts} +1 -1
  105. package/dist/{types-CnZYHyLW.d.mts.map → types-BmPPSUEx.d.mts.map} +1 -1
  106. package/dist/{types-6CUZRrZP.d.mts → types-BrA0xf5I.d.mts} +24 -2
  107. package/dist/{types-6CUZRrZP.d.mts.map → types-BrA0xf5I.d.mts.map} +1 -1
  108. package/dist/{types-8xrvl_68.d.mts → types-CS8FIX7L.d.mts} +10 -1
  109. package/dist/{types-8xrvl_68.d.mts.map → types-CS8FIX7L.d.mts.map} +1 -1
  110. package/dist/{types-BH2L167P.mjs → types-CgqmmMJB.mjs} +1 -1
  111. package/dist/{types-BH2L167P.mjs.map → types-CgqmmMJB.mjs.map} +1 -1
  112. package/dist/{types-CFWjXmus.d.mts → types-DIMwPFub.d.mts} +1 -1
  113. package/dist/{types-CFWjXmus.d.mts.map → types-DIMwPFub.d.mts.map} +1 -1
  114. package/dist/{types-DgrIP0tF.d.mts → types-i36XcA_X.d.mts} +49 -6
  115. package/dist/types-i36XcA_X.d.mts.map +1 -0
  116. package/dist/{validate-CqsNItbt.mjs → validate-CxVsLehf.mjs} +2 -2
  117. package/dist/{validate-CqsNItbt.mjs.map → validate-CxVsLehf.mjs.map} +1 -1
  118. package/dist/{validate-CaLH1Ia2.d.mts → validate-DHxmpFJt.d.mts} +4 -4
  119. package/dist/{validate-CaLH1Ia2.d.mts.map → validate-DHxmpFJt.d.mts.map} +1 -1
  120. package/dist/validation-C-ZpN2GI.mjs +144 -0
  121. package/dist/validation-C-ZpN2GI.mjs.map +1 -0
  122. package/dist/version-DJrV1K0M.mjs +7 -0
  123. package/dist/{version-Uaf2ynPX.mjs.map → version-DJrV1K0M.mjs.map} +1 -1
  124. package/dist/zod-generator-CpwccCIv.mjs +132 -0
  125. package/dist/zod-generator-CpwccCIv.mjs.map +1 -0
  126. package/package.json +19 -6
  127. package/src/api/auth-storage.ts +37 -0
  128. package/src/api/error.ts +6 -0
  129. package/src/api/errors.ts +8 -0
  130. package/src/api/handlers/comments.ts +13 -0
  131. package/src/api/handlers/content.ts +124 -3
  132. package/src/api/handlers/index.ts +2 -0
  133. package/src/api/handlers/media.ts +8 -1
  134. package/src/api/handlers/menus.ts +160 -21
  135. package/src/api/handlers/redirects.ts +16 -3
  136. package/src/api/handlers/sections.ts +8 -1
  137. package/src/api/handlers/taxonomies.ts +128 -16
  138. package/src/api/handlers/validation.ts +212 -0
  139. package/src/api/openapi/document.ts +4 -1
  140. package/src/api/public-url.ts +6 -3
  141. package/src/api/route-utils.ts +14 -0
  142. package/src/api/schemas/common.ts +1 -1
  143. package/src/api/schemas/content.ts +8 -0
  144. package/src/api/schemas/setup.ts +8 -0
  145. package/src/api/schemas/widgets.ts +12 -10
  146. package/src/api/setup-complete.ts +40 -0
  147. package/src/astro/integration/font-provider.ts +3 -1
  148. package/src/astro/integration/index.ts +15 -2
  149. package/src/astro/integration/routes.ts +28 -0
  150. package/src/astro/integration/runtime.ts +74 -2
  151. package/src/astro/integration/virtual-modules.ts +41 -0
  152. package/src/astro/integration/vite-config.ts +43 -12
  153. package/src/astro/middleware/auth.ts +21 -0
  154. package/src/astro/middleware.ts +18 -1
  155. package/src/astro/routes/PluginRegistry.tsx +10 -1
  156. package/src/astro/routes/admin.astro +14 -7
  157. package/src/astro/routes/api/auth/magic-link/send.ts +2 -1
  158. package/src/astro/routes/api/auth/mode.ts +57 -0
  159. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +23 -3
  160. package/src/astro/routes/api/auth/oauth/[provider].ts +10 -4
  161. package/src/astro/routes/api/auth/passkey/options.ts +2 -1
  162. package/src/astro/routes/api/auth/signup/request.ts +26 -8
  163. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +10 -6
  164. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +1 -1
  165. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +1 -1
  166. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +1 -1
  167. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +26 -0
  168. package/src/astro/routes/api/content/[collection]/[id].ts +30 -2
  169. package/src/astro/routes/api/content/[collection]/index.ts +20 -10
  170. package/src/astro/routes/api/content/[collection]/trash.ts +1 -1
  171. package/src/astro/routes/api/import/wordpress/media.ts +2 -7
  172. package/src/astro/routes/api/import/wordpress/prepare.ts +10 -0
  173. package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +4 -3
  174. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +4 -3
  175. package/src/astro/routes/api/manifest.ts +7 -0
  176. package/src/astro/routes/api/oauth/device/code.ts +2 -1
  177. package/src/astro/routes/api/oauth/device/token.ts +2 -1
  178. package/src/astro/routes/api/settings/email.ts +4 -9
  179. package/src/astro/routes/api/setup/admin-verify.ts +30 -5
  180. package/src/astro/routes/api/setup/admin.ts +38 -8
  181. package/src/astro/routes/api/setup/index.ts +7 -4
  182. package/src/astro/routes/api/setup/status.ts +3 -1
  183. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +4 -1
  184. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +4 -1
  185. package/src/astro/routes/api/widget-areas/[name].ts +4 -1
  186. package/src/astro/routes/api/widget-areas/index.ts +4 -1
  187. package/src/astro/types.ts +18 -0
  188. package/src/auth/mode.ts +15 -3
  189. package/src/auth/providers/github-admin.tsx +29 -0
  190. package/src/auth/providers/github.ts +31 -0
  191. package/src/auth/providers/google-admin.tsx +44 -0
  192. package/src/auth/providers/google.ts +31 -0
  193. package/src/auth/rate-limit.ts +50 -22
  194. package/src/auth/setup-nonce.ts +22 -0
  195. package/src/auth/trusted-proxy.ts +92 -0
  196. package/src/auth/types.ts +114 -4
  197. package/src/cli/commands/bundle.ts +3 -1
  198. package/src/components/EmDashImage.astro +7 -6
  199. package/src/components/Gallery.astro +5 -3
  200. package/src/components/Image.astro +8 -3
  201. package/src/components/InlinePortableTextEditor.tsx +2 -1
  202. package/src/components/LiveSearch.astro +5 -14
  203. package/src/database/migrations/035_bounded_404_log.ts +112 -0
  204. package/src/database/migrations/runner.ts +2 -0
  205. package/src/database/repositories/audit.ts +6 -8
  206. package/src/database/repositories/byline.ts +6 -8
  207. package/src/database/repositories/comment.ts +12 -16
  208. package/src/database/repositories/content.ts +79 -40
  209. package/src/database/repositories/index.ts +1 -1
  210. package/src/database/repositories/media.ts +10 -13
  211. package/src/database/repositories/options.ts +25 -0
  212. package/src/database/repositories/plugin-storage.ts +4 -6
  213. package/src/database/repositories/redirect.ts +123 -24
  214. package/src/database/repositories/taxonomy.ts +14 -3
  215. package/src/database/repositories/types.ts +57 -8
  216. package/src/database/repositories/user.ts +6 -8
  217. package/src/database/types.ts +9 -0
  218. package/src/emdash-runtime.ts +309 -91
  219. package/src/import/registry.ts +4 -3
  220. package/src/import/ssrf.ts +253 -12
  221. package/src/index.ts +5 -1
  222. package/src/loader.ts +6 -5
  223. package/src/mcp/server.ts +753 -107
  224. package/src/media/normalize.ts +1 -1
  225. package/src/media/url.ts +78 -0
  226. package/src/plugins/context.ts +15 -3
  227. package/src/plugins/email-console.ts +10 -3
  228. package/src/plugins/hooks.ts +11 -0
  229. package/src/plugins/manager.ts +6 -0
  230. package/src/plugins/manifest-schema.ts +12 -0
  231. package/src/plugins/request-meta.ts +66 -15
  232. package/src/plugins/routes.ts +3 -1
  233. package/src/plugins/types.ts +23 -2
  234. package/src/query.ts +1 -1
  235. package/src/request-cache.ts +3 -0
  236. package/src/schema/registry.ts +41 -5
  237. package/src/search/fts-manager.ts +0 -2
  238. package/src/search/query.ts +111 -26
  239. package/src/search/types.ts +8 -1
  240. package/src/sections/index.ts +7 -9
  241. package/src/seed/apply.ts +26 -0
  242. package/src/storage/s3.ts +12 -6
  243. package/src/virtual-modules.d.ts +21 -1
  244. package/src/visual-editing/toolbar.ts +6 -1
  245. package/src/widgets/index.ts +1 -1
  246. package/dist/apply-B4MsLM-w.mjs.map +0 -1
  247. package/dist/byline-C4OVd8b3.mjs.map +0 -1
  248. package/dist/content-BsBoyj8G.mjs.map +0 -1
  249. package/dist/error-CiYn9yDu.mjs.map +0 -1
  250. package/dist/index-BYv0mB9g.d.mts.map +0 -1
  251. package/dist/loader-DeiBJEMe.mjs.map +0 -1
  252. package/dist/manifest-schema-V30qsMft.mjs.map +0 -1
  253. package/dist/media-DqHVh136.mjs.map +0 -1
  254. package/dist/mode-CpNnGkPz.mjs.map +0 -1
  255. package/dist/redirect-7lGhLBNZ.mjs.map +0 -1
  256. package/dist/registry-Ci3WxVAr.mjs.map +0 -1
  257. package/dist/request-cache-DiR961CV.mjs.map +0 -1
  258. package/dist/runner-Cd-_WyDo.mjs.map +0 -1
  259. package/dist/search-DI4bM2w9.mjs.map +0 -1
  260. package/dist/types-CMMN0pNg.mjs +0 -31
  261. package/dist/types-CMMN0pNg.mjs.map +0 -1
  262. package/dist/types-DgrIP0tF.d.mts.map +0 -1
  263. package/dist/version-Uaf2ynPX.mjs +0 -7
@@ -3,29 +3,31 @@ import { createRecorder, flushRecorder, isInstrumentationEnabled, kyselyLogOptio
3
3
  import "../connection-2igzM-AT.mjs";
4
4
  import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
5
5
  import { a as isSqlite } from "../dialect-helpers-DhTzaUxP.mjs";
6
- import { r as runMigrations } from "../runner-Cd-_WyDo.mjs";
7
- import { At as handleContentRestore, B as EmailPipeline, Ct as handleContentDuplicate, Dt as handleContentListTrashed, Et as handleContentList, Ft as handleContentUpdate, G as extractRequestMeta, H as createHookPipeline, It as validateRev, K as sanitizeHeadersForSandbox, L as PluginRouteRegistry, Mt as handleContentTranslations, Nt as handleContentUnpublish, Ot as handleContentPermanentDelete, Pt as handleContentUnschedule, R as DEV_CONSOLE_EMAIL_PLUGIN_ID, St as handleContentDiscardDraft, Tt as handleContentGetIncludingTrashed, U as resolveExclusiveHooks, W as CronExecutor, X as after, _t as handleContentCompare, bt as handleContentCreate, ct as handleMediaGet, dt as handleRevisionGet, ft as handleRevisionList, gt as hashString, it as PluginStateRepository, jt as handleContentSchedule, kt as handleContentPublish, lt as handleMediaList, ot as handleMediaCreate, pt as handleRevisionRestore, q as definePlugin, st as handleMediaDelete, tt as loadBundleFromR2, ut as handleMediaUpdate, vt as handleContentCountScheduled, wt as handleContentGet, xt as handleContentDelete, yt as handleContentCountTrashed, z as devConsoleEmailDeliver } from "../search-DI4bM2w9.mjs";
8
- import { r as RevisionRepository } from "../content-BsBoyj8G.mjs";
6
+ import { r as runMigrations } from "../runner-tQ7BJ4T7.mjs";
7
+ import { At as handleContentSchedule, B as EmailPipeline, Ct as handleContentGet, Dt as handleContentPermanentDelete, Et as handleContentListTrashed, Ft as validateRev, G as extractRequestMeta, H as createHookPipeline, J as definePlugin, K as sanitizeHeadersForSandbox, L as PluginRouteRegistry, Mt as handleContentUnpublish, Nt as handleContentUnschedule, Ot as handleContentPublish, Pt as handleContentUpdate, R as DEV_CONSOLE_EMAIL_PLUGIN_ID, St as handleContentDuplicate, Tt as handleContentList, U as resolveExclusiveHooks, W as CronExecutor, Z as after, _t as handleContentCountScheduled, at as PluginStateRepository, bt as handleContentDelete, ct as handleMediaDelete, dt as handleMediaUpdate, ft as handleRevisionGet, gt as handleContentCompare, jt as handleContentTranslations, kt as handleContentRestore, lt as handleMediaGet, mt as handleRevisionRestore, nt as loadBundleFromR2, pt as handleRevisionList, q as getTrustedProxyHeaders, st as handleMediaCreate, ut as handleMediaList, vt as handleContentCountTrashed, wt as handleContentGetIncludingTrashed, xt as handleContentDiscardDraft, yt as handleContentCreate, z as devConsoleEmailDeliver } from "../search-BoZYFuUk.mjs";
8
+ import { r as RevisionRepository } from "../content-BcQPYxdV.mjs";
9
9
  import "../base64-MBPo9ozB.mjs";
10
- import "../types-CMMN0pNg.mjs";
11
- import { t as MediaRepository } from "../media-DqHVh136.mjs";
12
- import { f as OptionsRepository } from "../apply-B4MsLM-w.mjs";
13
- import "../redirect-7lGhLBNZ.mjs";
14
- import "../byline-C4OVd8b3.mjs";
10
+ import "../types-BIgulNsW.mjs";
11
+ import { t as MediaRepository } from "../media-D8FbNsl0.mjs";
12
+ import { p as OptionsRepository } from "../apply-x0eMK1lX.mjs";
13
+ import "../redirect-D_pshWdf.mjs";
14
+ import "../byline-Chbr2GoP.mjs";
15
15
  import { n as normalizeMediaValue } from "../placeholder-C-fk5hYI.mjs";
16
16
  import { i as setI18nConfig } from "../config-BXwuX8Bx.mjs";
17
- import { i as FTSManager, n as SchemaRegistry } from "../registry-Ci3WxVAr.mjs";
18
- import { n as getDb } from "../loader-DeiBJEMe.mjs";
19
- import "../request-cache-DiR961CV.mjs";
20
- import "../taxonomies-DbrKzDju.mjs";
21
- import { r as normalizeManifestRoute } from "../manifest-schema-V30qsMft.mjs";
22
- import { a as invalidateUrlPatternCache } from "../query-Bk_3vKvU.mjs";
23
- import "../tokens-BFPFx3CA.mjs";
24
- import "../bylines-hPTW79hw.mjs";
25
- import "../load-CBcmDIot.mjs";
17
+ import { r as hashString } from "../zod-generator-CpwccCIv.mjs";
18
+ import { i as FTSManager, n as SchemaRegistry } from "../registry-C3Mr0ODu.mjs";
19
+ import { n as getDb } from "../loader-CndGj8kM.mjs";
20
+ import "../request-cache-Ci7f5pBb.mjs";
21
+ import "../taxonomies-B4IAshV8.mjs";
22
+ import { r as normalizeManifestRoute } from "../manifest-schema-DH9xhc6t.mjs";
23
+ import "../error-zG5T1UGA.mjs";
24
+ import { a as invalidateUrlPatternCache } from "../query-fqEdLFms.mjs";
25
+ import "../tokens-D9vnZqYS.mjs";
26
+ import "../bylines-CRNsVG88.mjs";
27
+ import "../load-CyEoextb.mjs";
26
28
  import "../index.mjs";
27
- import { n as VERSION, t as COMMIT } from "../version-Uaf2ynPX.mjs";
28
- import { t as getAuthMode } from "../mode-CpNnGkPz.mjs";
29
+ import { n as VERSION, t as COMMIT } from "../version-DJrV1K0M.mjs";
30
+ import { t as getAuthMode } from "../mode-BnAOqItE.mjs";
29
31
  import { Kysely, sql } from "kysely";
30
32
  import { defineMiddleware } from "astro:middleware";
31
33
  import virtualConfig from "virtual:emdash/config";
@@ -281,6 +283,19 @@ var PiggybackScheduler = class {
281
283
  //#endregion
282
284
  //#region src/emdash-runtime.ts
283
285
  const LEADING_SLASH_PATTERN = /^\//;
286
+ /**
287
+ * Parse a JSON column expected to contain an array of strings.
288
+ *
289
+ * Throws on malformed JSON rather than returning []; callers are responsible
290
+ * for deciding how to handle/log the error. Empty string / null inputs return
291
+ * [] (they represent "no value"). Non-string array entries are filtered out.
292
+ */
293
+ function parseStringArray(raw) {
294
+ if (!raw) return [];
295
+ const parsed = JSON.parse(raw);
296
+ if (!Array.isArray(parsed)) return [];
297
+ return parsed.filter((v) => typeof v === "string");
298
+ }
284
299
  const VALID_METADATA_KINDS = new Set([
285
300
  "meta",
286
301
  "property",
@@ -410,27 +425,27 @@ var EmDashRuntime = class EmDashRuntime {
410
425
  if (ctx?.db) return ctx.db;
411
426
  return this._db;
412
427
  }
413
- constructor(db, storage, configuredPlugins, sandboxedPlugins, sandboxedPluginEntries, hooks, enabledPlugins, pluginStates, config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, runtimeDeps, pipelineRef, manifestCacheKey) {
414
- this._db = db;
415
- this.storage = storage;
416
- this.configuredPlugins = configuredPlugins;
417
- this.sandboxedPlugins = sandboxedPlugins;
418
- this.sandboxedPluginEntries = sandboxedPluginEntries;
419
- this.schemaRegistry = new SchemaRegistry(db);
420
- this._hooks = hooks;
421
- this.enabledPlugins = enabledPlugins;
422
- this.pluginStates = pluginStates;
423
- this.config = config;
424
- this.mediaProviders = mediaProviders;
425
- this.mediaProviderEntries = mediaProviderEntries;
426
- this.cronExecutor = cronExecutor;
427
- this.cronScheduler = cronScheduler;
428
- this.email = emailPipeline;
429
- this.allPipelinePlugins = allPipelinePlugins;
430
- this.pipelineFactoryOptions = pipelineFactoryOptions;
431
- this.runtimeDeps = runtimeDeps;
432
- this.pipelineRef = pipelineRef;
433
- this._manifestCacheKey = manifestCacheKey;
428
+ constructor(parts) {
429
+ this._db = parts.db;
430
+ this.storage = parts.storage;
431
+ this.configuredPlugins = parts.configuredPlugins;
432
+ this.sandboxedPlugins = parts.sandboxedPlugins;
433
+ this.sandboxedPluginEntries = parts.sandboxedPluginEntries;
434
+ this.schemaRegistry = new SchemaRegistry(parts.db);
435
+ this._hooks = parts.hooks;
436
+ this.enabledPlugins = parts.enabledPlugins;
437
+ this.pluginStates = parts.pluginStates;
438
+ this.config = parts.config;
439
+ this.mediaProviders = parts.mediaProviders;
440
+ this.mediaProviderEntries = parts.mediaProviderEntries;
441
+ this.cronExecutor = parts.cronExecutor;
442
+ this.cronScheduler = parts.cronScheduler;
443
+ this.email = parts.emailPipeline;
444
+ this.allPipelinePlugins = parts.allPipelinePlugins;
445
+ this.pipelineFactoryOptions = parts.pipelineFactoryOptions;
446
+ this.runtimeDeps = parts.runtimeDeps;
447
+ this.pipelineRef = parts.pipelineRef;
448
+ this._manifestCacheKey = parts.manifestCacheKey;
434
449
  }
435
450
  /**
436
451
  * Get the sandbox runner instance (for marketplace install/update)
@@ -723,7 +738,27 @@ var EmDashRuntime = class EmDashRuntime {
723
738
  virtualConfig?.i18n?.defaultLocale ?? "",
724
739
  (virtualConfig?.i18n?.locales ?? []).toSorted().join(",")
725
740
  ].join("|"));
726
- return new EmDashRuntime(db, storage, deps.plugins, sandboxedPlugins, deps.sandboxedPluginEntries, pipeline, enabledPlugins, pluginStates, deps.config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, deps, pipelineRef, manifestCacheKey);
741
+ return new EmDashRuntime({
742
+ db,
743
+ storage,
744
+ configuredPlugins: deps.plugins,
745
+ sandboxedPlugins,
746
+ sandboxedPluginEntries: deps.sandboxedPluginEntries,
747
+ hooks: pipeline,
748
+ enabledPlugins,
749
+ pluginStates,
750
+ config: deps.config,
751
+ mediaProviders,
752
+ mediaProviderEntries,
753
+ cronExecutor,
754
+ cronScheduler,
755
+ emailPipeline,
756
+ allPipelinePlugins,
757
+ pipelineFactoryOptions,
758
+ runtimeDeps: deps,
759
+ pipelineRef,
760
+ manifestCacheKey
761
+ });
727
762
  }
728
763
  /**
729
764
  * Get a media provider by ID
@@ -777,9 +812,9 @@ var EmDashRuntime = class EmDashRuntime {
777
812
  }
778
813
  })();
779
814
  if (collectionCount.count === 0 && !setupDone) {
780
- const { applySeed } = await import("../apply-B4MsLM-w.mjs").then((n) => n.n);
781
- const { loadSeed } = await import("../load-CBcmDIot.mjs").then((n) => n.r);
782
- const { validateSeed } = await import("../validate-CqsNItbt.mjs").then((n) => n.n);
815
+ const { applySeed } = await import("../apply-x0eMK1lX.mjs").then((n) => n.n);
816
+ const { loadSeed } = await import("../load-CyEoextb.mjs").then((n) => n.r);
817
+ const { validateSeed } = await import("../validate-CxVsLehf.mjs").then((n) => n.n);
783
818
  const seed = await loadSeed();
784
819
  if (validateSeed(seed).valid) {
785
820
  await applySeed(db, seed, { onConflict: "skip" });
@@ -1055,7 +1090,7 @@ var EmDashRuntime = class EmDashRuntime {
1055
1090
  label: row.label,
1056
1091
  labelSingular: row.label_singular ?? void 0,
1057
1092
  hierarchical: row.hierarchical === 1,
1058
- collections: row.collections ? JSON.parse(row.collections).toSorted() : []
1093
+ collections: parseStringArray(row.collections).toSorted()
1059
1094
  }));
1060
1095
  } catch (error) {
1061
1096
  console.debug("EmDash: Could not load taxonomy definitions:", error);
@@ -1143,16 +1178,67 @@ var EmDashRuntime = class EmDashRuntime {
1143
1178
  return handleContentList(this.db, collection, params);
1144
1179
  }
1145
1180
  async handleContentGet(collection, id, locale) {
1146
- return handleContentGet(this.db, collection, id, locale);
1181
+ const result = await handleContentGet(this.db, collection, id, locale);
1182
+ return this.hydrateDraftData(result);
1147
1183
  }
1148
1184
  async handleContentGetIncludingTrashed(collection, id, locale) {
1149
- return handleContentGetIncludingTrashed(this.db, collection, id, locale);
1185
+ const result = await handleContentGetIncludingTrashed(this.db, collection, id, locale);
1186
+ return this.hydrateDraftData(result);
1187
+ }
1188
+ /**
1189
+ * If the response item has a `draftRevisionId`, replace `item.data` with
1190
+ * the draft revision's data and expose the original published values as
1191
+ * `liveData`. This makes the content_get / content_update round-trip
1192
+ * intuitive — read returns the latest content the caller has saved
1193
+ * (their pending draft), with the previously-published values still
1194
+ * accessible for compare-style flows.
1195
+ *
1196
+ * No-op when no draft exists or the response is an error.
1197
+ */
1198
+ async hydrateDraftData(result) {
1199
+ if (!result || typeof result !== "object") return result;
1200
+ const r = result;
1201
+ if (!r.success || !r.data?.item) return result;
1202
+ const item = r.data.item;
1203
+ const draftRevisionId = typeof item.draftRevisionId === "string" ? item.draftRevisionId : null;
1204
+ if (!draftRevisionId) return result;
1205
+ try {
1206
+ const revision = await new RevisionRepository(this.db).findById(draftRevisionId);
1207
+ if (!revision) return result;
1208
+ const liveData = item.data && typeof item.data === "object" ? item.data : {};
1209
+ const revisionData = {};
1210
+ for (const [key, value] of Object.entries(revision.data)) if (!key.startsWith("_")) revisionData[key] = value;
1211
+ const mergedData = {
1212
+ ...liveData,
1213
+ ...revisionData
1214
+ };
1215
+ return {
1216
+ ...result,
1217
+ data: {
1218
+ ...r.data,
1219
+ item: {
1220
+ ...item,
1221
+ data: mergedData,
1222
+ liveData
1223
+ }
1224
+ }
1225
+ };
1226
+ } catch (error) {
1227
+ console.error("[emdash] draft hydration failed:", error);
1228
+ return result;
1229
+ }
1150
1230
  }
1151
1231
  async handleContentCreate(collection, body) {
1152
1232
  let processedData = body.data;
1153
1233
  if (this.hooks.hasHooks("content:beforeSave")) processedData = (await this.hooks.runContentBeforeSave(body.data, collection, true)).content;
1154
1234
  processedData = await this.runSandboxedBeforeSave(processedData, collection, true);
1155
1235
  processedData = await this.normalizeMediaFields(collection, processedData);
1236
+ const { validateContentData } = await import("../validation-C-ZpN2GI.mjs");
1237
+ const validation = await validateContentData(this.db, collection, processedData, { partial: false });
1238
+ if (!validation.ok) return {
1239
+ success: false,
1240
+ error: validation.error
1241
+ };
1156
1242
  const result = await handleContentCreate(this.db, collection, {
1157
1243
  ...body,
1158
1244
  data: processedData,
@@ -1163,7 +1249,7 @@ var EmDashRuntime = class EmDashRuntime {
1163
1249
  return result;
1164
1250
  }
1165
1251
  async handleContentUpdate(collection, id, body) {
1166
- const { ContentRepository } = await import("../content-BsBoyj8G.mjs").then((n) => n.n);
1252
+ const { ContentRepository } = await import("../content-BcQPYxdV.mjs").then((n) => n.n);
1167
1253
  const repo = new ContentRepository(this.db);
1168
1254
  const resolvedItem = await repo.findByIdOrSlug(collection, id);
1169
1255
  const resolvedId = resolvedItem?.id ?? id;
@@ -1190,6 +1276,12 @@ var EmDashRuntime = class EmDashRuntime {
1190
1276
  if (this.hooks.hasHooks("content:beforeSave")) processedData = (await this.hooks.runContentBeforeSave(bodyWithoutRev.data, collection, false)).content;
1191
1277
  processedData = await this.runSandboxedBeforeSave(processedData, collection, false);
1192
1278
  processedData = await this.normalizeMediaFields(collection, processedData);
1279
+ const { validateContentData } = await import("../validation-C-ZpN2GI.mjs");
1280
+ const validation = await validateContentData(this.db, collection, processedData, { partial: true });
1281
+ if (!validation.ok) return {
1282
+ success: false,
1283
+ error: validation.error
1284
+ };
1193
1285
  }
1194
1286
  let usesDraftRevisions = false;
1195
1287
  if (processedData) try {
@@ -1234,8 +1326,9 @@ var EmDashRuntime = class EmDashRuntime {
1234
1326
  authorId: bodyWithoutRev.authorId,
1235
1327
  bylines: bodyWithoutRev.bylines
1236
1328
  });
1237
- if (result.success && result.data) this.runAfterSaveHooks(contentItemToRecord(result.data.item), collection, false);
1238
- return result;
1329
+ const hydrated = await this.hydrateDraftData(result);
1330
+ if (hydrated.success && hydrated.data) this.runAfterSaveHooks(contentItemToRecord(hydrated.data.item), collection, false);
1331
+ return hydrated;
1239
1332
  }
1240
1333
  async handleContentDelete(collection, id) {
1241
1334
  if (this.hooks.hasHooks("content:beforeDelete")) {
@@ -1353,7 +1446,47 @@ var EmDashRuntime = class EmDashRuntime {
1353
1446
  return handleRevisionGet(this.db, revisionId);
1354
1447
  }
1355
1448
  async handleRevisionRestore(revisionId, callerUserId) {
1356
- return handleRevisionRestore(this.db, revisionId, callerUserId);
1449
+ const revisionRepo = new RevisionRepository(this.db);
1450
+ const revision = await revisionRepo.findById(revisionId);
1451
+ if (!revision) return {
1452
+ success: false,
1453
+ error: {
1454
+ code: "NOT_FOUND",
1455
+ message: `Revision not found: ${revisionId}`
1456
+ }
1457
+ };
1458
+ if (!((await this.schemaRegistry.getCollectionWithFields(revision.collection))?.supports?.includes("revisions") ?? false)) {
1459
+ const result = await handleRevisionRestore(this.db, revisionId, callerUserId);
1460
+ return this.hydrateDraftData(result);
1461
+ }
1462
+ try {
1463
+ const newDraft = await revisionRepo.create({
1464
+ collection: revision.collection,
1465
+ entryId: revision.entryId,
1466
+ data: revision.data,
1467
+ authorId: callerUserId
1468
+ });
1469
+ validateIdentifier(revision.collection, "collection");
1470
+ const tableName = `ec_${revision.collection}`;
1471
+ await sql`
1472
+ UPDATE ${sql.ref(tableName)}
1473
+ SET draft_revision_id = ${newDraft.id},
1474
+ updated_at = ${(/* @__PURE__ */ new Date()).toISOString()}
1475
+ WHERE id = ${revision.entryId}
1476
+ `.execute(this.db);
1477
+ revisionRepo.pruneOldRevisions(revision.collection, revision.entryId, 50).catch(() => {});
1478
+ const refetched = await handleContentGet(this.db, revision.collection, revision.entryId);
1479
+ return this.hydrateDraftData(refetched);
1480
+ } catch (error) {
1481
+ console.error("[emdash] revision restore failed:", error);
1482
+ return {
1483
+ success: false,
1484
+ error: {
1485
+ code: "REVISION_RESTORE_ERROR",
1486
+ message: "Failed to restore revision"
1487
+ }
1488
+ };
1489
+ }
1357
1490
  }
1358
1491
  /**
1359
1492
  * Get route metadata for a plugin route without invoking the handler.
@@ -1395,7 +1528,8 @@ var EmDashRuntime = class EmDashRuntime {
1395
1528
  if (trustedPlugin && this.enabledPlugins.has(trustedPlugin.id)) {
1396
1529
  const routeRegistry = new PluginRouteRegistry({
1397
1530
  db: this.db,
1398
- emailPipeline: this.email ?? void 0
1531
+ emailPipeline: this.email ?? void 0,
1532
+ trustedProxyHeaders: getTrustedProxyHeaders(this.config)
1399
1533
  });
1400
1534
  routeRegistry.register(trustedPlugin);
1401
1535
  const routeKey = path.replace(LEADING_SLASH_PATTERN, "");
@@ -1485,16 +1619,30 @@ var EmDashRuntime = class EmDashRuntime {
1485
1619
  return true;
1486
1620
  }
1487
1621
  runAfterSaveHooks(content, collection, isNew) {
1488
- if (this.hooks.hasHooks("content:afterSave")) this.hooks.runContentAfterSave(content, collection, isNew).catch((err) => console.error("EmDash afterSave hook error:", err));
1489
- for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1490
- const [id] = pluginKey.split(":");
1491
- if (!id || !this.isPluginEnabled(id)) continue;
1492
- plugin.invokeHook("content:afterSave", {
1493
- content,
1494
- collection,
1495
- isNew
1496
- }).catch((err) => console.error(`EmDash: Sandboxed plugin ${id} afterSave error:`, err));
1497
- }
1622
+ after(async () => {
1623
+ if (this.hooks.hasHooks("content:afterSave")) try {
1624
+ await this.hooks.runContentAfterSave(content, collection, isNew);
1625
+ } catch (err) {
1626
+ console.error("EmDash afterSave hook error:", err);
1627
+ }
1628
+ const tasks = [];
1629
+ for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1630
+ const [id] = pluginKey.split(":");
1631
+ if (!id || !this.isPluginEnabled(id)) continue;
1632
+ tasks.push((async () => {
1633
+ try {
1634
+ await plugin.invokeHook("content:afterSave", {
1635
+ content,
1636
+ collection,
1637
+ isNew
1638
+ });
1639
+ } catch (err) {
1640
+ console.error(`EmDash: Sandboxed plugin ${id} afterSave error:`, err);
1641
+ }
1642
+ })());
1643
+ }
1644
+ await Promise.allSettled(tasks);
1645
+ });
1498
1646
  }
1499
1647
  runAfterDeleteHooks(id, collection, permanent) {
1500
1648
  if (this.hooks.hasHooks("content:afterDelete")) this.hooks.runContentAfterDelete(id, collection, permanent).catch((err) => console.error("EmDash afterDelete hook error:", err));
@@ -1509,15 +1657,29 @@ var EmDashRuntime = class EmDashRuntime {
1509
1657
  }
1510
1658
  }
1511
1659
  runAfterPublishHooks(content, collection) {
1512
- if (this.hooks.hasHooks("content:afterPublish")) this.hooks.runContentAfterPublish(content, collection).catch((err) => console.error("EmDash afterPublish hook error:", err));
1513
- for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1514
- const [pluginId] = pluginKey.split(":");
1515
- if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
1516
- plugin.invokeHook("content:afterPublish", {
1517
- content,
1518
- collection
1519
- }).catch((err) => console.error(`EmDash: Sandboxed plugin ${pluginId} afterPublish error:`, err));
1520
- }
1660
+ after(async () => {
1661
+ if (this.hooks.hasHooks("content:afterPublish")) try {
1662
+ await this.hooks.runContentAfterPublish(content, collection);
1663
+ } catch (err) {
1664
+ console.error("EmDash afterPublish hook error:", err);
1665
+ }
1666
+ const tasks = [];
1667
+ for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1668
+ const [pluginId] = pluginKey.split(":");
1669
+ if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
1670
+ tasks.push((async () => {
1671
+ try {
1672
+ await plugin.invokeHook("content:afterPublish", {
1673
+ content,
1674
+ collection
1675
+ });
1676
+ } catch (err) {
1677
+ console.error(`EmDash: Sandboxed plugin ${pluginId} afterPublish error:`, err);
1678
+ }
1679
+ })());
1680
+ }
1681
+ await Promise.allSettled(tasks);
1682
+ });
1521
1683
  }
1522
1684
  runAfterUnpublishHooks(content, collection) {
1523
1685
  if (this.hooks.hasHooks("content:afterUnpublish")) this.hooks.runContentAfterUnpublish(content, collection).catch((err) => console.error("EmDash afterUnpublish hook error:", err));
@@ -1538,7 +1700,7 @@ var EmDashRuntime = class EmDashRuntime {
1538
1700
  } catch {}
1539
1701
  try {
1540
1702
  const headers = sanitizeHeadersForSandbox(request.headers);
1541
- const meta = extractRequestMeta(request);
1703
+ const meta = extractRequestMeta(request, this.config);
1542
1704
  return {
1543
1705
  success: true,
1544
1706
  data: await plugin.invokeRoute(routeName, body, {
@@ -1628,6 +1790,28 @@ var EmDashRuntime = class EmDashRuntime {
1628
1790
  }
1629
1791
  };
1630
1792
 
1793
+ //#endregion
1794
+ //#region src/media/url.ts
1795
+ /**
1796
+ * Resolve the public URL for a locally stored media key. Returns an empty
1797
+ * string when no key is given. When a storage adapter is supplied, defers to
1798
+ * `storage.getPublicUrl()`; otherwise returns the internal proxy route.
1799
+ */
1800
+ function resolvePublicMediaUrl(storage, storageKey) {
1801
+ if (!storageKey) return "";
1802
+ if (storage) return storage.getPublicUrl(storageKey);
1803
+ return `/_emdash/api/media/file/${storageKey}`;
1804
+ }
1805
+ /**
1806
+ * Build the `getPublicMediaUrl` closure attached to `Astro.locals.emdash`.
1807
+ * Shared by the anonymous fast path and the full-runtime path in middleware.
1808
+ *
1809
+ * @internal
1810
+ */
1811
+ function createPublicMediaUrlResolver(storage) {
1812
+ return (key) => resolvePublicMediaUrl(storage, key);
1813
+ }
1814
+
1631
1815
  //#endregion
1632
1816
  //#region src/astro/middleware.ts
1633
1817
  /**
@@ -1750,6 +1934,9 @@ function createRequestScopedDb$1(opts) {
1750
1934
  const onRequest = defineMiddleware(async (context, next) => {
1751
1935
  const { request, locals, cookies } = context;
1752
1936
  const url = context.url;
1937
+ if (!url.pathname.startsWith("/_emdash") && virtualConfig?.authProviders) {
1938
+ if (virtualConfig.authProviders.some((p) => p.routes?.some((r) => r.pattern && url.pathname === r.pattern))) return finalizeResponse(await next());
1939
+ }
1753
1940
  const queryRecorder = isInstrumentationEnabled() ? createRecorder(url.pathname, request.method, request.headers.get("x-perf-phase") ?? "default") : void 0;
1754
1941
  const run = async () => {
1755
1942
  const isEmDashRoute = url.pathname.startsWith("/_emdash");
@@ -1765,7 +1952,7 @@ const onRequest = defineMiddleware(async (context, next) => {
1765
1952
  if (!setupVerified) {
1766
1953
  const t0 = performance.now();
1767
1954
  try {
1768
- const { getDb } = await import("../loader-DeiBJEMe.mjs").then((n) => n.r);
1955
+ const { getDb } = await import("../loader-CndGj8kM.mjs").then((n) => n.r);
1769
1956
  await (await getDb()).selectFrom("_emdash_migrations").selectAll().limit(1).execute();
1770
1957
  setupVerified = true;
1771
1958
  } catch {
@@ -1786,7 +1973,8 @@ const onRequest = defineMiddleware(async (context, next) => {
1786
1973
  setupVerified = true;
1787
1974
  locals.emdash = {
1788
1975
  collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
1789
- collectPageFragments: runtime.collectPageFragments.bind(runtime)
1976
+ collectPageFragments: runtime.collectPageFragments.bind(runtime),
1977
+ getPublicMediaUrl: createPublicMediaUrlResolver(runtime.storage)
1790
1978
  };
1791
1979
  } catch {}
1792
1980
  timings.push({
@@ -1899,6 +2087,7 @@ const onRequest = defineMiddleware(async (context, next) => {
1899
2087
  ensureSearchHealthy: runtime.ensureSearchHealthy.bind(runtime),
1900
2088
  storage: runtime.storage,
1901
2089
  db: runtime.db,
2090
+ getPublicMediaUrl: createPublicMediaUrlResolver(runtime.storage),
1902
2091
  hooks: runtime.hooks,
1903
2092
  email: runtime.email,
1904
2093
  configuredPlugins: runtime.configuredPlugins,