emdash 0.5.0 → 0.7.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 (252) hide show
  1. package/dist/{adapters-C2BzVy0p.d.mts → adapters-Di31kZ28.d.mts} +16 -1
  2. package/dist/adapters-Di31kZ28.d.mts.map +1 -0
  3. package/dist/{apply-Cma_PiF6.mjs → apply-5uslYdUu.mjs} +197 -25
  4. package/dist/apply-5uslYdUu.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 +203 -33
  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 +30 -4
  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.d.mts.map +1 -1
  15. package/dist/astro/middleware/request-context.mjs +11 -4
  16. package/dist/astro/middleware/request-context.mjs.map +1 -1
  17. package/dist/astro/middleware/setup.mjs +1 -1
  18. package/dist/astro/middleware.d.mts.map +1 -1
  19. package/dist/astro/middleware.mjs +467 -186
  20. package/dist/astro/middleware.mjs.map +1 -1
  21. package/dist/astro/types.d.mts +17 -9
  22. package/dist/astro/types.d.mts.map +1 -1
  23. package/dist/{byline-WuOq9MFJ.mjs → byline-C4OVd8b3.mjs} +3 -19
  24. package/dist/byline-C4OVd8b3.mjs.map +1 -0
  25. package/dist/{bylines-C_Wsnz4L.mjs → bylines-hPTW79hw.mjs} +20 -33
  26. package/dist/bylines-hPTW79hw.mjs.map +1 -0
  27. package/dist/{cache-E3Dts-yT.mjs → cache-BkKBuIvS.mjs} +1 -1
  28. package/dist/{cache-E3Dts-yT.mjs.map → cache-BkKBuIvS.mjs.map} +1 -1
  29. package/dist/chunks-HGz06Soa.mjs +19 -0
  30. package/dist/chunks-HGz06Soa.mjs.map +1 -0
  31. package/dist/cli/index.mjs +12 -11
  32. package/dist/cli/index.mjs.map +1 -1
  33. package/dist/client/cf-access.d.mts +1 -1
  34. package/dist/client/index.d.mts +1 -1
  35. package/dist/client/index.mjs +1 -1
  36. package/dist/{config-DkxPrM9l.mjs → config-BXwuX8Bx.mjs} +1 -1
  37. package/dist/{config-DkxPrM9l.mjs.map → config-BXwuX8Bx.mjs.map} +1 -1
  38. package/dist/{connection-B4zVnQIa.mjs → connection-2igzM-AT.mjs} +19 -2
  39. package/dist/connection-2igzM-AT.mjs.map +1 -0
  40. package/dist/{content-BsBoyj8G.mjs → content-D7J5y73J.mjs} +27 -1
  41. package/dist/{content-BsBoyj8G.mjs.map → content-D7J5y73J.mjs.map} +1 -1
  42. package/dist/database/instrumentation.d.mts +45 -0
  43. package/dist/database/instrumentation.d.mts.map +1 -0
  44. package/dist/database/instrumentation.mjs +61 -0
  45. package/dist/database/instrumentation.mjs.map +1 -0
  46. package/dist/db/index.d.mts +3 -3
  47. package/dist/db/index.mjs +1 -1
  48. package/dist/db/index.mjs.map +1 -1
  49. package/dist/db/libsql.d.mts +1 -1
  50. package/dist/db/postgres.d.mts +1 -1
  51. package/dist/db/sqlite.d.mts +1 -1
  52. package/dist/db-errors-D0UT85nC.mjs +41 -0
  53. package/dist/db-errors-D0UT85nC.mjs.map +1 -0
  54. package/dist/{default-PUx9RK6u.mjs → default-CME5YdZ3.mjs} +1 -1
  55. package/dist/{default-PUx9RK6u.mjs.map → default-CME5YdZ3.mjs.map} +1 -1
  56. package/dist/{error-HBeQbVhV.mjs → error-CiYn9yDu.mjs} +1 -1
  57. package/dist/{error-HBeQbVhV.mjs.map → error-CiYn9yDu.mjs.map} +1 -1
  58. package/dist/{index-CCWzlriB.d.mts → index-De6_Xv3v.d.mts} +209 -19
  59. package/dist/index-De6_Xv3v.d.mts.map +1 -0
  60. package/dist/index.d.mts +11 -11
  61. package/dist/index.mjs +23 -21
  62. package/dist/{load-BhSSm-TS.mjs → load-CBcmDIot.mjs} +1 -1
  63. package/dist/{load-BhSSm-TS.mjs.map → load-CBcmDIot.mjs.map} +1 -1
  64. package/dist/{loader-BYzwzORf.mjs → loader-DeiBJEMe.mjs} +18 -12
  65. package/dist/loader-DeiBJEMe.mjs.map +1 -0
  66. package/dist/{manifest-schema-BsXINkQD.mjs → manifest-schema-V30qsMft.mjs} +1 -1
  67. package/dist/{manifest-schema-BsXINkQD.mjs.map → manifest-schema-V30qsMft.mjs.map} +1 -1
  68. package/dist/media/index.d.mts +1 -1
  69. package/dist/media/index.mjs +1 -1
  70. package/dist/media/local-runtime.d.mts +7 -7
  71. package/dist/{mode-CyPLdO3C.mjs → mode-CpNnGkPz.mjs} +1 -1
  72. package/dist/{mode-CyPLdO3C.mjs.map → mode-CpNnGkPz.mjs.map} +1 -1
  73. package/dist/page/index.d.mts +11 -2
  74. package/dist/page/index.d.mts.map +1 -1
  75. package/dist/page/index.mjs +23 -1
  76. package/dist/page/index.mjs.map +1 -1
  77. package/dist/{placeholder-DntBEQo7.mjs → placeholder-C-fk5hYI.mjs} +1 -1
  78. package/dist/{placeholder-DntBEQo7.mjs.map → placeholder-C-fk5hYI.mjs.map} +1 -1
  79. package/dist/{placeholder-BBCtpTES.d.mts → placeholder-tzpqGWII.d.mts} +1 -1
  80. package/dist/{placeholder-BBCtpTES.d.mts.map → placeholder-tzpqGWII.d.mts.map} +1 -1
  81. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  82. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  83. package/dist/{query-B6Vu0d2i.mjs → query-g4Ug-9j9.mjs} +79 -12
  84. package/dist/query-g4Ug-9j9.mjs.map +1 -0
  85. package/dist/{redirect-7lGhLBNZ.mjs → redirect-CN0Rt9Ob.mjs} +66 -10
  86. package/dist/redirect-CN0Rt9Ob.mjs.map +1 -0
  87. package/dist/{registry-BgnP3ysR.mjs → registry-Ci3WxVAr.mjs} +133 -97
  88. package/dist/registry-Ci3WxVAr.mjs.map +1 -0
  89. package/dist/request-cache-DiR961CV.mjs +79 -0
  90. package/dist/request-cache-DiR961CV.mjs.map +1 -0
  91. package/dist/request-context.d.mts +19 -16
  92. package/dist/request-context.d.mts.map +1 -1
  93. package/dist/request-context.mjs.map +1 -1
  94. package/dist/{runner-DYv3rX8P.d.mts → runner-BR2xKwhn.d.mts} +2 -2
  95. package/dist/{runner-DYv3rX8P.d.mts.map → runner-BR2xKwhn.d.mts.map} +1 -1
  96. package/dist/{runner-Cd-_WyDo.mjs → runner-tQ7BJ4T7.mjs} +211 -134
  97. package/dist/runner-tQ7BJ4T7.mjs.map +1 -0
  98. package/dist/runtime.d.mts +6 -6
  99. package/dist/runtime.mjs +1 -1
  100. package/dist/{search-Cn1SYvYF.mjs → search-B0effn3j.mjs} +210 -226
  101. package/dist/search-B0effn3j.mjs.map +1 -0
  102. package/dist/seed/index.d.mts +2 -2
  103. package/dist/seed/index.mjs +10 -9
  104. package/dist/seo/index.d.mts +1 -1
  105. package/dist/storage/local.d.mts +1 -1
  106. package/dist/storage/local.mjs +1 -1
  107. package/dist/storage/s3.d.mts +1 -1
  108. package/dist/storage/s3.mjs +1 -1
  109. package/dist/taxonomies-K2z0Uhnj.mjs +308 -0
  110. package/dist/taxonomies-K2z0Uhnj.mjs.map +1 -0
  111. package/dist/{tokens-DKHiCYCB.mjs → tokens-BFPFx3CA.mjs} +1 -1
  112. package/dist/{tokens-DKHiCYCB.mjs.map → tokens-BFPFx3CA.mjs.map} +1 -1
  113. package/dist/{transport-BtcQ-Z7T.mjs → transport-BykRfpyy.mjs} +1 -1
  114. package/dist/{transport-BtcQ-Z7T.mjs.map → transport-BykRfpyy.mjs.map} +1 -1
  115. package/dist/{transport-CKQA_G44.d.mts → transport-H4Iwx7tC.d.mts} +1 -1
  116. package/dist/{transport-CKQA_G44.d.mts.map → transport-H4Iwx7tC.d.mts.map} +1 -1
  117. package/dist/{types-BmkQR1En.d.mts → types-6CUZRrZP.d.mts} +1 -1
  118. package/dist/{types-BmkQR1En.d.mts.map → types-6CUZRrZP.d.mts.map} +1 -1
  119. package/dist/{types-Dz9_WMS6.mjs → types-BH2L167P.mjs} +1 -1
  120. package/dist/{types-Dz9_WMS6.mjs.map → types-BH2L167P.mjs.map} +1 -1
  121. package/dist/{types-B6BzlZxx.d.mts → types-C2v0c34j.d.mts} +10 -1
  122. package/dist/{types-B6BzlZxx.d.mts.map → types-C2v0c34j.d.mts.map} +1 -1
  123. package/dist/{types-DNZpaCBk.d.mts → types-CFWjXmus.d.mts} +1 -1
  124. package/dist/{types-DNZpaCBk.d.mts.map → types-CFWjXmus.d.mts.map} +1 -1
  125. package/dist/{types-DeG21anB.d.mts → types-CnZYHyLW.d.mts} +55 -5
  126. package/dist/types-CnZYHyLW.d.mts.map +1 -0
  127. package/dist/{types-xxCWI3j0.mjs → types-DDS4MxsT.mjs} +11 -3
  128. package/dist/types-DDS4MxsT.mjs.map +1 -0
  129. package/dist/{types-C3ronwXb.d.mts → types-DgrIP0tF.d.mts} +102 -4
  130. package/dist/types-DgrIP0tF.d.mts.map +1 -0
  131. package/dist/{validate-DuZDIxfy.mjs → validate-CqsNItbt.mjs} +2 -2
  132. package/dist/{validate-DuZDIxfy.mjs.map → validate-CqsNItbt.mjs.map} +1 -1
  133. package/dist/{validate-Db1yNL3i.d.mts → validate-kM8Pjuf7.d.mts} +5 -52
  134. package/dist/validate-kM8Pjuf7.d.mts.map +1 -0
  135. package/dist/version-BnTKdfam.mjs +7 -0
  136. package/dist/{version-CMMjTuqu.mjs.map → version-BnTKdfam.mjs.map} +1 -1
  137. package/package.json +10 -5
  138. package/src/after.ts +62 -0
  139. package/src/api/handlers/content.ts +2 -0
  140. package/src/api/handlers/oauth-authorization.ts +2 -32
  141. package/src/api/handlers/oauth-clients.ts +40 -4
  142. package/src/api/handlers/taxonomies.ts +13 -0
  143. package/src/api/oauth/redirect-uri.ts +34 -0
  144. package/src/api/openapi/document.ts +126 -118
  145. package/src/api/schemas/content.ts +8 -0
  146. package/src/api/schemas/media.ts +26 -15
  147. package/src/api/schemas/schema.ts +1 -0
  148. package/src/astro/integration/font-provider.ts +178 -0
  149. package/src/astro/integration/index.ts +44 -0
  150. package/src/astro/integration/routes.ts +6 -0
  151. package/src/astro/integration/runtime.ts +117 -0
  152. package/src/astro/integration/virtual-modules.ts +41 -39
  153. package/src/astro/integration/vite-config.ts +16 -5
  154. package/src/astro/middleware/auth.ts +33 -1
  155. package/src/astro/middleware/request-context.ts +15 -3
  156. package/src/astro/middleware.ts +340 -263
  157. package/src/astro/routes/admin.astro +21 -10
  158. package/src/astro/routes/api/auth/magic-link/send.ts +2 -1
  159. package/src/astro/routes/api/auth/passkey/options.ts +2 -1
  160. package/src/astro/routes/api/auth/passkey/verify.ts +5 -1
  161. package/src/astro/routes/api/auth/signup/request.ts +26 -8
  162. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +10 -6
  163. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +1 -1
  164. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +1 -1
  165. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +1 -1
  166. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +5 -0
  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 +19 -1
  170. package/src/astro/routes/api/content/[collection]/trash.ts +1 -1
  171. package/src/astro/routes/api/import/wordpress/execute.ts +1 -1
  172. package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +4 -3
  173. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +5 -4
  174. package/src/astro/routes/api/manifest.ts +7 -0
  175. package/src/astro/routes/api/media/upload-url.ts +10 -2
  176. package/src/astro/routes/api/media.ts +10 -7
  177. package/src/astro/routes/api/oauth/device/code.ts +2 -1
  178. package/src/astro/routes/api/oauth/device/token.ts +2 -1
  179. package/src/astro/routes/api/oauth/register.ts +178 -0
  180. package/src/astro/routes/api/oauth/token.ts +15 -0
  181. package/src/astro/routes/api/openapi.json.ts +15 -5
  182. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +2 -0
  183. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +1 -0
  184. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +1 -0
  185. package/src/astro/routes/api/search/index.ts +5 -0
  186. package/src/astro/routes/api/search/suggest.ts +3 -0
  187. package/src/astro/routes/api/setup/admin-verify.ts +30 -5
  188. package/src/astro/routes/api/setup/admin.ts +32 -8
  189. package/src/astro/routes/api/setup/index.ts +5 -2
  190. package/src/astro/routes/api/taxonomies/index.ts +1 -0
  191. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +1 -1
  192. package/src/astro/types.ts +9 -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/bylines/index.ts +22 -45
  197. package/src/components/EmDashHead.astro +23 -7
  198. package/src/database/connection.ts +23 -1
  199. package/src/database/instrumentation.ts +98 -0
  200. package/src/database/migrations/035_bounded_404_log.ts +112 -0
  201. package/src/database/migrations/runner.ts +2 -0
  202. package/src/database/repositories/content.ts +39 -0
  203. package/src/database/repositories/options.ts +25 -0
  204. package/src/database/repositories/redirect.ts +111 -8
  205. package/src/database/types.ts +9 -0
  206. package/src/db/adapters.ts +15 -0
  207. package/src/emdash-runtime.ts +312 -92
  208. package/src/import/registry.ts +4 -3
  209. package/src/import/ssrf.ts +253 -12
  210. package/src/index.ts +6 -0
  211. package/src/loader.ts +19 -24
  212. package/src/mcp/server.ts +76 -3
  213. package/src/menus/index.ts +6 -3
  214. package/src/page/index.ts +1 -1
  215. package/src/page/seo-contributions.ts +36 -0
  216. package/src/plugins/context.ts +15 -3
  217. package/src/plugins/manager.ts +6 -0
  218. package/src/plugins/request-meta.ts +66 -15
  219. package/src/plugins/routes.ts +3 -1
  220. package/src/query.ts +104 -7
  221. package/src/request-cache.ts +106 -0
  222. package/src/request-context.ts +19 -0
  223. package/src/schema/query.ts +5 -2
  224. package/src/schema/registry.ts +243 -166
  225. package/src/schema/types.ts +13 -2
  226. package/src/schema/zod-generator.ts +4 -0
  227. package/src/search/fts-manager.ts +19 -5
  228. package/src/search/query.ts +4 -3
  229. package/src/seed/apply.ts +41 -1
  230. package/src/settings/index.ts +24 -5
  231. package/src/taxonomies/index.ts +324 -124
  232. package/src/utils/db-errors.ts +46 -0
  233. package/src/virtual-modules.d.ts +31 -10
  234. package/src/visual-editing/toolbar.ts +6 -1
  235. package/src/widgets/index.ts +54 -25
  236. package/dist/adapters-C2BzVy0p.d.mts.map +0 -1
  237. package/dist/apply-Cma_PiF6.mjs.map +0 -1
  238. package/dist/byline-WuOq9MFJ.mjs.map +0 -1
  239. package/dist/bylines-C_Wsnz4L.mjs.map +0 -1
  240. package/dist/connection-B4zVnQIa.mjs.map +0 -1
  241. package/dist/index-CCWzlriB.d.mts.map +0 -1
  242. package/dist/loader-BYzwzORf.mjs.map +0 -1
  243. package/dist/query-B6Vu0d2i.mjs.map +0 -1
  244. package/dist/redirect-7lGhLBNZ.mjs.map +0 -1
  245. package/dist/registry-BgnP3ysR.mjs.map +0 -1
  246. package/dist/runner-Cd-_WyDo.mjs.map +0 -1
  247. package/dist/search-Cn1SYvYF.mjs.map +0 -1
  248. package/dist/types-C3ronwXb.d.mts.map +0 -1
  249. package/dist/types-DeG21anB.d.mts.map +0 -1
  250. package/dist/types-xxCWI3j0.mjs.map +0 -1
  251. package/dist/validate-Db1yNL3i.d.mts.map +0 -1
  252. package/dist/version-CMMjTuqu.mjs +0 -7
