emdash 0.7.0 → 0.9.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 (354) hide show
  1. package/dist/{adapters-Di31kZ28.d.mts → adapters-DoNJiveC.d.mts} +1 -1
  2. package/dist/{adapters-Di31kZ28.d.mts.map → adapters-DoNJiveC.d.mts.map} +1 -1
  3. package/dist/{apply-5uslYdUu.mjs → apply-BzltprvY.mjs} +90 -139
  4. package/dist/apply-BzltprvY.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 +194 -17
  8. package/dist/astro/index.mjs.map +1 -1
  9. package/dist/astro/middleware/auth.d.mts +6 -7
  10. package/dist/astro/middleware/auth.d.mts.map +1 -1
  11. package/dist/astro/middleware/auth.mjs +34 -57
  12. package/dist/astro/middleware/auth.mjs.map +1 -1
  13. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  14. package/dist/astro/middleware/redirect.mjs +17 -12
  15. package/dist/astro/middleware/redirect.mjs.map +1 -1
  16. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  17. package/dist/astro/middleware/request-context.mjs +9 -6
  18. package/dist/astro/middleware/request-context.mjs.map +1 -1
  19. package/dist/astro/middleware/setup.mjs +1 -1
  20. package/dist/astro/middleware.d.mts.map +1 -1
  21. package/dist/astro/middleware.mjs +301 -165
  22. package/dist/astro/middleware.mjs.map +1 -1
  23. package/dist/astro/types.d.mts +34 -10
  24. package/dist/astro/types.d.mts.map +1 -1
  25. package/dist/{base64-MBPo9ozB.mjs → base64-BRICGH2l.mjs} +1 -1
  26. package/dist/{base64-MBPo9ozB.mjs.map → base64-BRICGH2l.mjs.map} +1 -1
  27. package/dist/{byline-C4OVd8b3.mjs → byline-BSaNL1w7.mjs} +5 -5
  28. package/dist/byline-BSaNL1w7.mjs.map +1 -0
  29. package/dist/bylines-CvJ3PYz2.mjs +113 -0
  30. package/dist/bylines-CvJ3PYz2.mjs.map +1 -0
  31. package/dist/cache-C6N_hhN7.mjs +65 -0
  32. package/dist/cache-C6N_hhN7.mjs.map +1 -0
  33. package/dist/{chunks-HGz06Soa.mjs → chunks-NBQVDOci.mjs} +8 -2
  34. package/dist/{chunks-HGz06Soa.mjs.map → chunks-NBQVDOci.mjs.map} +1 -1
  35. package/dist/cli/index.mjs +229 -31
  36. package/dist/cli/index.mjs.map +1 -1
  37. package/dist/client/cf-access.d.mts +1 -1
  38. package/dist/client/index.d.mts +1 -1
  39. package/dist/client/index.mjs +3 -3
  40. package/dist/client/index.mjs.map +1 -1
  41. package/dist/{config-BXwuX8Bx.mjs → config-BI0V3ICQ.mjs} +1 -1
  42. package/dist/{config-BXwuX8Bx.mjs.map → config-BI0V3ICQ.mjs.map} +1 -1
  43. package/dist/{content-D7J5y73J.mjs → content-8lOYF0pr.mjs} +43 -28
  44. package/dist/content-8lOYF0pr.mjs.map +1 -0
  45. package/dist/db/index.d.mts +3 -3
  46. package/dist/db/index.mjs +2 -2
  47. package/dist/db/libsql.d.mts +1 -1
  48. package/dist/db/libsql.d.mts.map +1 -1
  49. package/dist/db/libsql.mjs +7 -2
  50. package/dist/db/libsql.mjs.map +1 -1
  51. package/dist/db/postgres.d.mts +1 -1
  52. package/dist/db/sqlite.d.mts +1 -1
  53. package/dist/db/sqlite.d.mts.map +1 -1
  54. package/dist/db/sqlite.mjs +8 -3
  55. package/dist/db/sqlite.mjs.map +1 -1
  56. package/dist/{db-errors-D0UT85nC.mjs → db-errors-WRezodiz.mjs} +1 -1
  57. package/dist/{db-errors-D0UT85nC.mjs.map → db-errors-WRezodiz.mjs.map} +1 -1
  58. package/dist/{default-CME5YdZ3.mjs → default-D8ksjWhO.mjs} +1 -1
  59. package/dist/{default-CME5YdZ3.mjs.map → default-D8ksjWhO.mjs.map} +1 -1
  60. package/dist/{dialect-helpers-DhTzaUxP.mjs → dialect-helpers-BKCvISIQ.mjs} +19 -2
  61. package/dist/dialect-helpers-BKCvISIQ.mjs.map +1 -0
  62. package/dist/{error-CiYn9yDu.mjs → error-D_-tqP-I.mjs} +1 -1
  63. package/dist/error-D_-tqP-I.mjs.map +1 -0
  64. package/dist/{index-De6_Xv3v.d.mts → index-BFRaVcD6.d.mts} +243 -40
  65. package/dist/index-BFRaVcD6.d.mts.map +1 -0
  66. package/dist/index.d.mts +11 -11
  67. package/dist/index.mjs +29 -25
  68. package/dist/{load-CBcmDIot.mjs → load-DDqMMvZL.mjs} +2 -2
  69. package/dist/{load-CBcmDIot.mjs.map → load-DDqMMvZL.mjs.map} +1 -1
  70. package/dist/{loader-DeiBJEMe.mjs → loader-CKLbBnhK.mjs} +32 -10
  71. package/dist/loader-CKLbBnhK.mjs.map +1 -0
  72. package/dist/{manifest-schema-V30qsMft.mjs → manifest-schema-DqWNC3lM.mjs} +45 -3
  73. package/dist/manifest-schema-DqWNC3lM.mjs.map +1 -0
  74. package/dist/media/index.d.mts +1 -1
  75. package/dist/media/index.mjs +1 -1
  76. package/dist/media/local-runtime.d.mts +7 -7
  77. package/dist/media/local-runtime.mjs +3 -3
  78. package/dist/{media-DqHVh136.mjs → media-BW32b4gi.mjs} +4 -7
  79. package/dist/media-BW32b4gi.mjs.map +1 -0
  80. package/dist/{mode-CpNnGkPz.mjs → mode-ier8jbBk.mjs} +1 -1
  81. package/dist/mode-ier8jbBk.mjs.map +1 -0
  82. package/dist/options-BVp3UsTS.mjs +117 -0
  83. package/dist/options-BVp3UsTS.mjs.map +1 -0
  84. package/dist/page/index.d.mts +2 -2
  85. package/dist/{placeholder-tzpqGWII.d.mts → placeholder-BE4o_2dc.d.mts} +1 -1
  86. package/dist/{placeholder-tzpqGWII.d.mts.map → placeholder-BE4o_2dc.d.mts.map} +1 -1
  87. package/dist/{placeholder-C-fk5hYI.mjs → placeholder-CIJejMlK.mjs} +1 -1
  88. package/dist/placeholder-CIJejMlK.mjs.map +1 -0
  89. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  90. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  91. package/dist/plugins/adapt-sandbox-entry.mjs +6 -5
  92. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  93. package/dist/public-url-DByxYjUw.mjs +51 -0
  94. package/dist/public-url-DByxYjUw.mjs.map +1 -0
  95. package/dist/{query-g4Ug-9j9.mjs → query-Cg9ZKRQ0.mjs} +114 -16
  96. package/dist/query-Cg9ZKRQ0.mjs.map +1 -0
  97. package/dist/{redirect-CN0Rt9Ob.mjs → redirect-BhUBKRc1.mjs} +13 -8
  98. package/dist/redirect-BhUBKRc1.mjs.map +1 -0
  99. package/dist/{registry-Ci3WxVAr.mjs → registry-Dw70ChxB.mjs} +69 -11
  100. package/dist/registry-Dw70ChxB.mjs.map +1 -0
  101. package/dist/{request-cache-DiR961CV.mjs → request-cache-B-bmkipQ.mjs} +1 -1
  102. package/dist/request-cache-B-bmkipQ.mjs.map +1 -0
  103. package/dist/runner-Bnoj7vjK.d.mts +44 -0
  104. package/dist/runner-Bnoj7vjK.d.mts.map +1 -0
  105. package/dist/{runner-tQ7BJ4T7.mjs → runner-C7ADox5q.mjs} +185 -55
  106. package/dist/{runner-tQ7BJ4T7.mjs.map → runner-C7ADox5q.mjs.map} +1 -1
  107. package/dist/runtime.d.mts +6 -6
  108. package/dist/runtime.mjs +4 -4
  109. package/dist/{search-B0effn3j.mjs → search-dOGEccMa.mjs} +341 -152
  110. package/dist/search-dOGEccMa.mjs.map +1 -0
  111. package/dist/secrets-CW3reAnU.mjs +314 -0
  112. package/dist/secrets-CW3reAnU.mjs.map +1 -0
  113. package/dist/seed/index.d.mts +2 -2
  114. package/dist/seed/index.mjs +15 -14
  115. package/dist/seo/index.d.mts +1 -1
  116. package/dist/storage/local.d.mts +1 -1
  117. package/dist/storage/local.mjs +1 -1
  118. package/dist/storage/s3.d.mts +1 -1
  119. package/dist/storage/s3.d.mts.map +1 -1
  120. package/dist/storage/s3.mjs +4 -4
  121. package/dist/storage/s3.mjs.map +1 -1
  122. package/dist/{taxonomies-K2z0Uhnj.mjs → taxonomies-ZlRtD6AG.mjs} +14 -7
  123. package/dist/taxonomies-ZlRtD6AG.mjs.map +1 -0
  124. package/dist/{tokens-BFPFx3CA.mjs → tokens-D7zMmWi2.mjs} +2 -2
  125. package/dist/{tokens-BFPFx3CA.mjs.map → tokens-D7zMmWi2.mjs.map} +1 -1
  126. package/dist/{transport-BykRfpyy.mjs → transport-BeMCmin1.mjs} +6 -5
  127. package/dist/{transport-BykRfpyy.mjs.map → transport-BeMCmin1.mjs.map} +1 -1
  128. package/dist/{transport-H4Iwx7tC.d.mts → transport-DNEfeMaU.d.mts} +1 -1
  129. package/dist/{transport-H4Iwx7tC.d.mts.map → transport-DNEfeMaU.d.mts.map} +1 -1
  130. package/dist/types-4fVtCIm0.mjs +68 -0
  131. package/dist/types-4fVtCIm0.mjs.map +1 -0
  132. package/dist/{types-CnZYHyLW.d.mts → types-BSyXeCFW.d.mts} +24 -2
  133. package/dist/{types-CnZYHyLW.d.mts.map → types-BSyXeCFW.d.mts.map} +1 -1
  134. package/dist/{types-DgrIP0tF.d.mts → types-BuBIptGk.d.mts} +80 -106
  135. package/dist/types-BuBIptGk.d.mts.map +1 -0
  136. package/dist/{types-BH2L167P.mjs → types-CDbKp7ND.mjs} +1 -1
  137. package/dist/{types-BH2L167P.mjs.map → types-CDbKp7ND.mjs.map} +1 -1
  138. package/dist/{types-DDS4MxsT.mjs → types-CIOg5AR8.mjs} +1 -1
  139. package/dist/{types-DDS4MxsT.mjs.map → types-CIOg5AR8.mjs.map} +1 -1
  140. package/dist/{types-6CUZRrZP.d.mts → types-CJsYGpco.d.mts} +24 -2
  141. package/dist/{types-6CUZRrZP.d.mts.map → types-CJsYGpco.d.mts.map} +1 -1
  142. package/dist/types-CRxNbK-Z.mjs +68 -0
  143. package/dist/types-CRxNbK-Z.mjs.map +1 -0
  144. package/dist/{types-C2v0c34j.d.mts → types-CrtWgIvl.d.mts} +1 -1
  145. package/dist/{types-C2v0c34j.d.mts.map → types-CrtWgIvl.d.mts.map} +1 -1
  146. package/dist/{types-CFWjXmus.d.mts → types-M78DQ1lx.d.mts} +1 -1
  147. package/dist/{types-CFWjXmus.d.mts.map → types-M78DQ1lx.d.mts.map} +1 -1
  148. package/dist/{validate-CqsNItbt.mjs → validate-Baqf0slj.mjs} +3 -3
  149. package/dist/{validate-CqsNItbt.mjs.map → validate-Baqf0slj.mjs.map} +1 -1
  150. package/dist/{validate-kM8Pjuf7.d.mts → validate-BfQh_C_y.d.mts} +4 -4
  151. package/dist/{validate-kM8Pjuf7.d.mts.map → validate-BfQh_C_y.d.mts.map} +1 -1
  152. package/dist/validation-BfEI7tNe.mjs +144 -0
  153. package/dist/validation-BfEI7tNe.mjs.map +1 -0
  154. package/dist/version-DoxrVdYf.mjs +7 -0
  155. package/dist/{version-BnTKdfam.mjs.map → version-DoxrVdYf.mjs.map} +1 -1
  156. package/dist/zod-generator-CC0xNe_K.mjs +132 -0
  157. package/dist/zod-generator-CC0xNe_K.mjs.map +1 -0
  158. package/locals.d.ts +1 -6
  159. package/package.json +21 -7
  160. package/src/api/auth-storage.ts +37 -0
  161. package/src/api/error.ts +6 -0
  162. package/src/api/errors.ts +8 -0
  163. package/src/api/handlers/comments.ts +19 -4
  164. package/src/api/handlers/content.ts +151 -4
  165. package/src/api/handlers/device-flow.ts +5 -0
  166. package/src/api/handlers/index.ts +2 -0
  167. package/src/api/handlers/marketplace.ts +11 -4
  168. package/src/api/handlers/media.ts +8 -1
  169. package/src/api/handlers/menus.ts +160 -21
  170. package/src/api/handlers/oauth-authorization.ts +72 -33
  171. package/src/api/handlers/redirects.ts +16 -3
  172. package/src/api/handlers/revision.ts +23 -14
  173. package/src/api/handlers/sections.ts +8 -1
  174. package/src/api/handlers/taxonomies.ts +131 -22
  175. package/src/api/handlers/validation.ts +212 -0
  176. package/src/api/openapi/document.ts +4 -1
  177. package/src/api/public-url.ts +54 -5
  178. package/src/api/route-utils.ts +14 -0
  179. package/src/api/schemas/comments.ts +2 -2
  180. package/src/api/schemas/common.ts +1 -1
  181. package/src/api/schemas/content.ts +17 -0
  182. package/src/api/schemas/sections.ts +3 -3
  183. package/src/api/schemas/setup.ts +8 -0
  184. package/src/api/schemas/users.ts +1 -1
  185. package/src/api/schemas/widgets.ts +12 -10
  186. package/src/api/setup-complete.ts +40 -0
  187. package/src/api/types.ts +5 -1
  188. package/src/astro/integration/index.ts +30 -2
  189. package/src/astro/integration/routes.ts +28 -0
  190. package/src/astro/integration/runtime.ts +49 -1
  191. package/src/astro/integration/virtual-modules.ts +73 -2
  192. package/src/astro/integration/vite-config.ts +49 -13
  193. package/src/astro/middleware/auth.ts +34 -6
  194. package/src/astro/middleware/redirect.ts +29 -16
  195. package/src/astro/middleware/request-context.ts +15 -5
  196. package/src/astro/middleware.ts +41 -10
  197. package/src/astro/routes/PluginRegistry.tsx +10 -1
  198. package/src/astro/routes/api/auth/invite/complete.ts +6 -1
  199. package/src/astro/routes/api/auth/mode.ts +57 -0
  200. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +23 -3
  201. package/src/astro/routes/api/auth/oauth/[provider].ts +10 -4
  202. package/src/astro/routes/api/auth/passkey/register/verify.ts +6 -1
  203. package/src/astro/routes/api/auth/passkey/verify.ts +6 -1
  204. package/src/astro/routes/api/auth/signup/complete.ts +6 -1
  205. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -2
  206. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  207. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +34 -12
  208. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +32 -2
  209. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +4 -2
  210. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -2
  211. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +8 -4
  212. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
  213. package/src/astro/routes/api/content/[collection]/[id].ts +12 -0
  214. package/src/astro/routes/api/content/[collection]/index.ts +1 -9
  215. package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
  216. package/src/astro/routes/api/import/wordpress/media.ts +2 -7
  217. package/src/astro/routes/api/import/wordpress/prepare.ts +9 -0
  218. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -1
  219. package/src/astro/routes/api/manifest.ts +62 -45
  220. package/src/astro/routes/api/media/[id]/confirm.ts +10 -1
  221. package/src/astro/routes/api/media/providers/[providerId]/index.ts +12 -3
  222. package/src/astro/routes/api/openapi.json.ts +27 -10
  223. package/src/astro/routes/api/redirects/404s/index.ts +10 -4
  224. package/src/astro/routes/api/redirects/404s/summary.ts +4 -2
  225. package/src/astro/routes/api/redirects/[id].ts +10 -4
  226. package/src/astro/routes/api/redirects/index.ts +7 -3
  227. package/src/astro/routes/api/revisions/[revisionId]/index.ts +1 -1
  228. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +0 -2
  229. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +0 -1
  230. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +0 -1
  231. package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -2
  232. package/src/astro/routes/api/schema/collections/index.ts +1 -1
  233. package/src/astro/routes/api/search/index.ts +10 -2
  234. package/src/astro/routes/api/sections/[slug].ts +10 -4
  235. package/src/astro/routes/api/sections/index.ts +7 -3
  236. package/src/astro/routes/api/settings/email.ts +4 -9
  237. package/src/astro/routes/api/setup/admin-verify.ts +6 -1
  238. package/src/astro/routes/api/setup/admin.ts +8 -2
  239. package/src/astro/routes/api/setup/index.ts +2 -2
  240. package/src/astro/routes/api/setup/status.ts +3 -1
  241. package/src/astro/routes/api/snapshot.ts +44 -18
  242. package/src/astro/routes/api/taxonomies/index.ts +0 -1
  243. package/src/astro/routes/api/themes/preview.ts +11 -5
  244. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +4 -1
  245. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +4 -1
  246. package/src/astro/routes/api/widget-areas/[name].ts +4 -1
  247. package/src/astro/routes/api/widget-areas/index.ts +4 -1
  248. package/src/astro/types.ts +32 -3
  249. package/src/auth/allowed-origins.ts +168 -0
  250. package/src/auth/mode.ts +15 -3
  251. package/src/auth/passkey-config.ts +35 -13
  252. package/src/auth/providers/github-admin.tsx +29 -0
  253. package/src/auth/providers/github.ts +31 -0
  254. package/src/auth/providers/google-admin.tsx +44 -0
  255. package/src/auth/providers/google.ts +31 -0
  256. package/src/auth/types.ts +114 -4
  257. package/src/bylines/index.ts +37 -88
  258. package/src/cli/commands/auth.ts +28 -6
  259. package/src/cli/commands/bundle-utils.ts +11 -2
  260. package/src/cli/commands/bundle.ts +31 -9
  261. package/src/cli/commands/content.ts +13 -0
  262. package/src/cli/commands/login.ts +8 -1
  263. package/src/cli/commands/publish.ts +24 -0
  264. package/src/cli/commands/secrets.ts +183 -0
  265. package/src/cli/credentials.ts +1 -1
  266. package/src/cli/index.ts +5 -1
  267. package/src/client/index.ts +4 -4
  268. package/src/client/transport.ts +17 -7
  269. package/src/components/Break.astro +2 -2
  270. package/src/components/EmDashHead.astro +18 -13
  271. package/src/components/EmDashImage.astro +7 -6
  272. package/src/components/Embed.astro +1 -1
  273. package/src/components/Gallery.astro +6 -4
  274. package/src/components/Image.astro +9 -4
  275. package/src/components/InlinePortableTextEditor.tsx +106 -19
  276. package/src/components/LiveSearch.astro +5 -14
  277. package/src/config/secrets.ts +528 -0
  278. package/src/database/dialect-helpers.ts +50 -0
  279. package/src/database/migrations/034_published_at_index.ts +1 -1
  280. package/src/database/migrations/035_bounded_404_log.ts +56 -39
  281. package/src/database/migrations/runner.ts +156 -23
  282. package/src/database/repositories/audit.ts +6 -8
  283. package/src/database/repositories/byline.ts +6 -8
  284. package/src/database/repositories/comment.ts +12 -16
  285. package/src/database/repositories/content.ts +76 -52
  286. package/src/database/repositories/index.ts +1 -1
  287. package/src/database/repositories/media.ts +10 -13
  288. package/src/database/repositories/plugin-storage.ts +4 -6
  289. package/src/database/repositories/redirect.ts +26 -19
  290. package/src/database/repositories/taxonomy.ts +40 -3
  291. package/src/database/repositories/types.ts +57 -8
  292. package/src/database/repositories/user.ts +6 -8
  293. package/src/db/libsql.ts +1 -3
  294. package/src/db/sqlite.ts +2 -5
  295. package/src/emdash-runtime.ts +388 -247
  296. package/src/index.ts +14 -1
  297. package/src/loader.ts +30 -6
  298. package/src/mcp/server.ts +781 -141
  299. package/src/media/normalize.ts +1 -1
  300. package/src/media/url.ts +78 -0
  301. package/src/page/site-identity.ts +58 -0
  302. package/src/plugins/adapt-sandbox-entry.ts +22 -10
  303. package/src/plugins/context.ts +13 -10
  304. package/src/plugins/define-plugin.ts +40 -12
  305. package/src/plugins/email-console.ts +10 -3
  306. package/src/plugins/hooks.ts +34 -19
  307. package/src/plugins/index.ts +9 -0
  308. package/src/plugins/manifest-schema.ts +49 -2
  309. package/src/plugins/types.ts +174 -13
  310. package/src/preview/urls.ts +23 -3
  311. package/src/query.ts +149 -6
  312. package/src/redirects/cache.ts +38 -18
  313. package/src/request-cache.ts +3 -0
  314. package/src/schema/registry.ts +97 -5
  315. package/src/schema/zod-generator.ts +27 -5
  316. package/src/search/fts-manager.ts +0 -2
  317. package/src/search/query.ts +111 -26
  318. package/src/search/types.ts +8 -1
  319. package/src/sections/index.ts +7 -9
  320. package/src/seed/apply.ts +2 -0
  321. package/src/settings/index.ts +80 -6
  322. package/src/settings/types.ts +23 -1
  323. package/src/storage/s3.ts +12 -6
  324. package/src/taxonomies/index.ts +11 -1
  325. package/src/virtual-modules.d.ts +21 -1
  326. package/src/widgets/index.ts +1 -1
  327. package/dist/apply-5uslYdUu.mjs.map +0 -1
  328. package/dist/byline-C4OVd8b3.mjs.map +0 -1
  329. package/dist/bylines-hPTW79hw.mjs +0 -157
  330. package/dist/bylines-hPTW79hw.mjs.map +0 -1
  331. package/dist/cache-BkKBuIvS.mjs +0 -56
  332. package/dist/cache-BkKBuIvS.mjs.map +0 -1
  333. package/dist/chunk-ClPoSABd.mjs +0 -21
  334. package/dist/content-D7J5y73J.mjs.map +0 -1
  335. package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
  336. package/dist/error-CiYn9yDu.mjs.map +0 -1
  337. package/dist/index-De6_Xv3v.d.mts.map +0 -1
  338. package/dist/loader-DeiBJEMe.mjs.map +0 -1
  339. package/dist/manifest-schema-V30qsMft.mjs.map +0 -1
  340. package/dist/media-DqHVh136.mjs.map +0 -1
  341. package/dist/mode-CpNnGkPz.mjs.map +0 -1
  342. package/dist/placeholder-C-fk5hYI.mjs.map +0 -1
  343. package/dist/query-g4Ug-9j9.mjs.map +0 -1
  344. package/dist/redirect-CN0Rt9Ob.mjs.map +0 -1
  345. package/dist/registry-Ci3WxVAr.mjs.map +0 -1
  346. package/dist/request-cache-DiR961CV.mjs.map +0 -1
  347. package/dist/runner-BR2xKwhn.d.mts +0 -34
  348. package/dist/runner-BR2xKwhn.d.mts.map +0 -1
  349. package/dist/search-B0effn3j.mjs.map +0 -1
  350. package/dist/taxonomies-K2z0Uhnj.mjs.map +0 -1
  351. package/dist/types-CMMN0pNg.mjs +0 -31
  352. package/dist/types-CMMN0pNg.mjs.map +0 -1
  353. package/dist/types-DgrIP0tF.d.mts.map +0 -1
  354. package/dist/version-BnTKdfam.mjs +0 -7