@@ -1,32 +1,35 @@
1
- import "../connection-B4zVnQIa.mjs";
1
+ import { getRequestContext, runWithContext } from "../request-context.mjs";
2
+ import { createRecorder, flushRecorder, isInstrumentationEnabled, kyselyLogOption } from "../database/instrumentation.mjs";
3
+ import "../connection-2igzM-AT.mjs";
2
4
  import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
3
5
  import { a as isSqlite } from "../dialect-helpers-DhTzaUxP.mjs";
4
- import { r as runMigrations } from "../runner-Cd-_WyDo.mjs";
5
- import { $ as sanitizeHeadersForSandbox, At as handleContentGet, Bt as handleContentUnschedule, Ct as handleContentCompare, Dt as handleContentDelete, Et as handleContentCreate, Ft as handleContentPublish, G as DEV_CONSOLE_EMAIL_PLUGIN_ID, Ht as validateRev, It as handleContentRestore, K as devConsoleEmailDeliver, Lt as handleContentSchedule, Mt as handleContentList, Nt as handleContentListTrashed, Ot as handleContentDiscardDraft, Pt as handleContentPermanentDelete, Q as extractRequestMeta, Rt as handleContentTranslations, St as hashString, Tt as handleContentCountTrashed, Vt as handleContentUpdate, W as PluginRouteRegistry, X as resolveExclusiveHooks, Y as createHookPipeline, Z as CronExecutor, _t as handleRevisionGet, et as definePlugin, ft as handleMediaCreate, gt as handleMediaUpdate, ht as handleMediaList, jt as handleContentGetIncludingTrashed, kt as handleContentDuplicate, mt as handleMediaGet, pt as handleMediaDelete, q as EmailPipeline, st as loadBundleFromR2, ut as PluginStateRepository, vt as handleRevisionList, wt as handleContentCountScheduled, yt as handleRevisionRestore, zt as handleContentUnpublish } from "../search-Cn1SYvYF.mjs";
6
- import { r as RevisionRepository } from "../content-BsBoyj8G.mjs";
6
+ import { r as runMigrations } from "../runner-tQ7BJ4T7.mjs";
7
+ import { At as handleContentPublish, B as EmailPipeline, Ct as handleContentDiscardDraft, Dt as handleContentList, Et as handleContentGetIncludingTrashed, Ft as handleContentUnschedule, G as extractRequestMeta, H as createHookPipeline, It as handleContentUpdate, J as definePlugin, K as sanitizeHeadersForSandbox, L as PluginRouteRegistry, Lt as validateRev, Mt as handleContentSchedule, Nt as handleContentTranslations, Ot as handleContentListTrashed, Pt as handleContentUnpublish, R as DEV_CONSOLE_EMAIL_PLUGIN_ID, St as handleContentDelete, Tt as handleContentGet, U as resolveExclusiveHooks, W as CronExecutor, Z as after, _t as hashString, at as PluginStateRepository, bt as handleContentCountTrashed, ct as handleMediaDelete, dt as handleMediaUpdate, ft as handleRevisionGet, jt as handleContentRestore, kt as handleContentPermanentDelete, lt as handleMediaGet, mt as handleRevisionRestore, nt as loadBundleFromR2, pt as handleRevisionList, q as getTrustedProxyHeaders, st as handleMediaCreate, ut as handleMediaList, vt as handleContentCompare, wt as handleContentDuplicate, xt as handleContentCreate, yt as handleContentCountScheduled, z as devConsoleEmailDeliver } from "../search-B0effn3j.mjs";
8
+ import { r as RevisionRepository } from "../content-D7J5y73J.mjs";
7
9
  import "../base64-MBPo9ozB.mjs";