@@ -1,31 +1,36 @@
1
+ import { r as runMigrations } from "../runner-C7ADox5q.mjs";
1
2
  import { getRequestContext, runWithContext } from "../request-context.mjs";
2
3
  import { createRecorder, flushRecorder, isInstrumentationEnabled, kyselyLogOption } from "../database/instrumentation.mjs";
3
4
  import "../connection-2igzM-AT.mjs";
4
5
  import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
5
- import { a as isSqlite } from "../dialect-helpers-DhTzaUxP.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";
9
- import "../base64-MBPo9ozB.mjs";
10
- import "../types-CMMN0pNg.mjs";
11
- import { t as MediaRepository } from "../media-DqHVh136.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";
6
+ import { o as isSqlite } from "../dialect-helpers-BKCvISIQ.mjs";
7
+ import { At as handleContentTranslations, Ct as handleContentGetIncludingTrashed, Dt as handleContentPublish, Et as handleContentPermanentDelete, G as sanitizeHeadersForSandbox, H as resolveExclusiveHooks, I as PluginRouteRegistry, K as getTrustedProxyHeaders, L as DEV_CONSOLE_EMAIL_PLUGIN_ID, Mt as handleContentUnschedule, Nt as handleContentUpdate, Ot as handleContentRestore, Pt as validateRev, R as devConsoleEmailDeliver, St as handleContentGet, Tt as handleContentListTrashed, U as CronExecutor, V as createHookPipeline, W as extractRequestMeta, X as after, _t as handleContentCountTrashed, bt as handleContentDiscardDraft, ct as handleMediaGet, dt as handleRevisionGet, ft as handleRevisionList, gt as handleContentCountScheduled, ht as handleContentCompare, it as PluginStateRepository, jt as handleContentUnpublish, kt as handleContentSchedule, lt as handleMediaList, ot as handleMediaCreate, pt as handleRevisionRestore, q as definePlugin, st as handleMediaDelete, tt as loadBundleFromR2, ut as handleMediaUpdate, vt as handleContentCreate, wt as handleContentList, xt as handleContentDuplicate, yt as handleContentDelete, z as EmailPipeline } from "../search-dOGEccMa.mjs";
8
+ import { r as RevisionRepository } from "../content-8lOYF0pr.mjs";
9
+ import "../base64-BRICGH2l.mjs";
10
+ import "../types-CRxNbK-Z.mjs";
11
+ import { t as MediaRepository } from "../media-BW32b4gi.mjs";
12
+ import "../apply-BzltprvY.mjs";
13
+ import { t as OptionsRepository } from "../options-BVp3UsTS.mjs";
14
+ import "../redirect-BhUBKRc1.mjs";
15
+ import "../byline-BSaNL1w7.mjs";
16
+ import { n as normalizeMediaValue } from "../placeholder-CIJejMlK.mjs";
17
+ import { i as setI18nConfig } from "../config-BI0V3ICQ.mjs";
18
+ import { r as hashString } from "../zod-generator-CC0xNe_K.mjs";
19
+ import { i as FTSManager, n as SchemaRegistry } from "../registry-Dw70ChxB.mjs";
20
+ import { r as getDb } from "../loader-CKLbBnhK.mjs";
21
+ import { n as requestCached } from "../request-cache-B-bmkipQ.mjs";
22
+ import "../taxonomies-ZlRtD6AG.mjs";
23
+ import { r as normalizeManifestRoute } from "../manifest-schema-DqWNC3lM.mjs";
24
+ import "../types-4fVtCIm0.mjs";
25
+ import "../error-D_-tqP-I.mjs";
26
+ import { a as invalidateUrlPatternCache } from "../query-Cg9ZKRQ0.mjs";
27
+ import "../tokens-D7zMmWi2.mjs";
28
+ import "../bylines-CvJ3PYz2.mjs";
29
+ import "../load-DDqMMvZL.mjs";
26
30
  import "../index.mjs";