8
10
  import "../types-CMMN0pNg.mjs";
9
11
  import { t as MediaRepository } from "../media-DqHVh136.mjs";
10
- import { f as OptionsRepository } from "../apply-Cma_PiF6.mjs";
11
- import "../redirect-7lGhLBNZ.mjs";
12
- import "../byline-WuOq9MFJ.mjs";
13
- import { n as normalizeMediaValue } from "../placeholder-DntBEQo7.mjs";
14
- import { i as setI18nConfig } from "../config-DkxPrM9l.mjs";
15
- import { i as FTSManager, n as SchemaRegistry } from "../registry-BgnP3ysR.mjs";
16
- import { getRequestContext, runWithContext } from "../request-context.mjs";
17
- import { n as getDb } from "../loader-BYzwzORf.mjs";
18
- import { r as normalizeManifestRoute } from "../manifest-schema-BsXINkQD.mjs";
19
- import { a as invalidateUrlPatternCache } from "../query-B6Vu0d2i.mjs";
20
- import "../tokens-DKHiCYCB.mjs";
21
- import "../bylines-C_Wsnz4L.mjs";
22
- import "../load-BhSSm-TS.mjs";
12
+ import { p as OptionsRepository } from "../apply-5uslYdUu.mjs";
13
+ import "../redirect-CN0Rt9Ob.mjs";
14
+ import "../byline-C4OVd8b3.mjs";
15
+ import { n as normalizeMediaValue } from "../placeholder-C-fk5hYI.mjs";
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-K2z0Uhnj.mjs";
21
+ import { r as normalizeManifestRoute } from "../manifest-schema-V30qsMft.mjs";
22
+ import { a as invalidateUrlPatternCache } from "../query-g4Ug-9j9.mjs";
23
+ import "../tokens-BFPFx3CA.mjs";
24
+ import "../bylines-hPTW79hw.mjs";
25
+ import "../load-CBcmDIot.mjs";
23
26
  import "../index.mjs";
24
- import { n as VERSION, t as COMMIT } from "../version-CMMjTuqu.mjs";
25
- import { t as getAuthMode } from "../mode-CyPLdO3C.mjs";
27
+ import { n as VERSION, t as COMMIT } from "../version-BnTKdfam.mjs";
28
+ import { t as getAuthMode } from "../mode-CpNnGkPz.mjs";
26
29
  import { Kysely, sql } from "kysely";
27
30
  import { defineMiddleware } from "astro:middleware";
28
31
  import virtualConfig from "virtual:emdash/config";
29
- import { createDialect, createSessionDialect, getBookmarkCookieName, getD1Binding, getDefaultConstraint, isSessionEnabled } from "virtual:emdash/dialect";
32
+ import { createDialect, createRequestScopedDb } from "virtual:emdash/dialect";
30
33
  import { mediaProviders } from "virtual:emdash/media-providers";
31
34
  import { plugins } from "virtual:emdash/plugins";
32
35
  import { createSandboxRunner, sandboxEnabled } from "virtual:emdash/sandbox-runner";