27
- import { n as VERSION, t as COMMIT } from "../version-BnTKdfam.mjs";
28
- import { t as getAuthMode } from "../mode-CpNnGkPz.mjs";
31
+ import { n as VERSION, t as COMMIT } from "../version-DoxrVdYf.mjs";
32
+ import { t as getAuthMode } from "../mode-ier8jbBk.mjs";
33
+ import { a as validateEncryptionKeyAtStartup } from "../secrets-CW3reAnU.mjs";
29
34
  import { Kysely, sql } from "kysely";
30
35
  import { defineMiddleware } from "astro:middleware";
31
36
  import virtualConfig from "virtual:emdash/config";
@@ -281,6 +286,19 @@ var PiggybackScheduler = class {
281
286
  //#endregion
282
287
  //#region src/emdash-runtime.ts
283
288
  const LEADING_SLASH_PATTERN = /^\//;
289
+ /**
290
+ * Parse a JSON column expected to contain an array of strings.
291
+ *
292
+ * Throws on malformed JSON rather than returning []; callers are responsible
293
+ * for deciding how to handle/log the error. Empty string / null inputs return
294
+ * [] (they represent "no value"). Non-string array entries are filtered out.
295
+ */
296
+ function parseStringArray(raw) {
297
+ if (!raw) return [];
298
+ const parsed = JSON.parse(raw);
299
+ if (!Array.isArray(parsed)) return [];
300
+ return parsed.filter((v) => typeof v === "string");
301
+ }
284
302
  const VALID_METADATA_KINDS = new Set([
285
303
  "meta",
286
304
  "property",
@@ -375,9 +393,6 @@ var EmDashRuntime = class EmDashRuntime {
375
393
  cronScheduler;
376
394
  enabledPlugins;
377
395
  pluginStates;
378
- _cachedManifest = null;
379
- _manifestPromise = null;
380
- _manifestCacheKey;
381
396
  /**
382
397
  * Set to true after FTS indexes have been verified for this worker
383
398
  * lifetime so we don't re-scan on every admin request. See
@@ -410,27 +425,26 @@ 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;
434
448
  }
435
449
  /**
436
450
  * Get the sandbox runner instance (for marketplace install/update)
@@ -471,7 +485,6 @@ var EmDashRuntime = class EmDashRuntime {
471
485
  this.enabledPlugins.delete(pluginId);
472
486
  await this.rebuildHookPipeline();
473
487
  }
474
- this.invalidateManifest();
475
488
  }
476
489
  /**
477
490
  * Rebuild the hook pipeline from the current set of enabled plugins.
@@ -595,6 +608,7 @@ var EmDashRuntime = class EmDashRuntime {
595
608
  }
596
609
  };
597
610
  const db = await phase("rt.db", "DB init + migrations", () => EmDashRuntime.getDatabase(deps));
611
+ await phase("rt.secrets", "Validate encryption key", () => validateEncryptionKeyAtStartup());
598
612
  const storage = EmDashRuntime.getStorage(deps);
599
613
  let pluginStates = /* @__PURE__ */ new Map();
600
614
  await phase("rt.plugins", "Plugin states", async () => {
@@ -628,7 +642,7 @@ var EmDashRuntime = class EmDashRuntime {
628
642
  const devConsolePlugin = definePlugin({
629
643
  id: DEV_CONSOLE_EMAIL_PLUGIN_ID,
630
644
  version: "0.0.0",
631
- capabilities: ["email:provide"],
645
+ capabilities: ["hooks.email-transport:register"],
632
646
  hooks: { "email:deliver": {
633
647
  exclusive: true,
634
648
  handler: devConsoleEmailDeliver
@@ -643,7 +657,7 @@ var EmDashRuntime = class EmDashRuntime {
643
657
  const defaultModeratorPlugin = definePlugin({
644
658
  id: DEFAULT_COMMENT_MODERATOR_PLUGIN_ID,
645
659
  version: "0.0.0",
646
- capabilities: ["read:users"],
660
+ capabilities: ["users:read"],
647
661
  hooks: { "comment:moderate": {
648
662
  exclusive: true,
649
663
  handler: defaultCommentModerate
@@ -716,14 +730,26 @@ var EmDashRuntime = class EmDashRuntime {
716
730
  console.warn("[cron] Failed to initialize cron system:", error);
717
731
  }
718
732
  });
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);
733
+ return new EmDashRuntime({
734
+ db,
735
+ storage,
736
+ configuredPlugins: deps.plugins,
737
+ sandboxedPlugins,
738
+ sandboxedPluginEntries: deps.sandboxedPluginEntries,
739
+ hooks: pipeline,
740
+ enabledPlugins,
741
+ pluginStates,
742
+ config: deps.config,
743
+ mediaProviders,
744
+ mediaProviderEntries,
745
+ cronExecutor,
746
+ cronScheduler,
747
+ emailPipeline,
748
+ allPipelinePlugins,
749
+ pipelineFactoryOptions,
750
+ runtimeDeps: deps,
751
+ pipelineRef
752
+ });
727
753
  }
728
754
  /**
729
755
  * Get a media provider by ID
@@ -763,10 +789,7 @@ var EmDashRuntime = class EmDashRuntime {
763
789
  dialect: deps.createDialect(dbConfig.config),
764
790
  log: kyselyLogOption()
765
791
  });
766
- const { applied } = await runMigrations(db);
767
- if (applied.length > 0) try {
768
- await new OptionsRepository(db).delete("emdash:manifest_cache");
769
- } catch {}
792
+ await runMigrations(db);
770
793
  try {
771
794
  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()]);
772
795
  const setupDone = (() => {
@@ -777,9 +800,9 @@ var EmDashRuntime = class EmDashRuntime {
777
800
  }
778
801
  })();
779
802
  if (collectionCount.count === 0 && !setupDone) {
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);
803
+ const { applySeed } = await import("../apply-BzltprvY.mjs").then((n) => n.n);
804
+ const { loadSeed } = await import("../load-DDqMMvZL.mjs").then((n) => n.r);
805
+ const { validateSeed } = await import("../validate-Baqf0slj.mjs").then((n) => n.n);
783
806
  const seed = await loadSeed();
784
807
  if (validateSeed(seed).valid) {
785
808
  await applySeed(db, seed, { onConflict: "skip" });
@@ -918,60 +941,42 @@ var EmDashRuntime = class EmDashRuntime {
918
941
  });
919
942
  }
920
943
  /**
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.
944
+ * Build the admin manifest from the live database.
924
945
  *
925
- * Cache is invalidated by invalidateManifest(), called from schema
926
- * API routes, MCP server, plugin toggle, and taxonomy def changes.
946
+ * Used by the admin UI (sidebar collections, content editor field
947
+ * dispatch, manifest endpoint) and by WordPress import it's never
948
+ * read on a public request, so this isn't on any anonymous hot path.
949
+ *
950
+ * No cross-request cache. The previous worker-isolate cache produced
951
+ * a class of cross-isolate staleness bugs (#776, #873, #876, #877)
952
+ * because Cloudflare Workers keeps multiple warm isolates per region
953
+ * and there's no fan-out primitive to invalidate them in step. The
954
+ * cache existed to amortize an N+1 schema query pattern; now that
955
+ * `listCollectionsWithFields()` does the same work in two queries,
956
+ * the rebuild is fast enough to pay on every admin request.
957
+ *
958
+ * Within a single request, `requestCached` deduplicates concurrent
959
+ * callers (the manifest endpoint and an admin SSR template, say).
927
960
  */
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
- }
961
+ getManifest() {
962
+ return requestCached("emdash:manifest", () => this._buildManifest());
962
963
  }
963
964
  /**
964
- * Build the manifest from database (N+1 collection queries).
965
+ * Build the manifest from the database.
966
+ *
967
+ * Constant query shapes via `listCollectionsWithFields()` — one query
968
+ * for collections, one batched query for fields (chunked at
969
+ * `SQL_BATCH_SIZE` collection IDs to stay under D1's bound-parameter
970
+ * limit). Typical sites stay well under the chunk threshold, so this
971
+ * is two queries in practice; never N+1.
965
972
  */
966
973
  async _buildManifest() {
967
974
  const manifestCollections = {};
968
975
  try {
969
- const registry = new SchemaRegistry(this.db);
970
- const dbCollections = await registry.listCollections();
976
+ const dbCollections = await new SchemaRegistry(this.db).listCollectionsWithFields();
971
977
  for (const collection of dbCollections) {
972
- const collectionWithFields = await registry.getCollectionWithFields(collection.slug);
973
978
  const fields = {};
974
- if (collectionWithFields?.fields) for (const field of collectionWithFields.fields) {
979
+ for (const field of collection.fields) {
975
980
  const entry = {
976
981
  kind: FIELD_TYPE_TO_KIND[field.type] ?? "string",
977
982
  label: field.label,
@@ -1055,7 +1060,7 @@ var EmDashRuntime = class EmDashRuntime {
1055
1060
  label: row.label,
1056
1061
  labelSingular: row.label_singular ?? void 0,
1057
1062
  hierarchical: row.hierarchical === 1,
1058
- collections: row.collections ? JSON.parse(row.collections).toSorted() : []
1063
+ collections: parseStringArray(row.collections).toSorted()
1059
1064
  }));
1060
1065
  } catch (error) {
1061
1066
  console.debug("EmDash: Could not load taxonomy definitions:", error);
@@ -1081,22 +1086,6 @@ var EmDashRuntime = class EmDashRuntime {
1081
1086
  };
1082
1087
  }
1083
1088
  /**
1084
- * Invalidate cached data derived from the manifest/schema.
1085
- * Called when collections, fields, plugins, or taxonomy defs change.
1086
- */
1087
- invalidateManifest() {
1088
- this._cachedManifest = null;
1089
- this._manifestPromise = null;
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
1089
  * Verify and repair FTS indexes on demand. Runs at most once per worker
1101
1090
  * lifetime.
1102
1091
  *
@@ -1143,16 +1132,67 @@ var EmDashRuntime = class EmDashRuntime {
1143
1132
  return handleContentList(this.db, collection, params);
1144
1133
  }
1145
1134
  async handleContentGet(collection, id, locale) {
1146
- return handleContentGet(this.db, collection, id, locale);
1135
+ const result = await handleContentGet(this.db, collection, id, locale);
1136
+ return this.hydrateDraftData(result);
1147
1137
  }
1148
1138
  async handleContentGetIncludingTrashed(collection, id, locale) {
1149
- return handleContentGetIncludingTrashed(this.db, collection, id, locale);
1139
+ const result = await handleContentGetIncludingTrashed(this.db, collection, id, locale);
1140
+ return this.hydrateDraftData(result);
1141
+ }
1142
+ /**
1143
+ * If the response item has a `draftRevisionId`, replace `item.data` with
1144
+ * the draft revision's data and expose the original published values as
1145
+ * `liveData`. This makes the content_get / content_update round-trip
1146
+ * intuitive — read returns the latest content the caller has saved
1147
+ * (their pending draft), with the previously-published values still
1148
+ * accessible for compare-style flows.
1149
+ *
1150
+ * No-op when no draft exists or the response is an error.
1151
+ */
1152
+ async hydrateDraftData(result) {
1153
+ if (!result || typeof result !== "object") return result;
1154
+ const r = result;
1155
+ if (!r.success || !r.data?.item) return result;
1156
+ const item = r.data.item;
1157
+ const draftRevisionId = typeof item.draftRevisionId === "string" ? item.draftRevisionId : null;
1158
+ if (!draftRevisionId) return result;
1159
+ try {
1160
+ const revision = await new RevisionRepository(this.db).findById(draftRevisionId);
1161
+ if (!revision) return result;
1162
+ const liveData = item.data && typeof item.data === "object" ? item.data : {};
1163
+ const revisionData = {};
1164
+ for (const [key, value] of Object.entries(revision.data)) if (!key.startsWith("_")) revisionData[key] = value;
1165
+ const mergedData = {
1166
+ ...liveData,
1167
+ ...revisionData
1168
+ };
1169
+ return {
1170
+ ...result,
1171
+ data: {
1172
+ ...r.data,
1173
+ item: {
1174
+ ...item,
1175
+ data: mergedData,
1176
+ liveData
1177
+ }
1178
+ }
1179
+ };
1180
+ } catch (error) {
1181
+ console.error("[emdash] draft hydration failed:", error);
1182
+ return result;
1183
+ }
1150
1184
  }
1151
1185
  async handleContentCreate(collection, body) {
1152
1186
  let processedData = body.data;
1153
1187
  if (this.hooks.hasHooks("content:beforeSave")) processedData = (await this.hooks.runContentBeforeSave(body.data, collection, true)).content;
1154
1188
  processedData = await this.runSandboxedBeforeSave(processedData, collection, true);
1155
1189
  processedData = await this.normalizeMediaFields(collection, processedData);
1190
+ const { validateContentData } = await import("../validation-BfEI7tNe.mjs");
1191
+ const validation = await validateContentData(this.db, collection, processedData, { partial: false });
1192
+ if (!validation.ok) return {
1193
+ success: false,
1194
+ error: validation.error
1195
+ };
1156
1196
  const result = await handleContentCreate(this.db, collection, {
1157
1197
  ...body,
1158
1198
  data: processedData,
@@ -1163,7 +1203,7 @@ var EmDashRuntime = class EmDashRuntime {
1163
1203
  return result;
1164
1204
  }
1165
1205
  async handleContentUpdate(collection, id, body) {
1166
- const { ContentRepository } = await import("../content-D7J5y73J.mjs").then((n) => n.n);
1206
+ const { ContentRepository } = await import("../content-8lOYF0pr.mjs").then((n) => n.n);
1167
1207
  const repo = new ContentRepository(this.db);
1168
1208
  const resolvedItem = await repo.findByIdOrSlug(collection, id);
1169
1209
  const resolvedId = resolvedItem?.id ?? id;
@@ -1190,6 +1230,12 @@ var EmDashRuntime = class EmDashRuntime {
1190
1230
  if (this.hooks.hasHooks("content:beforeSave")) processedData = (await this.hooks.runContentBeforeSave(bodyWithoutRev.data, collection, false)).content;
1191
1231
  processedData = await this.runSandboxedBeforeSave(processedData, collection, false);
1192
1232
  processedData = await this.normalizeMediaFields(collection, processedData);
1233
+ const { validateContentData } = await import("../validation-BfEI7tNe.mjs");
1234
+ const validation = await validateContentData(this.db, collection, processedData, { partial: true });
1235
+ if (!validation.ok) return {
1236
+ success: false,
1237
+ error: validation.error
1238
+ };
1193
1239
  }
1194
1240
  let usesDraftRevisions = false;
1195
1241
  if (processedData) try {
@@ -1234,8 +1280,9 @@ var EmDashRuntime = class EmDashRuntime {
1234
1280
  authorId: bodyWithoutRev.authorId,
1235
1281
  bylines: bodyWithoutRev.bylines
1236
1282
  });
1237
- if (result.success && result.data) this.runAfterSaveHooks(contentItemToRecord(result.data.item), collection, false);
1238
- return result;
1283
+ const hydrated = await this.hydrateDraftData(result);
1284
+ if (hydrated.success && hydrated.data) this.runAfterSaveHooks(contentItemToRecord(hydrated.data.item), collection, false);
1285
+ return hydrated;
1239
1286
  }
1240
1287
  async handleContentDelete(collection, id) {
1241
1288
  if (this.hooks.hasHooks("content:beforeDelete")) {
@@ -1276,8 +1323,8 @@ var EmDashRuntime = class EmDashRuntime {
1276
1323
  async handleContentDuplicate(collection, id, authorId) {
1277
1324
  return handleContentDuplicate(this.db, collection, id, authorId);
1278
1325
  }
1279
- async handleContentPublish(collection, id) {
1280
- const result = await handleContentPublish(this.db, collection, id);
1326
+ async handleContentPublish(collection, id, options = {}) {
1327
+ const result = await handleContentPublish(this.db, collection, id, options);
1281
1328
  if (result.success && result.data) this.runAfterPublishHooks(contentItemToRecord(result.data.item), collection);
1282
1329
  return result;
1283
1330
  }
@@ -1353,7 +1400,47 @@ var EmDashRuntime = class EmDashRuntime {
1353
1400
  return handleRevisionGet(this.db, revisionId);
1354
1401
  }
1355
1402
  async handleRevisionRestore(revisionId, callerUserId) {
1356
- return handleRevisionRestore(this.db, revisionId, callerUserId);
1403
+ const revisionRepo = new RevisionRepository(this.db);
1404
+ const revision = await revisionRepo.findById(revisionId);
1405
+ if (!revision) return {
1406
+ success: false,
1407
+ error: {
1408
+ code: "NOT_FOUND",
1409
+ message: `Revision not found: ${revisionId}`
1410
+ }
1411
+ };
1412
+ if (!((await this.schemaRegistry.getCollectionWithFields(revision.collection))?.supports?.includes("revisions") ?? false)) {
1413
+ const result = await handleRevisionRestore(this.db, revisionId, callerUserId);
1414
+ return this.hydrateDraftData(result);
1415
+ }
1416
+ try {
1417
+ const newDraft = await revisionRepo.create({
1418
+ collection: revision.collection,
1419
+ entryId: revision.entryId,
1420
+ data: revision.data,
1421
+ authorId: callerUserId
1422
+ });
1423
+ validateIdentifier(revision.collection, "collection");
1424
+ const tableName = `ec_${revision.collection}`;
1425
+ await sql`
1426
+ UPDATE ${sql.ref(tableName)}
1427
+ SET draft_revision_id = ${newDraft.id},
1428
+ updated_at = ${(/* @__PURE__ */ new Date()).toISOString()}
1429
+ WHERE id = ${revision.entryId}
1430
+ `.execute(this.db);
1431
+ revisionRepo.pruneOldRevisions(revision.collection, revision.entryId, 50).catch(() => {});
1432
+ const refetched = await handleContentGet(this.db, revision.collection, revision.entryId);
1433
+ return this.hydrateDraftData(refetched);
1434
+ } catch (error) {
1435
+ console.error("[emdash] revision restore failed:", error);
1436
+ return {
1437
+ success: false,
1438
+ error: {
1439
+ code: "REVISION_RESTORE_ERROR",
1440
+ message: "Failed to restore revision"
1441
+ }
1442
+ };
1443
+ }
1357
1444
  }
1358
1445
  /**
1359
1446
  * Get route metadata for a plugin route without invoking the handler.
@@ -1486,16 +1573,30 @@ var EmDashRuntime = class EmDashRuntime {
1486
1573
  return true;
1487
1574
  }
1488
1575
  runAfterSaveHooks(content, collection, isNew) {
1489
- if (this.hooks.hasHooks("content:afterSave")) this.hooks.runContentAfterSave(content, collection, isNew).catch((err) => console.error("EmDash afterSave hook error:", err));
1490
- for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1491
- const [id] = pluginKey.split(":");
1492
- if (!id || !this.isPluginEnabled(id)) continue;
1493
- plugin.invokeHook("content:afterSave", {
1494
- content,
1495
- collection,
1496
- isNew
1497
- }).catch((err) => console.error(`EmDash: Sandboxed plugin ${id} afterSave error:`, err));
1498
- }
1576
+ after(async () => {
1577
+ if (this.hooks.hasHooks("content:afterSave")) try {
1578
+ await this.hooks.runContentAfterSave(content, collection, isNew);
1579
+ } catch (err) {
1580
+ console.error("EmDash afterSave hook error:", err);
1581
+ }
1582
+ const tasks = [];
1583
+ for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1584
+ const [id] = pluginKey.split(":");
1585
+ if (!id || !this.isPluginEnabled(id)) continue;
1586
+ tasks.push((async () => {
1587
+ try {
1588
+ await plugin.invokeHook("content:afterSave", {
1589
+ content,
1590
+ collection,
1591
+ isNew
1592
+ });
1593
+ } catch (err) {
1594
+ console.error(`EmDash: Sandboxed plugin ${id} afterSave error:`, err);
1595
+ }
1596
+ })());
1597
+ }
1598
+ await Promise.allSettled(tasks);
1599
+ });
1499
1600
  }
1500
1601
  runAfterDeleteHooks(id, collection, permanent) {
1501
1602
  if (this.hooks.hasHooks("content:afterDelete")) this.hooks.runContentAfterDelete(id, collection, permanent).catch((err) => console.error("EmDash afterDelete hook error:", err));
@@ -1510,15 +1611,29 @@ var EmDashRuntime = class EmDashRuntime {
1510
1611
  }
1511
1612
  }
1512
1613
  runAfterPublishHooks(content, collection) {
1513
- if (this.hooks.hasHooks("content:afterPublish")) this.hooks.runContentAfterPublish(content, collection).catch((err) => console.error("EmDash afterPublish hook error:", err));
1514
- for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1515
- const [pluginId] = pluginKey.split(":");
1516
- if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
1517
- plugin.invokeHook("content:afterPublish", {
1518
- content,
1519
- collection
1520
- }).catch((err) => console.error(`EmDash: Sandboxed plugin ${pluginId} afterPublish error:`, err));
1521
- }
1614
+ after(async () => {
1615
+ if (this.hooks.hasHooks("content:afterPublish")) try {
1616
+ await this.hooks.runContentAfterPublish(content, collection);
1617
+ } catch (err) {
1618
+ console.error("EmDash afterPublish hook error:", err);
1619
+ }
1620
+ const tasks = [];
1621
+ for (const [pluginKey, plugin] of this.sandboxedPlugins) {
1622
+ const [pluginId] = pluginKey.split(":");
1623
+ if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
1624
+ tasks.push((async () => {
1625
+ try {
1626
+ await plugin.invokeHook("content:afterPublish", {
1627
+ content,
1628
+ collection
1629
+ });
1630
+ } catch (err) {
1631
+ console.error(`EmDash: Sandboxed plugin ${pluginId} afterPublish error:`, err);
1632
+ }
1633
+ })());
1634
+ }
1635
+ await Promise.allSettled(tasks);
1636
+ });
1522
1637
  }
1523
1638
  runAfterUnpublishHooks(content, collection) {
1524
1639
  if (this.hooks.hasHooks("content:afterUnpublish")) this.hooks.runContentAfterUnpublish(content, collection).catch((err) => console.error("EmDash afterUnpublish hook error:", err));
@@ -1629,6 +1744,28 @@ var EmDashRuntime = class EmDashRuntime {
1629
1744
  }
1630
1745
  };
1631
1746
 
1747
+ //#endregion
1748
+ //#region src/media/url.ts
1749
+ /**
1750
+ * Resolve the public URL for a locally stored media key. Returns an empty
1751
+ * string when no key is given. When a storage adapter is supplied, defers to
1752
+ * `storage.getPublicUrl()`; otherwise returns the internal proxy route.
1753
+ */
1754
+ function resolvePublicMediaUrl(storage, storageKey) {
1755
+ if (!storageKey) return "";
1756
+ if (storage) return storage.getPublicUrl(storageKey);
1757
+ return `/_emdash/api/media/file/${storageKey}`;
1758
+ }
1759
+ /**
1760
+ * Build the `getPublicMediaUrl` closure attached to `Astro.locals.emdash`.
1761
+ * Shared by the anonymous fast path and the full-runtime path in middleware.
1762
+ *
1763
+ * @internal
1764
+ */
1765
+ function createPublicMediaUrlResolver(storage) {
1766
+ return (key) => resolvePublicMediaUrl(storage, key);
1767
+ }
1768
+
1632
1769
  //#endregion
1633
1770
  //#region src/astro/middleware.ts
1634
1771
  /**
@@ -1751,6 +1888,9 @@ function createRequestScopedDb$1(opts) {
1751
1888
  const onRequest = defineMiddleware(async (context, next) => {
1752
1889
  const { request, locals, cookies } = context;
1753
1890
  const url = context.url;
1891
+ if (!url.pathname.startsWith("/_emdash") && virtualConfig?.authProviders) {
1892
+ if (virtualConfig.authProviders.some((p) => p.routes?.some((r) => r.pattern && url.pathname === r.pattern))) return finalizeResponse(await next());
1893
+ }
1754
1894
  const queryRecorder = isInstrumentationEnabled() ? createRecorder(url.pathname, request.method, request.headers.get("x-perf-phase") ?? "default") : void 0;
1755
1895
  const run = async () => {
1756
1896
  const isEmDashRoute = url.pathname.startsWith("/_emdash");
@@ -1758,7 +1898,8 @@ const onRequest = defineMiddleware(async (context, next) => {
1758
1898
  const hasEditCookie = cookies.get("emdash-edit-mode")?.value === "true";
1759
1899
  const hasPreviewToken = url.searchParams.has("_preview");
1760
1900
  const playgroundDb = locals.__playgroundDb;
1761
- const sessionUser = context.isPrerendered ? null : await context.session?.get("user");
1901
+ const hasSessionCookie = cookies.get("astro-session") !== void 0;
1902
+ const sessionUser = context.isPrerendered || !hasSessionCookie ? null : await context.session?.get("user");
1762
1903
  if (!isEmDashRoute && !isPublicRuntimeRoute && !hasEditCookie && !hasPreviewToken) {
1763
1904
  if (!sessionUser && !playgroundDb) {
1764
1905
  const timings = [];
@@ -1766,7 +1907,7 @@ const onRequest = defineMiddleware(async (context, next) => {
1766
1907
  if (!setupVerified) {
1767
1908
  const t0 = performance.now();
1768
1909
  try {
1769
- const { getDb } = await import("../loader-DeiBJEMe.mjs").then((n) => n.r);
1910
+ const { getDb } = await import("../loader-CKLbBnhK.mjs").then((n) => n.i);
1770
1911
  await (await getDb()).selectFrom("_emdash_migrations").selectAll().limit(1).execute();
1771
1912
  setupVerified = true;
1772
1913
  } catch {
@@ -1787,7 +1928,8 @@ const onRequest = defineMiddleware(async (context, next) => {
1787
1928
  setupVerified = true;
1788
1929
  locals.emdash = {
1789
1930
  collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
1790
- collectPageFragments: runtime.collectPageFragments.bind(runtime)
1931
+ collectPageFragments: runtime.collectPageFragments.bind(runtime),
1932
+ getPublicMediaUrl: createPublicMediaUrlResolver(runtime.storage)
1791
1933
  };
1792
1934
  } catch {}
1793
1935
  timings.push({
@@ -1855,14 +1997,6 @@ const onRequest = defineMiddleware(async (context, next) => {
1855
1997
  });
1856
1998
  for (const sub of initSubTimings) timings.push(sub);
1857
1999
  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;
1866
2000
  locals.emdash = {
1867
2001
  handleContentList: runtime.handleContentList.bind(runtime),
1868
2002
  handleContentGet: runtime.handleContentGet.bind(runtime),
@@ -1900,11 +2034,13 @@ const onRequest = defineMiddleware(async (context, next) => {
1900
2034
  ensureSearchHealthy: runtime.ensureSearchHealthy.bind(runtime),
1901
2035
  storage: runtime.storage,
1902
2036
  db: runtime.db,
2037
+ getPublicMediaUrl: createPublicMediaUrlResolver(runtime.storage),
1903
2038
  hooks: runtime.hooks,
1904
2039
  email: runtime.email,
1905
2040
  configuredPlugins: runtime.configuredPlugins,
1906
2041
  config,
1907
- invalidateManifest: runtime.invalidateManifest.bind(runtime),
2042
+ getManifest: runtime.getManifest.bind(runtime),
2043
+ invalidateUrlPatternCache,
1908
2044
  getSandboxRunner: runtime.getSandboxRunner.bind(runtime),
1909
2045
  syncMarketplacePlugins: runtime.syncMarketplacePlugins.bind(runtime),
1910
2046
  setPluginStatus: runtime.setPluginStatus.bind(runtime)