@@ -316,6 +319,7 @@ function isValidMetadataContribution(c) {
316
319
  const FIELD_TYPE_TO_KIND = {
317
320
  string: "string",
318
321
  slug: "string",
322
+ url: "url",
319
323
  text: "richText",
320
324
  number: "number",
321
325
  integer: "number",
@@ -371,6 +375,16 @@ var EmDashRuntime = class EmDashRuntime {
371
375
  cronScheduler;
372
376
  enabledPlugins;
373
377
  pluginStates;
378
+ _cachedManifest = null;
379
+ _manifestPromise = null;
380
+ _manifestCacheKey;
381
+ /**
382
+ * Set to true after FTS indexes have been verified for this worker
383
+ * lifetime so we don't re-scan on every admin request. See
384
+ * ensureSearchHealthy().
385
+ */
386
+ _searchHealthChecked = false;
387
+ _searchHealthPromise = null;
374
388
  /** Current hook pipeline. Use the `hooks` getter for external access. */
375
389
  get hooks() {
376
390
  return this._hooks;
@@ -396,7 +410,7 @@ var EmDashRuntime = class EmDashRuntime {
396
410
  if (ctx?.db) return ctx.db;
397
411
  return this._db;
398
412
  }
399
- constructor(db, storage, configuredPlugins, sandboxedPlugins, sandboxedPluginEntries, hooks, enabledPlugins, pluginStates, config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, runtimeDeps, pipelineRef) {
413
+ constructor(db, storage, configuredPlugins, sandboxedPlugins, sandboxedPluginEntries, hooks, enabledPlugins, pluginStates, config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, runtimeDeps, pipelineRef, manifestCacheKey) {
400
414
  this._db = db;
401
415
  this.storage = storage;
402
416
  this.configuredPlugins = configuredPlugins;
@@ -416,6 +430,7 @@ var EmDashRuntime = class EmDashRuntime {
416
430
  this.pipelineFactoryOptions = pipelineFactoryOptions;
417
431
  this.runtimeDeps = runtimeDeps;
418
432
  this.pipelineRef = pipelineRef;
433
+ this._manifestCacheKey = manifestCacheKey;
419
434
  }
420
435
  /**
421
436
  * Get the sandbox runner instance (for marketplace install/update)
@@ -456,6 +471,7 @@ var EmDashRuntime = class EmDashRuntime {
456
471
  this.enabledPlugins.delete(pluginId);
457
472
  await this.rebuildHookPipeline();
458
473
  }
474
+ this.invalidateManifest();
459
475
  }
460
476
  /**
461
477
  * Rebuild the hook pipeline from the current set of enabled plugins.
@@ -564,35 +580,49 @@ var EmDashRuntime = class EmDashRuntime {
564
580
  /**
565
581
  * Create and initialize the runtime
566
582
  */
567
- static async create(deps) {
568
- const db = await EmDashRuntime.getDatabase(deps);
569
- if (isSqlite(db)) try {
570
- const repaired = await new FTSManager(db).verifyAndRepairAll();
571
- if (repaired > 0) console.log(`Repaired ${repaired} corrupted FTS index(es) at startup`);
572
- } catch {}
583
+ static async create(deps, timings) {
584
+ const phase = async (name, desc, fn) => {
585
+ if (!timings) return fn();
586
+ const t0 = performance.now();
587
+ try {
588
+ return await fn();
589
+ } finally {
590
+ timings.push({
591
+ name,
592
+ dur: performance.now() - t0,
593
+ desc
594
+ });
595
+ }
596
+ };
597
+ const db = await phase("rt.db", "DB init + migrations", () => EmDashRuntime.getDatabase(deps));
573
598
  const storage = EmDashRuntime.getStorage(deps);
574
599
  let pluginStates = /* @__PURE__ */ new Map();
575
- try {
576
- const states = await db.selectFrom("_plugin_state").select(["plugin_id", "status"]).execute();
577
- pluginStates = new Map(states.map((s) => [s.plugin_id, s.status]));
578
- } catch {}
600
+ await phase("rt.plugins", "Plugin states", async () => {
601
+ try {
602
+ const states = await db.selectFrom("_plugin_state").select(["plugin_id", "status"]).execute();
603
+ pluginStates = new Map(states.map((s) => [s.plugin_id, s.status]));
604
+ } catch {}
605
+ });
579
606
  const enabledPlugins = /* @__PURE__ */ new Set();
580
607
  for (const plugin of deps.plugins) {
581
608
  const status = pluginStates.get(plugin.id);
582
609
  if (status === void 0 || status === "active") enabledPlugins.add(plugin.id);
583
610
  }
584
611
  let siteInfo;
585
- try {
586
- const optionsRepo = new OptionsRepository(db);
587
- const siteName = await optionsRepo.get("emdash:site_title");
588
- const siteUrl = await optionsRepo.get("emdash:site_url");
589
- const locale = await optionsRepo.get("emdash:locale");
590
- siteInfo = {
591
- siteName: siteName ?? void 0,
592
- siteUrl: siteUrl ?? void 0,
593
- locale: locale ?? void 0
594
- };
595
- } catch {}
612
+ await phase("rt.site", "Site info options", async () => {
613
+ try {
614
+ const siteOpts = await new OptionsRepository(db).getMany([
615
+ "emdash:site_title",
616
+ "emdash:site_url",
617
+ "emdash:locale"
618
+ ]);
619
+ siteInfo = {
620
+ siteName: siteOpts.get("emdash:site_title") ?? void 0,
621
+ siteUrl: siteOpts.get("emdash:site_url") ?? void 0,
622
+ locale: siteOpts.get("emdash:locale") ?? void 0
623
+ };
624
+ } catch {}
625
+ });
596
626
  const allPipelinePlugins = [...deps.plugins];
597
627
  if (import.meta.env.DEV) try {
598
628
  const devConsolePlugin = definePlugin({
@@ -631,8 +661,8 @@ var EmDashRuntime = class EmDashRuntime {
631
661
  siteInfo
632
662
  };
633
663
  const pipeline = createHookPipeline(enabledPluginList, pipelineFactoryOptions);
634
- const sandboxedPlugins = await EmDashRuntime.loadSandboxedPlugins(deps, db);
635
- if (deps.config.marketplace && storage) await EmDashRuntime.loadMarketplacePlugins(db, storage, deps, sandboxedPlugins);
664
+ const sandboxedPlugins = await phase("rt.sandbox", "Sandboxed plugins", () => EmDashRuntime.loadSandboxedPlugins(deps, db));
665
+ if (deps.config.marketplace && storage) await phase("rt.market", "Marketplace plugins", () => EmDashRuntime.loadMarketplacePlugins(db, storage, deps, sandboxedPlugins));
636
666
  const mediaProviders = /* @__PURE__ */ new Map();
637
667
  const mediaProviderEntries = deps.mediaProviderEntries ?? [];
638
668
  const providerContext = {
@@ -645,7 +675,7 @@ var EmDashRuntime = class EmDashRuntime {
645
675
  } catch (error) {
646
676
  console.warn(`Failed to initialize media provider "${entry.id}":`, error);
647
677
  }
648
- await EmDashRuntime.resolveExclusiveHooks(pipeline, db, deps);
678
+ await phase("rt.hooks", "Exclusive hook resolution", () => EmDashRuntime.resolveExclusiveHooks(pipeline, db, deps));
649
679
  const emailPipeline = new EmailPipeline(pipeline);
650
680
  if (sandboxRunner) sandboxRunner.setEmailSend((message, pluginId) => emailPipeline.send(message, pluginId));
651
681
  const pipelineRef = { current: pipeline };
@@ -659,25 +689,41 @@ var EmDashRuntime = class EmDashRuntime {
659
689
  });
660
690
  let cronExecutor = null;
661
691
  let cronScheduler = null;
662
- try {
663
- cronExecutor = new CronExecutor(db, invokeCronHook);
664
- const recovered = await cronExecutor.recoverStaleLocks();
665
- if (recovered > 0) console.log(`[cron] Recovered ${recovered} stale task lock(s)`);
666
- if (typeof globalThis.navigator !== "undefined" && globalThis.navigator.userAgent === "Cloudflare-Workers") cronScheduler = new PiggybackScheduler(cronExecutor);
667
- else cronScheduler = new NodeCronScheduler(cronExecutor);
668
- cronScheduler.setSystemCleanup(async () => {
669
- try {
670
- await runSystemCleanup(db, storage ?? void 0);
671
- } catch (error) {
672
- console.error("[cleanup] System cleanup failed:", error);
673
- }
674
- });
675
- pipeline.setContextFactory({ cronReschedule: () => cronScheduler?.reschedule() });
676
- await cronScheduler.start();
677
- } catch (error) {
678
- console.warn("[cron] Failed to initialize cron system:", error);
679
- }
680
- return new EmDashRuntime(db, storage, deps.plugins, sandboxedPlugins, deps.sandboxedPluginEntries, pipeline, enabledPlugins, pluginStates, deps.config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, deps, pipelineRef);
692
+ await phase("rt.cron", "Cron init (recovery deferred post-response)", async () => {
693
+ try {
694
+ cronExecutor = new CronExecutor(db, invokeCronHook);
695
+ const executorForRecovery = cronExecutor;
696
+ after(async () => {
697
+ try {
698
+ const recovered = await executorForRecovery.recoverStaleLocks();
699
+ if (recovered > 0) console.log(`[cron] Recovered ${recovered} stale task lock(s)`);
700
+ } catch (error) {
701
+ console.error("[cron] Failed to recover stale task locks:", error);
702
+ }
703
+ });
704
+ if (typeof globalThis.navigator !== "undefined" && globalThis.navigator.userAgent === "Cloudflare-Workers") cronScheduler = new PiggybackScheduler(cronExecutor);
705
+ else cronScheduler = new NodeCronScheduler(cronExecutor);
706
+ cronScheduler.setSystemCleanup(async () => {
707
+ try {
708
+ await runSystemCleanup(db, storage ?? void 0);
709
+ } catch (error) {
710
+ console.error("[cleanup] System cleanup failed:", error);
711
+ }
712
+ });
713
+ pipeline.setContextFactory({ cronReschedule: () => cronScheduler?.reschedule() });
714
+ await cronScheduler.start();
715
+ } catch (error) {
716
+ console.warn("[cron] Failed to initialize cron system:", error);
717
+ }
718
+ });
719
+ const manifestCacheKey = await hashString([
720
+ COMMIT,
721
+ ...deps.plugins.map((p) => `${p.id}@${p.version ?? ""}`).toSorted(),
722
+ ...deps.sandboxedPluginEntries.map((e) => `${e.id}@${e.version}`).toSorted(),
723
+ virtualConfig?.i18n?.defaultLocale ?? "",
724
+ (virtualConfig?.i18n?.locales ?? []).toSorted().join(",")
725
+ ].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);
681
727
  }
682
728
  /**
683
729
  * Get a media provider by ID
@@ -701,7 +747,7 @@ var EmDashRuntime = class EmDashRuntime {
701
747
  */
702
748
  static async getDatabase(deps) {
703
749
  const ctx = getRequestContext();
704
- if (ctx?.db) return ctx.db;
750
+ if (ctx?.dbIsIsolated && ctx.db) return ctx.db;
705
751
  const dbConfig = deps.config.database;
706
752
  if (!dbConfig) try {
707
753
  return await getDb();
@@ -713,8 +759,14 @@ var EmDashRuntime = class EmDashRuntime {
713
759
  if (cached) return cached;
714
760
  if (dbInitPromise) return dbInitPromise;
715
761
  dbInitPromise = (async () => {
716
- const db = new Kysely({ dialect: deps.createDialect(dbConfig.config) });
717
- await runMigrations(db);
762
+ const db = new Kysely({
763
+ dialect: deps.createDialect(dbConfig.config),
764
+ log: kyselyLogOption()
765
+ });
766
+ const { applied } = await runMigrations(db);
767
+ if (applied.length > 0) try {
768
+ await new OptionsRepository(db).delete("emdash:manifest_cache");
769
+ } catch {}
718
770
  try {
719
771
  const [collectionCount, setupOption] = await Promise.all([db.selectFrom("_emdash_collections").select((eb) => eb.fn.countAll().as("count")).executeTakeFirstOrThrow(), db.selectFrom("options").select("value").where("name", "=", "emdash:setup_complete").executeTakeFirst()]);
720
772
  const setupDone = (() => {
@@ -725,9 +777,9 @@ var EmDashRuntime = class EmDashRuntime {
725
777
  }
726
778
  })();
727
779
  if (collectionCount.count === 0 && !setupDone) {
728
- const { applySeed } = await import("../apply-Cma_PiF6.mjs").then((n) => n.n);
729
- const { loadSeed } = await import("../load-BhSSm-TS.mjs").then((n) => n.r);
730
- const { validateSeed } = await import("../validate-DuZDIxfy.mjs").then((n) => n.n);
780
+ const { applySeed } = await import("../apply-5uslYdUu.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);
731
783
  const seed = await loadSeed();
732
784
  if (validateSeed(seed).valid) {
733
785
  await applySeed(db, seed, { onConflict: "skip" });
@@ -866,9 +918,52 @@ var EmDashRuntime = class EmDashRuntime {
866
918
  });
867
919
  }
868
920
  /**
869
- * Build the manifest (rebuilt on each request for freshness)
921
+ * Get the manifest, using an in-memory cache with a DB-persisted
922
+ * fallback for cold starts. Avoids N+1 schema registry queries
923
+ * on every request.
924
+ *
925
+ * Cache is invalidated by invalidateManifest(), called from schema
926
+ * API routes, MCP server, plugin toggle, and taxonomy def changes.
870
927
  */
871
928
  async getManifest() {
929
+ if (getRequestContext()?.dbIsIsolated) return this._buildManifest();
930
+ if (this._cachedManifest) return this._cachedManifest;
931
+ try {
932
+ const cached = await new OptionsRepository(this.db).get("emdash:manifest_cache");
933
+ if (cached && cached.key === this._manifestCacheKey && cached.manifest) {
934
+ this._cachedManifest = cached.manifest;
935
+ return cached.manifest;
936
+ }
937
+ } catch {}
938
+ if (!this._manifestPromise) {
939
+ let manifestPromise;
940
+ const isCurrentLoad = () => this._manifestPromise === manifestPromise;
941
+ manifestPromise = this._loadManifest(isCurrentLoad);
942
+ this._manifestPromise = manifestPromise;
943
+ }
944
+ return this._manifestPromise;
945
+ }
946
+ async _loadManifest(isCurrentLoad) {
947
+ try {
948
+ const manifest = await this._buildManifest();
949
+ if (isCurrentLoad()) {
950
+ this._cachedManifest = manifest;
951
+ try {
952
+ await new OptionsRepository(this.db).set("emdash:manifest_cache", {
953
+ key: this._manifestCacheKey,
954
+ manifest
955
+ });
956
+ } catch {}
957
+ }
958
+ return manifest;
959
+ } finally {
960
+ if (isCurrentLoad()) this._manifestPromise = null;
961
+ }
962
+ }
963
+ /**
964
+ * Build the manifest from database (N+1 collection queries).
965
+ */
966
+ async _buildManifest() {
872
967
  const manifestCollections = {};
873
968
  try {
874
969
  const registry = new SchemaRegistry(this.db);
@@ -987,10 +1082,62 @@ var EmDashRuntime = class EmDashRuntime {
987
1082
  }
988
1083
  /**
989
1084
  * Invalidate cached data derived from the manifest/schema.
990
- * Called when collections are created, updated, or deleted.
1085
+ * Called when collections, fields, plugins, or taxonomy defs change.
991
1086
  */
992
1087
  invalidateManifest() {
1088
+ this._cachedManifest = null;
1089
+ this._manifestPromise = null;
993
1090
  invalidateUrlPatternCache();
1091
+ try {
1092
+ new OptionsRepository(this.db).delete("emdash:manifest_cache").catch((error) => {
1093
+ console.error("Failed to delete persisted manifest cache", error);
1094
+ });
1095
+ } catch (error) {
1096
+ console.error("Failed to initialize manifest cache invalidation", error);
1097
+ }
1098
+ }
1099
+ /**
1100
+ * Verify and repair FTS indexes on demand. Runs at most once per worker
1101
+ * lifetime.
1102
+ *
1103
+ * Originally called from `EmDashRuntime.create()`, but on a busy D1 link
1104
+ * (e.g. SIN replica ~80-150ms per query) it added ~1.5s to every cold
1105
+ * start for a modest-sized site — more than every other init phase
1106
+ * combined. Anonymous public reads never touch the search write path,
1107
+ * so the cost isn't paid back for the vast majority of requests.
1108
+ *
1109
+ * Instead, search endpoints call this lazily: the first request that
1110
+ * actually needs the index pays the verify cost (usually fast — no
1111
+ * rebuild needed), everyone else runs cold-free.
1112
+ *
1113
+ * Uses the runtime's singleton database (`this._db`) rather than the
1114
+ * request-scoped DB. Verify reads only, but `rebuildIndex` writes, and
1115
+ * a GET search request on D1 carries a `first-unconstrained` session
1116
+ * that's free to route at a read replica — unsafe for writes. The
1117
+ * singleton always goes through the default binding, which the D1
1118
+ * adapter will promote to `first-primary` for write statements.
1119
+ *
1120
+ * Safe to call concurrently: repeated callers share the same in-flight
1121
+ * promise. Errors are swallowed internally so callers don't need to
1122
+ * defend against FTS not existing yet (pre-setup).
1123
+ */
1124
+ async ensureSearchHealthy() {
1125
+ if (this._searchHealthChecked) return;
1126
+ if (this._searchHealthPromise) return this._searchHealthPromise;
1127
+ if (!isSqlite(this._db)) {
1128
+ this._searchHealthChecked = true;
1129
+ return;
1130
+ }
1131
+ this._searchHealthPromise = (async () => {
1132
+ try {
1133
+ const repaired = await new FTSManager(this._db).verifyAndRepairAll();
1134
+ if (repaired > 0) console.log(`Repaired ${repaired} corrupted FTS index(es)`);
1135
+ } catch {} finally {
1136
+ this._searchHealthChecked = true;
1137
+ this._searchHealthPromise = null;
1138
+ }
1139
+ })();
1140
+ return this._searchHealthPromise;
994
1141
  }
995
1142
  async handleContentList(collection, params) {
996
1143
  return handleContentList(this.db, collection, params);
@@ -1016,7 +1163,7 @@ var EmDashRuntime = class EmDashRuntime {
1016
1163
  return result;
1017
1164
  }
1018
1165
  async handleContentUpdate(collection, id, body) {
1019
- const { ContentRepository } = await import("../content-BsBoyj8G.mjs").then((n) => n.n);
1166
+ const { ContentRepository } = await import("../content-D7J5y73J.mjs").then((n) => n.n);
1020
1167
  const repo = new ContentRepository(this.db);
1021
1168
  const resolvedItem = await repo.findByIdOrSlug(collection, id);
1022
1169
  const resolvedId = resolvedItem?.id ?? id;
@@ -1248,7 +1395,8 @@ var EmDashRuntime = class EmDashRuntime {
1248
1395
  if (trustedPlugin && this.enabledPlugins.has(trustedPlugin.id)) {
1249
1396
  const routeRegistry = new PluginRouteRegistry({
1250
1397
  db: this.db,
1251
- emailPipeline: this.email ?? void 0
1398
+ emailPipeline: this.email ?? void 0,
1399
+ trustedProxyHeaders: getTrustedProxyHeaders(this.config)
1252
1400
  });
1253
1401
  routeRegistry.register(trustedPlugin);
1254
1402
  const routeKey = path.replace(LEADING_SLASH_PATTERN, "");
@@ -1391,7 +1539,7 @@ var EmDashRuntime = class EmDashRuntime {
1391
1539
  } catch {}
1392
1540
  try {
1393
1541
  const headers = sanitizeHeadersForSandbox(request.headers);
1394
- const meta = extractRequestMeta(request);
1542
+ const meta = extractRequestMeta(request, this.config);
1395
1543
  return {
1396
1544
  success: true,
1397
1545
  data: await plugin.invokeRoute(routeName, body, {
@@ -1539,18 +1687,23 @@ function buildDependencies(config) {
1539
1687
  };
1540
1688
  }
1541
1689
  /**
1542
- * Get or create the runtime instance
1690
+ * Get or create the runtime instance.
1691
+ *
1692
+ * When `initTimings` is provided, any timing samples recorded during a
1693
+ * genuine cold init are appended. Subsequent warm calls (hitting the
1694
+ * cached instance) push nothing — callers should treat an empty array
1695
+ * as "warm, nothing to report".
1543
1696
  */
1544
- async function getRuntime(config) {
1697
+ async function getRuntime(config, initTimings) {
1545
1698
  if (runtimeInstance) return runtimeInstance;
1546
1699
  if (runtimeInitializing) {
1547
1700
  await new Promise((resolve) => setTimeout(resolve, 50));
1548
- return getRuntime(config);
1701
+ return getRuntime(config, initTimings);
1549
1702
  }
1550
1703
  runtimeInitializing = true;
1551
1704
  try {
1552
1705
  const deps = buildDependencies(config);
1553
- const runtime = await EmDashRuntime.create(deps);
1706
+ const runtime = await EmDashRuntime.create(deps, initTimings);
1554
1707
  runtimeInstance = runtime;
1555
1708
  return runtime;
1556
1709
  } finally {
@@ -1558,142 +1711,270 @@ async function getRuntime(config) {
1558
1711
  }
1559
1712
  }
1560
1713
  /**
1714
+ * Astro attaches AstroCookies to outgoing responses via a well-known global
1715
+ * symbol. Cloning a Response (`new Response(body, init)`) drops non-header
1716
+ * metadata, so any middleware that wraps the response must explicitly forward
1717
+ * this symbol or `cookies.set()` calls will be silently dropped.
1718
+ */
1719
+ const ASTRO_COOKIES_SYMBOL = Symbol.for("astro.cookies");
1720
+ /**
1561
1721
  * Baseline security headers applied to all responses.
1562
1722
  * Admin routes get additional headers (strict CSP) from auth middleware.
1563
1723
  */
1564
- function setBaselineSecurityHeaders(response) {
1724
+ function finalizeResponse(response, serverTimings) {
1565
1725
  const res = new Response(response.body, response);
1726
+ const astroCookies = Reflect.get(response, ASTRO_COOKIES_SYMBOL);
1727
+ if (astroCookies !== void 0) Reflect.set(res, ASTRO_COOKIES_SYMBOL, astroCookies);
1566
1728
  res.headers.set("X-Content-Type-Options", "nosniff");
1567
1729
  res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
1568
1730
  res.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=()");
1569
1731
  if (!res.headers.has("Content-Security-Policy")) res.headers.set("X-Frame-Options", "SAMEORIGIN");
1732
+ if (serverTimings && serverTimings.length > 0) res.headers.set("Server-Timing", serverTimings.map((t) => {
1733
+ const dur = Math.round(t.dur);
1734
+ return t.desc ? `${t.name};dur=${dur};desc="${t.desc}"` : `${t.name};dur=${dur}`;
1735
+ }).join(", "));
1570
1736
  return res;
1571
1737
  }
1572
1738
  /** Public routes that require the runtime (sitemap, robots.txt, etc.) */
1573
1739
  const PUBLIC_RUNTIME_ROUTES = new Set(["/sitemap.xml", "/robots.txt"]);
1574
1740
  const SITEMAP_COLLECTION_RE = /^\/sitemap-[a-z][a-z0-9_]*\.xml$/;
1741
+ /**
1742
+ * Ask the configured database adapter for a per-request scoped Kysely. The
1743
+ * adapter encapsulates any per-request semantics (D1 sessions, read-replica
1744
+ * routing, bookmark cookies, etc.); core just forwards the cookie jar and
1745
+ * request flags and wraps next() in ALS if a scope was returned.
1746
+ */
1747
+ function createRequestScopedDb$1(opts) {
1748
+ if (typeof createRequestScopedDb !== "function") return null;
1749
+ return createRequestScopedDb(opts);
1750
+ }
1575
1751
  const onRequest = defineMiddleware(async (context, next) => {
1576
1752
  const { request, locals, cookies } = context;
1577
1753
  const url = context.url;
1578
- const isEmDashRoute = url.pathname.startsWith("/_emdash");
1579
- const isPublicRuntimeRoute = PUBLIC_RUNTIME_ROUTES.has(url.pathname) || SITEMAP_COLLECTION_RE.test(url.pathname);
1580
- const hasEditCookie = cookies.get("emdash-edit-mode")?.value === "true";
1581
- const hasPreviewToken = url.searchParams.has("_preview");
1582
- const playgroundDb = locals.__playgroundDb;
1583
- if (!isEmDashRoute && !isPublicRuntimeRoute && !hasEditCookie && !hasPreviewToken) {
1584
- if (!(context.isPrerendered ? null : await context.session?.get("user")) && !playgroundDb) {
1585
- if (!setupVerified) try {
1586
- const { getDb } = await import("../loader-BYzwzORf.mjs").then((n) => n.r);
1587
- await (await getDb()).selectFrom("_emdash_migrations").selectAll().limit(1).execute();
1588
- setupVerified = true;
1589
- } catch {
1590
- return context.redirect("/_emdash/admin/setup");
1754
+ const queryRecorder = isInstrumentationEnabled() ? createRecorder(url.pathname, request.method, request.headers.get("x-perf-phase") ?? "default") : void 0;
1755
+ const run = async () => {
1756
+ const isEmDashRoute = url.pathname.startsWith("/_emdash");
1757
+ const isPublicRuntimeRoute = PUBLIC_RUNTIME_ROUTES.has(url.pathname) || SITEMAP_COLLECTION_RE.test(url.pathname);
1758
+ const hasEditCookie = cookies.get("emdash-edit-mode")?.value === "true";
1759
+ const hasPreviewToken = url.searchParams.has("_preview");
1760
+ const playgroundDb = locals.__playgroundDb;
1761
+ const sessionUser = context.isPrerendered ? null : await context.session?.get("user");
1762
+ if (!isEmDashRoute && !isPublicRuntimeRoute && !hasEditCookie && !hasPreviewToken) {
1763
+ if (!sessionUser && !playgroundDb) {
1764
+ const timings = [];
1765
+ const mwStart = performance.now();
1766
+ if (!setupVerified) {
1767
+ const t0 = performance.now();
1768
+ try {
1769
+ const { getDb } = await import("../loader-DeiBJEMe.mjs").then((n) => n.r);
1770
+ await (await getDb()).selectFrom("_emdash_migrations").selectAll().limit(1).execute();
1771
+ setupVerified = true;
1772
+ } catch {
1773
+ return context.redirect("/_emdash/admin/setup");
1774
+ }
1775
+ timings.push({
1776
+ name: "setup",
1777
+ dur: performance.now() - t0,
1778
+ desc: "Setup probe"
1779
+ });
1780
+ }
1781
+ const config = getConfig();
1782
+ if (config) {
1783
+ const initSubTimings = [];
1784
+ const t0 = performance.now();
1785
+ try {
1786
+ const runtime = await getRuntime(config, initSubTimings);
1787
+ setupVerified = true;
1788
+ locals.emdash = {
1789
+ collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
1790
+ collectPageFragments: runtime.collectPageFragments.bind(runtime)
1791
+ };
1792
+ } catch {}
1793
+ timings.push({
1794
+ name: "rt",
1795
+ dur: performance.now() - t0,
1796
+ desc: "Runtime init"
1797
+ });
1798
+ for (const sub of initSubTimings) timings.push(sub);
1799
+ }
1800
+ const anonScoped = createRequestScopedDb$1({
1801
+ config: config?.database?.config,
1802
+ isAuthenticated: false,
1803
+ isWrite: request.method !== "GET" && request.method !== "HEAD",
1804
+ cookies,
1805
+ url
1806
+ });
1807
+ const runAnon = async () => {
1808
+ const t0 = performance.now();
1809
+ const response = await next();
1810
+ timings.push({
1811
+ name: "render",
1812
+ dur: performance.now() - t0,
1813
+ desc: "Page render"
1814
+ });
1815
+ timings.push({
1816
+ name: "mw",
1817
+ dur: performance.now() - mwStart,
1818
+ desc: "Total middleware"
1819
+ });
1820
+ return finalizeResponse(response, timings);
1821
+ };
1822
+ if (anonScoped) {
1823
+ const parent = getRequestContext();
1824
+ return runWithContext(parent ? {
1825
+ ...parent,
1826
+ db: anonScoped.db
1827
+ } : {
1828
+ editMode: false,
1829
+ db: anonScoped.db
1830
+ }, async () => {
1831
+ const response = await runAnon();
1832
+ anonScoped.commit();
1833
+ return response;
1834
+ });
1835
+ }
1836
+ return runAnon();
1591
1837
  }
1592
- const config = getConfig();
1593
- if (config) try {
1594
- const runtime = await getRuntime(config);
1838
+ }
1839
+ const config = getConfig();
1840
+ if (!config) {
1841
+ console.error("EmDash: No configuration found");
1842
+ return finalizeResponse(await next());
1843
+ }
1844
+ const doInit = async () => {
1845
+ const timings = [];
1846
+ const mwStart = performance.now();
1847
+ try {
1848
+ const initSubTimings = [];
1849
+ let t0 = performance.now();
1850
+ const runtime = await getRuntime(config, initSubTimings);
1851
+ timings.push({
1852
+ name: "rt",
1853
+ dur: performance.now() - t0,
1854
+ desc: "Runtime init"
1855
+ });
1856
+ for (const sub of initSubTimings) timings.push(sub);
1595
1857
  setupVerified = true;
1858
+ t0 = performance.now();
1859
+ const manifest = await runtime.getManifest();
1860
+ timings.push({
1861
+ name: "manifest",
1862
+ dur: performance.now() - t0,
1863
+ desc: "Manifest"
1864
+ });
1865
+ locals.emdashManifest = manifest;
1596
1866
  locals.emdash = {
1867
+ handleContentList: runtime.handleContentList.bind(runtime),
1868
+ handleContentGet: runtime.handleContentGet.bind(runtime),
1869
+ handleContentCreate: runtime.handleContentCreate.bind(runtime),
1870
+ handleContentUpdate: runtime.handleContentUpdate.bind(runtime),
1871
+ handleContentDelete: runtime.handleContentDelete.bind(runtime),
1872
+ handleContentListTrashed: runtime.handleContentListTrashed.bind(runtime),
1873
+ handleContentRestore: runtime.handleContentRestore.bind(runtime),
1874
+ handleContentPermanentDelete: runtime.handleContentPermanentDelete.bind(runtime),
1875
+ handleContentCountTrashed: runtime.handleContentCountTrashed.bind(runtime),
1876
+ handleContentGetIncludingTrashed: runtime.handleContentGetIncludingTrashed.bind(runtime),
1877
+ handleContentDuplicate: runtime.handleContentDuplicate.bind(runtime),
1878
+ handleContentPublish: runtime.handleContentPublish.bind(runtime),
1879
+ handleContentUnpublish: runtime.handleContentUnpublish.bind(runtime),
1880
+ handleContentSchedule: runtime.handleContentSchedule.bind(runtime),
1881
+ handleContentUnschedule: runtime.handleContentUnschedule.bind(runtime),
1882
+ handleContentCountScheduled: runtime.handleContentCountScheduled.bind(runtime),
1883
+ handleContentDiscardDraft: runtime.handleContentDiscardDraft.bind(runtime),
1884
+ handleContentCompare: runtime.handleContentCompare.bind(runtime),
1885
+ handleContentTranslations: runtime.handleContentTranslations.bind(runtime),
1886
+ handleMediaList: runtime.handleMediaList.bind(runtime),
1887
+ handleMediaGet: runtime.handleMediaGet.bind(runtime),
1888
+ handleMediaCreate: runtime.handleMediaCreate.bind(runtime),
1889
+ handleMediaUpdate: runtime.handleMediaUpdate.bind(runtime),
1890
+ handleMediaDelete: runtime.handleMediaDelete.bind(runtime),
1891
+ handleRevisionList: runtime.handleRevisionList.bind(runtime),
1892
+ handleRevisionGet: runtime.handleRevisionGet.bind(runtime),
1893
+ handleRevisionRestore: runtime.handleRevisionRestore.bind(runtime),
1894
+ handlePluginApiRoute: runtime.handlePluginApiRoute.bind(runtime),
1895
+ getPluginRouteMeta: runtime.getPluginRouteMeta.bind(runtime),
1896
+ getMediaProvider: runtime.getMediaProvider.bind(runtime),
1897
+ getMediaProviderList: runtime.getMediaProviderList.bind(runtime),
1597
1898
  collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
1598
- collectPageFragments: runtime.collectPageFragments.bind(runtime)
1899
+ collectPageFragments: runtime.collectPageFragments.bind(runtime),
1900
+ ensureSearchHealthy: runtime.ensureSearchHealthy.bind(runtime),
1901
+ storage: runtime.storage,
1902
+ db: runtime.db,
1903
+ hooks: runtime.hooks,
1904
+ email: runtime.email,
1905
+ configuredPlugins: runtime.configuredPlugins,
1906
+ config,
1907
+ invalidateManifest: runtime.invalidateManifest.bind(runtime),
1908
+ getSandboxRunner: runtime.getSandboxRunner.bind(runtime),
1909
+ syncMarketplacePlugins: runtime.syncMarketplacePlugins.bind(runtime),
1910
+ setPluginStatus: runtime.setPluginStatus.bind(runtime)
1599
1911
  };
1600
- } catch {}
1601
- return setBaselineSecurityHeaders(await next());
1602
- }
1603
- }
1604
- const config = getConfig();
1605
- if (!config) {
1606
- console.error("EmDash: No configuration found");
1607
- return next();
1608
- }
1609
- const doInit = async () => {
1610
- try {
1611
- const runtime = await getRuntime(config);
1612
- setupVerified = true;
1613
- locals.emdashManifest = await runtime.getManifest();
1614
- locals.emdash = {
1615
- handleContentList: runtime.handleContentList.bind(runtime),
1616
- handleContentGet: runtime.handleContentGet.bind(runtime),
1617
- handleContentCreate: runtime.handleContentCreate.bind(runtime),
1618
- handleContentUpdate: runtime.handleContentUpdate.bind(runtime),
1619
- handleContentDelete: runtime.handleContentDelete.bind(runtime),
1620
- handleContentListTrashed: runtime.handleContentListTrashed.bind(runtime),
1621
- handleContentRestore: runtime.handleContentRestore.bind(runtime),
1622
- handleContentPermanentDelete: runtime.handleContentPermanentDelete.bind(runtime),
1623
- handleContentCountTrashed: runtime.handleContentCountTrashed.bind(runtime),
1624
- handleContentGetIncludingTrashed: runtime.handleContentGetIncludingTrashed.bind(runtime),
1625
- handleContentDuplicate: runtime.handleContentDuplicate.bind(runtime),
1626
- handleContentPublish: runtime.handleContentPublish.bind(runtime),
1627
- handleContentUnpublish: runtime.handleContentUnpublish.bind(runtime),
1628
- handleContentSchedule: runtime.handleContentSchedule.bind(runtime),
1629
- handleContentUnschedule: runtime.handleContentUnschedule.bind(runtime),
1630
- handleContentCountScheduled: runtime.handleContentCountScheduled.bind(runtime),
1631
- handleContentDiscardDraft: runtime.handleContentDiscardDraft.bind(runtime),
1632
- handleContentCompare: runtime.handleContentCompare.bind(runtime),
1633
- handleContentTranslations: runtime.handleContentTranslations.bind(runtime),
1634
- handleMediaList: runtime.handleMediaList.bind(runtime),
1635
- handleMediaGet: runtime.handleMediaGet.bind(runtime),
1636
- handleMediaCreate: runtime.handleMediaCreate.bind(runtime),
1637
- handleMediaUpdate: runtime.handleMediaUpdate.bind(runtime),
1638
- handleMediaDelete: runtime.handleMediaDelete.bind(runtime),
1639
- handleRevisionList: runtime.handleRevisionList.bind(runtime),
1640
- handleRevisionGet: runtime.handleRevisionGet.bind(runtime),
1641
- handleRevisionRestore: runtime.handleRevisionRestore.bind(runtime),
1642
- handlePluginApiRoute: runtime.handlePluginApiRoute.bind(runtime),
1643
- getPluginRouteMeta: runtime.getPluginRouteMeta.bind(runtime),
1644
- getMediaProvider: runtime.getMediaProvider.bind(runtime),
1645
- getMediaProviderList: runtime.getMediaProviderList.bind(runtime),
1646
- collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
1647
- collectPageFragments: runtime.collectPageFragments.bind(runtime),
1648
- storage: runtime.storage,
1649
- db: runtime.db,
1650
- hooks: runtime.hooks,
1651
- email: runtime.email,
1652
- configuredPlugins: runtime.configuredPlugins,
1653
- config,
1654
- invalidateManifest: runtime.invalidateManifest.bind(runtime),
1655
- getSandboxRunner: runtime.getSandboxRunner.bind(runtime),
1656
- syncMarketplacePlugins: runtime.syncMarketplacePlugins.bind(runtime),
1657
- setPluginStatus: runtime.setPluginStatus.bind(runtime)
1912
+ } catch (error) {
1913
+ console.error("EmDash middleware error:", error);
1914
+ }
1915
+ const scoped = createRequestScopedDb$1({
1916
+ config: config?.database?.config,
1917
+ isAuthenticated: !!sessionUser,
1918
+ isWrite: request.method !== "GET" && request.method !== "HEAD",
1919
+ cookies: context.cookies,
1920
+ url
1921
+ });
1922
+ const renderAndFinalize = async () => {
1923
+ const t0 = performance.now();
1924
+ const response = await next();
1925
+ timings.push({
1926
+ name: "render",
1927
+ dur: performance.now() - t0,
1928
+ desc: "Page render"
1929
+ });
1930
+ timings.push({
1931
+ name: "mw",
1932
+ dur: performance.now() - mwStart,
1933
+ desc: "Total middleware"
1934
+ });
1935
+ return finalizeResponse(response, timings);
1658
1936
  };
1659
- } catch (error) {
1660
- console.error("EmDash middleware error:", error);
1661
- }
1662
- const dbConfig = config?.database?.config;
1663
- if (dbConfig && typeof isSessionEnabled === "function" && isSessionEnabled(dbConfig) && typeof getD1Binding === "function" && createSessionDialect) {
1664
- const d1Binding = getD1Binding(dbConfig);
1665
- if (d1Binding && typeof d1Binding === "object" && "withSession" in d1Binding) {
1666
- const isAuthenticated = context.isPrerendered ? false : !!await context.session?.get("user");
1667
- const isWrite = request.method !== "GET" && request.method !== "HEAD";
1668
- const configConstraint = getDefaultConstraint(dbConfig);
1669
- const cookieName = getBookmarkCookieName(dbConfig);
1670
- let constraint = configConstraint;
1671
- if (isAuthenticated && isWrite) constraint = "first-primary";
1672
- else if (isAuthenticated) {
1673
- const bookmarkCookie = context.cookies.get(cookieName);
1674
- if (bookmarkCookie?.value) constraint = bookmarkCookie.value;
1675
- }
1676
- const session = d1Binding.withSession.call(d1Binding, constraint);
1677
- return runWithContext({
1937
+ if (scoped) {
1938
+ const parent = getRequestContext();
1939
+ return runWithContext(parent ? {
1940
+ ...parent,
1941
+ db: scoped.db
1942
+ } : {
1678
1943
  editMode: false,
1679
- db: new Kysely({ dialect: createSessionDialect(session) })
1944
+ db: scoped.db
1680
1945
  }, async () => {
1681
- const response = setBaselineSecurityHeaders(await next());
1682
- if (isAuthenticated && session && typeof session === "object" && "getBookmark" in session) {
1683
- const newBookmark = session.getBookmark.call(session);
1684
- if (newBookmark) response.headers.append("Set-Cookie", `${cookieName}=${newBookmark}; Path=/; HttpOnly; SameSite=Lax; Secure`);
1685
- }
1946
+ const response = await renderAndFinalize();
1947
+ scoped.commit();
1686
1948
  return response;
1687
1949
  });
1688
1950
  }
1951
+ return renderAndFinalize();
1952
+ };
1953
+ if (playgroundDb) {
1954
+ const editMode = context.cookies.get("emdash-edit-mode")?.value === "true";
1955
+ const parent = getRequestContext();
1956
+ return runWithContext(parent ? {
1957
+ ...parent,
1958
+ editMode,
1959
+ db: playgroundDb,
1960
+ dbIsIsolated: true
1961
+ } : {
1962
+ editMode,
1963
+ db: playgroundDb,
1964
+ dbIsIsolated: true
1965
+ }, doInit);
1689
1966
  }
1690
- return setBaselineSecurityHeaders(await next());
1967
+ return doInit();
1691
1968
  };
1692
- if (playgroundDb) return runWithContext({
1693
- editMode: context.cookies.get("emdash-edit-mode")?.value === "true",
1694
- db: playgroundDb
1695
- }, doInit);
1696
- return doInit();
1969
+ if (queryRecorder) try {
1970
+ return await runWithContext({
1971
+ editMode: false,
1972
+ queryRecorder
1973
+ }, run);
1974
+ } finally {
1975
+ flushRecorder(queryRecorder);
1976
+ }
1977
+ return run();
1697
1978
  });
1698
1979
 
1699
1980
  //#endregion