emdash 0.7.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/dist/{adapters-Di31kZ28.d.mts → adapters-BKSf3T9R.d.mts} +1 -1
  2. package/dist/{adapters-Di31kZ28.d.mts.map → adapters-BKSf3T9R.d.mts.map} +1 -1
  3. package/dist/{apply-5uslYdUu.mjs → apply-x0eMK1lX.mjs} +18 -17
  4. package/dist/apply-x0eMK1lX.mjs.map +1 -0
  5. package/dist/astro/index.d.mts +6 -6
  6. package/dist/astro/index.d.mts.map +1 -1
  7. package/dist/astro/index.mjs +86 -15
  8. package/dist/astro/index.mjs.map +1 -1
  9. package/dist/astro/middleware/auth.d.mts +5 -5
  10. package/dist/astro/middleware/auth.d.mts.map +1 -1
  11. package/dist/astro/middleware/auth.mjs +22 -2
  12. package/dist/astro/middleware/auth.mjs.map +1 -1
  13. package/dist/astro/middleware/redirect.mjs +2 -2
  14. package/dist/astro/middleware/request-context.mjs +1 -1
  15. package/dist/astro/middleware/setup.mjs +1 -1
  16. package/dist/astro/middleware.d.mts.map +1 -1
  17. package/dist/astro/middleware.mjs +259 -71
  18. package/dist/astro/middleware.mjs.map +1 -1
  19. package/dist/astro/types.d.mts +16 -8
  20. package/dist/astro/types.d.mts.map +1 -1
  21. package/dist/{byline-C4OVd8b3.mjs → byline-Chbr2GoP.mjs} +3 -3
  22. package/dist/byline-Chbr2GoP.mjs.map +1 -0
  23. package/dist/{bylines-hPTW79hw.mjs → bylines-CRNsVG88.mjs} +4 -4
  24. package/dist/{bylines-hPTW79hw.mjs.map → bylines-CRNsVG88.mjs.map} +1 -1
  25. package/dist/cli/index.mjs +16 -12
  26. package/dist/cli/index.mjs.map +1 -1
  27. package/dist/client/cf-access.d.mts +1 -1
  28. package/dist/client/index.d.mts +1 -1
  29. package/dist/client/index.mjs +1 -1
  30. package/dist/{content-D7J5y73J.mjs → content-BcQPYxdV.mjs} +13 -15
  31. package/dist/content-BcQPYxdV.mjs.map +1 -0
  32. package/dist/db/index.d.mts +3 -3
  33. package/dist/db/libsql.d.mts +1 -1
  34. package/dist/db/postgres.d.mts +1 -1
  35. package/dist/db/sqlite.d.mts +1 -1
  36. package/dist/{db-errors-D0UT85nC.mjs → db-errors-l1Qh2RPR.mjs} +1 -1
  37. package/dist/{db-errors-D0UT85nC.mjs.map → db-errors-l1Qh2RPR.mjs.map} +1 -1
  38. package/dist/{default-CME5YdZ3.mjs → default-DCVqE5ib.mjs} +1 -1
  39. package/dist/{default-CME5YdZ3.mjs.map → default-DCVqE5ib.mjs.map} +1 -1
  40. package/dist/{error-CiYn9yDu.mjs → error-zG5T1UGA.mjs} +1 -1
  41. package/dist/error-zG5T1UGA.mjs.map +1 -0
  42. package/dist/{index-De6_Xv3v.d.mts → index-DIb-CzNx.d.mts} +157 -14
  43. package/dist/index-DIb-CzNx.d.mts.map +1 -0
  44. package/dist/index.d.mts +11 -11
  45. package/dist/index.mjs +22 -20
  46. package/dist/{load-CBcmDIot.mjs → load-CyEoextb.mjs} +1 -1
  47. package/dist/{load-CBcmDIot.mjs.map → load-CyEoextb.mjs.map} +1 -1
  48. package/dist/{loader-DeiBJEMe.mjs → loader-CndGj8kM.mjs} +8 -6
  49. package/dist/loader-CndGj8kM.mjs.map +1 -0
  50. package/dist/{manifest-schema-V30qsMft.mjs → manifest-schema-DH9xhc6t.mjs} +13 -1
  51. package/dist/manifest-schema-DH9xhc6t.mjs.map +1 -0
  52. package/dist/media/index.d.mts +1 -1
  53. package/dist/media/local-runtime.d.mts +7 -7
  54. package/dist/media/local-runtime.mjs +2 -2
  55. package/dist/{media-DqHVh136.mjs → media-D8FbNsl0.mjs} +4 -7
  56. package/dist/media-D8FbNsl0.mjs.map +1 -0
  57. package/dist/{mode-CpNnGkPz.mjs → mode-BnAOqItE.mjs} +1 -1
  58. package/dist/mode-BnAOqItE.mjs.map +1 -0
  59. package/dist/page/index.d.mts +2 -2
  60. package/dist/placeholder-C-fk5hYI.mjs.map +1 -1
  61. package/dist/{placeholder-tzpqGWII.d.mts → placeholder-D29tWZ7o.d.mts} +1 -1
  62. package/dist/{placeholder-tzpqGWII.d.mts.map → placeholder-D29tWZ7o.d.mts.map} +1 -1
  63. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  64. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  65. package/dist/{query-g4Ug-9j9.mjs → query-fqEdLFms.mjs} +9 -9
  66. package/dist/{query-g4Ug-9j9.mjs.map → query-fqEdLFms.mjs.map} +1 -1
  67. package/dist/{redirect-CN0Rt9Ob.mjs → redirect-D_pshWdf.mjs} +4 -4
  68. package/dist/redirect-D_pshWdf.mjs.map +1 -0
  69. package/dist/{registry-Ci3WxVAr.mjs → registry-C3Mr0ODu.mjs} +33 -9
  70. package/dist/registry-C3Mr0ODu.mjs.map +1 -0
  71. package/dist/{request-cache-DiR961CV.mjs → request-cache-Ci7f5pBb.mjs} +1 -1
  72. package/dist/request-cache-Ci7f5pBb.mjs.map +1 -0
  73. package/dist/{runner-BR2xKwhn.d.mts → runner-OURCaApa.d.mts} +2 -2
  74. package/dist/{runner-BR2xKwhn.d.mts.map → runner-OURCaApa.d.mts.map} +1 -1
  75. package/dist/runtime.d.mts +6 -6
  76. package/dist/runtime.mjs +2 -2
  77. package/dist/{search-B0effn3j.mjs → search-BoZYFuUk.mjs} +227 -84
  78. package/dist/search-BoZYFuUk.mjs.map +1 -0
  79. package/dist/seed/index.d.mts +2 -2
  80. package/dist/seed/index.mjs +12 -12
  81. package/dist/seo/index.d.mts +1 -1
  82. package/dist/storage/local.d.mts +1 -1
  83. package/dist/storage/local.mjs +1 -1
  84. package/dist/storage/s3.d.mts +1 -1
  85. package/dist/storage/s3.d.mts.map +1 -1
  86. package/dist/storage/s3.mjs +4 -4
  87. package/dist/storage/s3.mjs.map +1 -1
  88. package/dist/{taxonomies-K2z0Uhnj.mjs → taxonomies-B4IAshV8.mjs} +5 -5
  89. package/dist/{taxonomies-K2z0Uhnj.mjs.map → taxonomies-B4IAshV8.mjs.map} +1 -1
  90. package/dist/{tokens-BFPFx3CA.mjs → tokens-D9vnZqYS.mjs} +1 -1
  91. package/dist/{tokens-BFPFx3CA.mjs.map → tokens-D9vnZqYS.mjs.map} +1 -1
  92. package/dist/{transport-BykRfpyy.mjs → transport-C9ugt2Nr.mjs} +1 -1
  93. package/dist/{transport-BykRfpyy.mjs.map → transport-C9ugt2Nr.mjs.map} +1 -1
  94. package/dist/{transport-H4Iwx7tC.d.mts → transport-CUnEL3Vs.d.mts} +1 -1
  95. package/dist/{transport-H4Iwx7tC.d.mts.map → transport-CUnEL3Vs.d.mts.map} +1 -1
  96. package/dist/types-BIgulNsW.mjs +68 -0
  97. package/dist/types-BIgulNsW.mjs.map +1 -0
  98. package/dist/{types-DDS4MxsT.mjs → types-Bm1dn-q3.mjs} +1 -1
  99. package/dist/{types-DDS4MxsT.mjs.map → types-Bm1dn-q3.mjs.map} +1 -1
  100. package/dist/{types-CnZYHyLW.d.mts → types-BmPPSUEx.d.mts} +1 -1
  101. package/dist/{types-CnZYHyLW.d.mts.map → types-BmPPSUEx.d.mts.map} +1 -1
  102. package/dist/{types-6CUZRrZP.d.mts → types-BrA0xf5I.d.mts} +24 -2
  103. package/dist/{types-6CUZRrZP.d.mts.map → types-BrA0xf5I.d.mts.map} +1 -1
  104. package/dist/{types-C2v0c34j.d.mts → types-CS8FIX7L.d.mts} +1 -1
  105. package/dist/{types-C2v0c34j.d.mts.map → types-CS8FIX7L.d.mts.map} +1 -1
  106. package/dist/{types-BH2L167P.mjs → types-CgqmmMJB.mjs} +1 -1
  107. package/dist/{types-BH2L167P.mjs.map → types-CgqmmMJB.mjs.map} +1 -1
  108. package/dist/{types-CFWjXmus.d.mts → types-DIMwPFub.d.mts} +1 -1
  109. package/dist/{types-CFWjXmus.d.mts.map → types-DIMwPFub.d.mts.map} +1 -1
  110. package/dist/{types-DgrIP0tF.d.mts → types-i36XcA_X.d.mts} +49 -6
  111. package/dist/types-i36XcA_X.d.mts.map +1 -0
  112. package/dist/{validate-CqsNItbt.mjs → validate-CxVsLehf.mjs} +2 -2
  113. package/dist/{validate-CqsNItbt.mjs.map → validate-CxVsLehf.mjs.map} +1 -1
  114. package/dist/{validate-kM8Pjuf7.d.mts → validate-DHxmpFJt.d.mts} +4 -4
  115. package/dist/{validate-kM8Pjuf7.d.mts.map → validate-DHxmpFJt.d.mts.map} +1 -1
  116. package/dist/validation-C-ZpN2GI.mjs +144 -0
  117. package/dist/validation-C-ZpN2GI.mjs.map +1 -0
  118. package/dist/version-DJrV1K0M.mjs +7 -0
  119. package/dist/{version-BnTKdfam.mjs.map → version-DJrV1K0M.mjs.map} +1 -1
  120. package/dist/zod-generator-CpwccCIv.mjs +132 -0
  121. package/dist/zod-generator-CpwccCIv.mjs.map +1 -0
  122. package/package.json +19 -6
  123. package/src/api/auth-storage.ts +37 -0
  124. package/src/api/error.ts +6 -0
  125. package/src/api/errors.ts +8 -0
  126. package/src/api/handlers/comments.ts +13 -0
  127. package/src/api/handlers/content.ts +122 -3
  128. package/src/api/handlers/index.ts +2 -0
  129. package/src/api/handlers/media.ts +8 -1
  130. package/src/api/handlers/menus.ts +160 -21
  131. package/src/api/handlers/redirects.ts +16 -3
  132. package/src/api/handlers/sections.ts +8 -1
  133. package/src/api/handlers/taxonomies.ts +128 -16
  134. package/src/api/handlers/validation.ts +212 -0
  135. package/src/api/openapi/document.ts +4 -1
  136. package/src/api/public-url.ts +6 -3
  137. package/src/api/route-utils.ts +14 -0
  138. package/src/api/schemas/common.ts +1 -1
  139. package/src/api/schemas/setup.ts +8 -0
  140. package/src/api/schemas/widgets.ts +12 -10
  141. package/src/api/setup-complete.ts +40 -0
  142. package/src/astro/integration/index.ts +13 -2
  143. package/src/astro/integration/routes.ts +28 -0
  144. package/src/astro/integration/runtime.ts +19 -1
  145. package/src/astro/integration/virtual-modules.ts +41 -0
  146. package/src/astro/integration/vite-config.ts +43 -12
  147. package/src/astro/middleware/auth.ts +21 -0
  148. package/src/astro/middleware.ts +18 -1
  149. package/src/astro/routes/PluginRegistry.tsx +10 -1
  150. package/src/astro/routes/api/auth/mode.ts +57 -0
  151. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +23 -3
  152. package/src/astro/routes/api/auth/oauth/[provider].ts +10 -4
  153. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
  154. package/src/astro/routes/api/content/[collection]/index.ts +1 -9
  155. package/src/astro/routes/api/import/wordpress/media.ts +2 -7
  156. package/src/astro/routes/api/import/wordpress/prepare.ts +10 -0
  157. package/src/astro/routes/api/settings/email.ts +4 -9
  158. package/src/astro/routes/api/setup/admin.ts +8 -2
  159. package/src/astro/routes/api/setup/index.ts +2 -2
  160. package/src/astro/routes/api/setup/status.ts +3 -1
  161. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +4 -1
  162. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +4 -1
  163. package/src/astro/routes/api/widget-areas/[name].ts +4 -1
  164. package/src/astro/routes/api/widget-areas/index.ts +4 -1
  165. package/src/astro/types.ts +9 -0
  166. package/src/auth/mode.ts +15 -3
  167. package/src/auth/providers/github-admin.tsx +29 -0
  168. package/src/auth/providers/github.ts +31 -0
  169. package/src/auth/providers/google-admin.tsx +44 -0
  170. package/src/auth/providers/google.ts +31 -0
  171. package/src/auth/types.ts +114 -4
  172. package/src/cli/commands/bundle.ts +3 -1
  173. package/src/components/EmDashImage.astro +7 -6
  174. package/src/components/Gallery.astro +5 -3
  175. package/src/components/Image.astro +8 -3
  176. package/src/components/InlinePortableTextEditor.tsx +2 -1
  177. package/src/components/LiveSearch.astro +5 -14
  178. package/src/database/repositories/audit.ts +6 -8
  179. package/src/database/repositories/byline.ts +6 -8
  180. package/src/database/repositories/comment.ts +12 -16
  181. package/src/database/repositories/content.ts +40 -40
  182. package/src/database/repositories/index.ts +1 -1
  183. package/src/database/repositories/media.ts +10 -13
  184. package/src/database/repositories/plugin-storage.ts +4 -6
  185. package/src/database/repositories/redirect.ts +12 -16
  186. package/src/database/repositories/taxonomy.ts +14 -3
  187. package/src/database/repositories/types.ts +57 -8
  188. package/src/database/repositories/user.ts +6 -8
  189. package/src/emdash-runtime.ts +306 -90
  190. package/src/index.ts +5 -1
  191. package/src/loader.ts +6 -5
  192. package/src/mcp/server.ts +678 -105
  193. package/src/media/normalize.ts +1 -1
  194. package/src/media/url.ts +78 -0
  195. package/src/plugins/email-console.ts +10 -3
  196. package/src/plugins/hooks.ts +11 -0
  197. package/src/plugins/manifest-schema.ts +12 -0
  198. package/src/plugins/types.ts +23 -2
  199. package/src/query.ts +1 -1
  200. package/src/request-cache.ts +3 -0
  201. package/src/schema/registry.ts +41 -5
  202. package/src/search/fts-manager.ts +0 -2
  203. package/src/search/query.ts +111 -26
  204. package/src/search/types.ts +8 -1
  205. package/src/sections/index.ts +7 -9
  206. package/src/storage/s3.ts +12 -6
  207. package/src/virtual-modules.d.ts +21 -1
  208. package/src/widgets/index.ts +1 -1
  209. package/dist/apply-5uslYdUu.mjs.map +0 -1
  210. package/dist/byline-C4OVd8b3.mjs.map +0 -1
  211. package/dist/content-D7J5y73J.mjs.map +0 -1
  212. package/dist/error-CiYn9yDu.mjs.map +0 -1
  213. package/dist/index-De6_Xv3v.d.mts.map +0 -1
  214. package/dist/loader-DeiBJEMe.mjs.map +0 -1
  215. package/dist/manifest-schema-V30qsMft.mjs.map +0 -1
  216. package/dist/media-DqHVh136.mjs.map +0 -1
  217. package/dist/mode-CpNnGkPz.mjs.map +0 -1
  218. package/dist/redirect-CN0Rt9Ob.mjs.map +0 -1
  219. package/dist/registry-Ci3WxVAr.mjs.map +0 -1
  220. package/dist/request-cache-DiR961CV.mjs.map +0 -1
  221. package/dist/search-B0effn3j.mjs.map +0 -1
  222. package/dist/types-CMMN0pNg.mjs +0 -31
  223. package/dist/types-CMMN0pNg.mjs.map +0 -1
  224. package/dist/types-DgrIP0tF.d.mts.map +0 -1
  225. package/dist/version-BnTKdfam.mjs +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/astro/storage/adapters.ts","../../src/astro/integration/font-provider.ts","../../src/astro/integration/routes.ts","../../src/astro/integration/virtual-modules.ts","../../src/astro/integration/vite-config.ts","../../src/astro/integration/runtime.ts","../../src/astro/integration/index.ts"],"sourcesContent":["/**\n * Storage Adapter Functions\n *\n * These run at config time (astro.config.mjs) and return serializable descriptors.\n * The actual storage is created at runtime by loading the entrypoint.\n *\n * @example\n * ```ts\n * // astro.config.mjs\n * import emdash, { s3, local } from \"emdash/astro\";\n *\n * export default defineConfig({\n * integrations: [\n * emdash({\n * storage: s3({\n * endpoint: \"https://xxx.r2.cloudflarestorage.com\",\n * bucket: \"media\",\n * accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n * }),\n * // or: storage: local({ directory: \"./uploads\", baseUrl: \"/_emdash/api/media/file\" }),\n * }),\n * ],\n * });\n * ```\n *\n * For Cloudflare R2 bindings, use `r2()` from `@emdash-cms/cloudflare`.\n */\n\nimport type { StorageDescriptor, S3StorageConfig, LocalStorageConfig } from \"./types.js\";\n\n/**\n * S3-compatible storage adapter\n *\n * Works with AWS S3, Cloudflare R2 (via S3 API), MinIO, etc.\n *\n * Any field omitted here is resolved from the matching `S3_*` environment\n * variable when the container starts (`S3_ENDPOINT`, `S3_BUCKET`,\n * `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_REGION`, `S3_PUBLIC_URL`).\n * Explicit values always take precedence over env vars.\n *\n * Note: env var resolution reads `process.env` on Node at runtime.\n * Workers users should continue passing explicit values to `s3({...})`.\n *\n * @example\n * ```ts\n * // All fields from env (container deployments)\n * storage: s3()\n *\n * // Mix: CDN from config, credentials from env\n * storage: s3({ publicUrl: \"https://cdn.example.com\" })\n *\n * // All explicit (unchanged from before)\n * storage: s3({\n * endpoint: \"https://xxx.r2.cloudflarestorage.com\",\n * bucket: \"media\",\n * accessKeyId: process.env.R2_ACCESS_KEY_ID,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,\n * })\n * ```\n */\nexport function s3(config: Partial<S3StorageConfig> = {}): StorageDescriptor {\n\treturn {\n\t\tentrypoint: \"emdash/storage/s3\",\n\t\tconfig,\n\t};\n}\n\n/**\n * Local filesystem storage adapter\n *\n * For development and testing. Stores files in a local directory.\n * Does NOT support signed upload URLs.\n *\n * @example\n * ```ts\n * storage: local({\n * directory: \"./uploads\",\n * baseUrl: \"/_emdash/api/media/file\",\n * })\n * ```\n */\nexport function local(config: LocalStorageConfig): StorageDescriptor {\n\treturn {\n\t\tentrypoint: \"emdash/storage/local\",\n\t\tconfig,\n\t};\n}\n","/**\n * EmDash Noto Sans font provider\n *\n * A custom Astro font provider that wraps Google Fonts to resolve\n * multiple Noto Sans families (Latin, Arabic, JP, etc.) under a\n * single logical font entry. This lets all @font-face blocks share\n * the same font-family name, so the browser picks the right file\n * per character via unicode-range.\n *\n * Without this, registering \"Noto Sans\" and \"Noto Sans Arabic\" as\n * separate font entries on the same cssVariable triggers an Astro\n * warning and the last entry overwrites the first.\n */\n\nimport { fontProviders } from \"astro/config\";\n\n/**\n * All subset names used by Google Fonts CSS responses.\n * Passed when resolving extra script families so the unifont\n * provider doesn't filter out any faces.\n */\nconst ALL_GOOGLE_SUBSETS = [\n\t\"arabic\",\n\t\"armenian\",\n\t\"bengali\",\n\t\"chinese-simplified\",\n\t\"chinese-traditional\",\n\t\"chinese-hongkong\",\n\t\"cyrillic\",\n\t\"cyrillic-ext\",\n\t\"devanagari\",\n\t\"ethiopic\",\n\t\"farsi\",\n\t\"georgian\",\n\t\"greek\",\n\t\"greek-ext\",\n\t\"gujarati\",\n\t\"gurmukhi\",\n\t\"hebrew\",\n\t\"japanese\",\n\t\"kannada\",\n\t\"khmer\",\n\t\"korean\",\n\t\"lao\",\n\t\"latin\",\n\t\"latin-ext\",\n\t\"malayalam\",\n\t\"math\",\n\t\"myanmar\",\n\t\"oriya\",\n\t\"sinhala\",\n\t\"symbols\",\n\t\"tamil\",\n\t\"telugu\",\n\t\"thai\",\n\t\"tibetan\",\n\t\"vietnamese\",\n];\n\n/**\n * Known Noto Sans and Sans script families on Google Fonts.\n * Maps user-friendly script names to Google Fonts family names.\n */\nconst NOTO_SCRIPT_FAMILIES: Record<string, string> = {\n\tarabic: \"Noto Sans Arabic\",\n\tarmenian: \"Noto Sans Armenian\",\n\tbengali: \"Noto Sans Bengali\",\n\t\"chinese-simplified\": \"Noto Sans SC\",\n\t\"chinese-traditional\": \"Noto Sans TC\",\n\t\"chinese-hongkong\": \"Noto Sans HK\",\n\tdevanagari: \"Noto Sans Devanagari\",\n\tethiopic: \"Noto Sans Ethiopic\",\n\tfarsi: \"Vazirmatn\",\n\tgeorgian: \"Noto Sans Georgian\",\n\tgujarati: \"Noto Sans Gujarati\",\n\tgurmukhi: \"Noto Sans Gurmukhi\",\n\thebrew: \"Noto Sans Hebrew\",\n\tjapanese: \"Noto Sans JP\",\n\tkannada: \"Noto Sans Kannada\",\n\tkhmer: \"Noto Sans Khmer\",\n\tkorean: \"Noto Sans KR\",\n\tlao: \"Noto Sans Lao\",\n\tmalayalam: \"Noto Sans Malayalam\",\n\tmyanmar: \"Noto Sans Myanmar\",\n\toriya: \"Noto Sans Oriya\",\n\tsinhala: \"Noto Sans Sinhala\",\n\ttamil: \"Noto Sans Tamil\",\n\ttelugu: \"Noto Sans Telugu\",\n\tthai: \"Noto Sans Thai\",\n\ttibetan: \"Noto Sans Tibetan\",\n};\n\nexport interface NotoSansProviderOptions {\n\t/**\n\t * Additional Noto Sans script families to include.\n\t * Use script names like \"arabic\", \"japanese\", \"chinese-simplified\".\n\t *\n\t * @see {@link NOTO_SCRIPT_FAMILIES} for the full list of supported scripts.\n\t */\n\tscripts?: string[];\n}\n\n// Use ReturnType to get the provider type without importing it directly.\n// The Astro FontProvider type is not part of the public API surface.\ntype GoogleProvider = ReturnType<typeof fontProviders.google>;\n\n/**\n * Create a font provider that resolves Noto Sans plus additional\n * script-specific Noto families from Google Fonts, all under one\n * font-family name.\n */\nexport function notoSans(options?: NotoSansProviderOptions): GoogleProvider {\n\t// Create a single Google provider instance to share initialization\n\tconst googleProvider = fontProviders.google();\n\n\treturn {\n\t\tname: \"emdash-noto\",\n\t\tasync init(context) {\n\t\t\tawait googleProvider.init?.(context);\n\t\t},\n\t\tasync resolveFont(resolveFontOptions) {\n\t\t\t// Resolve the base Noto Sans (Latin, Cyrillic, Greek, etc.)\n\t\t\tconst base = await googleProvider.resolveFont(resolveFontOptions);\n\t\t\tconst baseFonts = base?.fonts ?? [];\n\n\t\t\tif (!options?.scripts?.length) {\n\t\t\t\treturn base;\n\t\t\t}\n\n\t\t\t// Collect subset names already covered by the base font so we\n\t\t\t// can filter out duplicate faces from extra script families.\n\t\t\t// e.g. Noto Sans Arabic includes latin/latin-ext faces that\n\t\t\t// would otherwise override the base Noto Sans latin faces.\n\t\t\tconst baseSubsets = new Set(baseFonts.map((f) => f.meta?.subset).filter(Boolean));\n\n\t\t\t// Resolve additional script families\n\t\t\tconst extraFonts = await Promise.all(\n\t\t\t\toptions.scripts.map(async (script) => {\n\t\t\t\t\tconst family = NOTO_SCRIPT_FAMILIES[script];\n\t\t\t\t\tif (!family) {\n\t\t\t\t\t\t// Silently skip subset names that are already covered\n\t\t\t\t\t\t// by the base Noto Sans font (latin, cyrillic, etc.)\n\t\t\t\t\t\tif (ALL_GOOGLE_SUBSETS.includes(script)) {\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[emdash] Unknown Noto Sans script \"${script}\". ` +\n\t\t\t\t\t\t\t\t`Available: ${Object.keys(NOTO_SCRIPT_FAMILIES).join(\", \")}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn googleProvider.resolveFont({\n\t\t\t\t\t\t...resolveFontOptions,\n\t\t\t\t\t\tfamilyName: family,\n\t\t\t\t\t\t// Pass all known subset names so the unifont provider\n\t\t\t\t\t\t// doesn't filter out any faces. Each script family\n\t\t\t\t\t\t// only returns faces for its own subsets anyway.\n\t\t\t\t\t\tsubsets: ALL_GOOGLE_SUBSETS,\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\t// Merge, dropping faces from extra fonts that duplicate base subsets\n\t\t\tconst extraFaces = extraFonts.flatMap((r) =>\n\t\t\t\t(r?.fonts ?? []).filter((f) => !f.meta?.subset || !baseSubsets.has(f.meta.subset)),\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tfonts: [...baseFonts, ...extraFaces],\n\t\t\t};\n\t\t},\n\t};\n}\n\n/** Get the list of available Noto Sans script names */\nexport function getAvailableNotoScripts(): string[] {\n\treturn Object.keys(NOTO_SCRIPT_FAMILIES);\n}\n","/**\n * Route Injection\n *\n * Defines and injects all EmDash routes into the Astro application.\n */\n\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Resolve path to a route file in the package\n * Uses Node.js APIs - only call at build time\n */\nfunction resolveRoute(route: string): string {\n\t// Lazy initialization to avoid running Node.js code at import time\n\t// This prevents issues when the module is bundled for Cloudflare Workers\n\tconst require = createRequire(import.meta.url);\n\tconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n\ttry {\n\t\t// Try to resolve as package export\n\t\treturn require.resolve(`emdash/routes/${route}`);\n\t} catch {\n\t\t// Fallback to relative path (for development)\n\t\treturn resolve(__dirname, \"../routes\", route);\n\t}\n}\n\n/** Route injection function type */\ntype InjectRoute = (route: { pattern: string; entrypoint: string }) => void;\n\n/**\n * Injects all core EmDash routes.\n */\nexport function injectCoreRoutes(injectRoute: InjectRoute): void {\n\t// Inject admin shell route\n\tinjectRoute({\n\t\tpattern: \"/_emdash/admin/[...path]\",\n\t\tentrypoint: resolveRoute(\"admin.astro\"),\n\t});\n\n\t// Inject API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/manifest\",\n\t\tentrypoint: resolveRoute(\"api/manifest.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/dashboard\",\n\t\tentrypoint: resolveRoute(\"api/dashboard.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/revisions\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/revisions.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/preview-url\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/preview-url.ts\"),\n\t});\n\n\t// Trash/restore routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/trash\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/trash.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/restore\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/restore.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/permanent\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/permanent.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/duplicate\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/duplicate.ts\"),\n\t});\n\n\t// Publishing routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/publish\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/publish.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/unpublish\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/unpublish.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/discard-draft\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/discard-draft.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/compare\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/compare.ts\"),\n\t});\n\n\t// i18n translation routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/translations\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/translations.ts\"),\n\t});\n\n\t// Scheduled publishing routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/schedule\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/schedule.ts\"),\n\t});\n\n\t// Revision management routes (for restore, etc.)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/revisions/[revisionId]\",\n\t\tentrypoint: resolveRoute(\"api/revisions/[revisionId]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/revisions/[revisionId]/restore\",\n\t\tentrypoint: resolveRoute(\"api/revisions/[revisionId]/restore.ts\"),\n\t});\n\n\t// Media API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media\",\n\t\tentrypoint: resolveRoute(\"api/media.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/upload-url\",\n\t\tentrypoint: resolveRoute(\"api/media/upload-url.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/file/[...key]\",\n\t\tentrypoint: resolveRoute(\"api/media/file/[...key].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/[id]\",\n\t\tentrypoint: resolveRoute(\"api/media/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/[id]/confirm\",\n\t\tentrypoint: resolveRoute(\"api/media/[id]/confirm.ts\"),\n\t});\n\n\t// Media provider routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/providers\",\n\t\tentrypoint: resolveRoute(\"api/media/providers/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/providers/[providerId]\",\n\t\tentrypoint: resolveRoute(\"api/media/providers/[providerId]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/providers/[providerId]/[itemId]\",\n\t\tentrypoint: resolveRoute(\"api/media/providers/[providerId]/[itemId].ts\"),\n\t});\n\n\t// Import API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/probe\",\n\t\tentrypoint: resolveRoute(\"api/import/probe.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/analyze\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/analyze.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/prepare\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/prepare.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/execute\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/execute.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/media\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/media.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/rewrite-urls\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/rewrite-urls.ts\"),\n\t});\n\n\t// WordPress Plugin (EmDash Exporter) direct import routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress-plugin/analyze\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress-plugin/analyze.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress-plugin/execute\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress-plugin/execute.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress-plugin/callback\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress-plugin/callback.ts\"),\n\t});\n\n\t// Schema API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema\",\n\t\tentrypoint: resolveRoute(\"api/schema/index.ts\"),\n\t});\n\n\t// Typegen endpoint (dev-only)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/typegen\",\n\t\tentrypoint: resolveRoute(\"api/typegen.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]/fields\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/fields/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]/fields/reorder\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/fields/reorder.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]/fields/[fieldSlug]\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/fields/[fieldSlug].ts\"),\n\t});\n\n\t// Orphaned tables discovery\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/orphans\",\n\t\tentrypoint: resolveRoute(\"api/schema/orphans/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/orphans/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/schema/orphans/[slug].ts\"),\n\t});\n\n\t// Site settings route\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/settings\",\n\t\tentrypoint: resolveRoute(\"api/settings.ts\"),\n\t});\n\n\t// Email settings route\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/settings/email\",\n\t\tentrypoint: resolveRoute(\"api/settings/email.ts\"),\n\t});\n\n\t// Snapshot route (for DO preview database population)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/snapshot\",\n\t\tentrypoint: resolveRoute(\"api/snapshot.ts\"),\n\t});\n\n\t// Taxonomy API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/taxonomies\",\n\t\tentrypoint: resolveRoute(\"api/taxonomies/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/taxonomies/[name]/terms\",\n\t\tentrypoint: resolveRoute(\"api/taxonomies/[name]/terms/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/taxonomies/[name]/terms/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/taxonomies/[name]/terms/[slug].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/terms/[taxonomy]\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/terms/[taxonomy].ts\"),\n\t});\n\n\t// Plugin management routes (under /admin to avoid conflict with plugin API routes)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/enable\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/enable.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/disable\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/disable.ts\"),\n\t});\n\n\t// Marketplace plugin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace/[id]/icon\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/[id]/icon.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace/[id]/install\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/[id]/install.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/update\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/update.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/uninstall\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/uninstall.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/updates\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/updates.ts\"),\n\t});\n\n\t// Exclusive hooks admin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/hooks/exclusive\",\n\t\tentrypoint: resolveRoute(\"api/admin/hooks/exclusive/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/hooks/exclusive/[hookName]\",\n\t\tentrypoint: resolveRoute(\"api/admin/hooks/exclusive/[hookName].ts\"),\n\t});\n\n\t// Theme marketplace routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/themes/marketplace\",\n\t\tentrypoint: resolveRoute(\"api/admin/themes/marketplace/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/themes/marketplace/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/themes/marketplace/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/themes/marketplace/[id]/thumbnail\",\n\t\tentrypoint: resolveRoute(\"api/admin/themes/marketplace/[id]/thumbnail.ts\"),\n\t});\n\n\t// Theme preview signing (local, not proxied)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/themes/preview\",\n\t\tentrypoint: resolveRoute(\"api/themes/preview.ts\"),\n\t});\n\n\t// User management routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/index.ts\"),\n\t});\n\n\t// Bylines routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/bylines\",\n\t\tentrypoint: resolveRoute(\"api/admin/bylines/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/bylines/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/bylines/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]/disable\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/disable.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]/enable\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/enable.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]/send-recovery\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/send-recovery.ts\"),\n\t});\n\n\t// API token admin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/api-tokens\",\n\t\tentrypoint: resolveRoute(\"api/admin/api-tokens/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/api-tokens/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/api-tokens/[id].ts\"),\n\t});\n\n\t// OAuth client admin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/oauth-clients\",\n\t\tentrypoint: resolveRoute(\"api/admin/oauth-clients/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/oauth-clients/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/oauth-clients/[id].ts\"),\n\t});\n\n\t// OAuth Device Flow routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/device/code\",\n\t\tentrypoint: resolveRoute(\"api/oauth/device/code.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/device/token\",\n\t\tentrypoint: resolveRoute(\"api/oauth/device/token.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/device/authorize\",\n\t\tentrypoint: resolveRoute(\"api/oauth/device/authorize.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/token/refresh\",\n\t\tentrypoint: resolveRoute(\"api/oauth/token/refresh.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/token/revoke\",\n\t\tentrypoint: resolveRoute(\"api/oauth/token/revoke.ts\"),\n\t});\n\n\t// Auth discovery endpoint\n\tinjectRoute({\n\t\tpattern: \"/_emdash/.well-known/auth\",\n\t\tentrypoint: resolveRoute(\"api/well-known/auth.ts\"),\n\t});\n\n\t// OAuth 2.1 Authorization Code flow routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/token\",\n\t\tentrypoint: resolveRoute(\"api/oauth/token.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/oauth/authorize\",\n\t\tentrypoint: resolveRoute(\"api/oauth/authorize.ts\"),\n\t});\n\n\t// OAuth discovery endpoints (RFC 9728, RFC 8414)\n\tinjectRoute({\n\t\tpattern: \"/.well-known/oauth-protected-resource\",\n\t\tentrypoint: resolveRoute(\"api/well-known/oauth-protected-resource.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/.well-known/oauth-authorization-server/_emdash\",\n\t\tentrypoint: resolveRoute(\"api/well-known/oauth-authorization-server.ts\"),\n\t});\n\n\t// RFC 7591 Dynamic Client Registration\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/register\",\n\t\tentrypoint: resolveRoute(\"api/oauth/register.ts\"),\n\t});\n\n\t// Plugin-defined API routes\n\t// All plugin routes are handled by a single catch-all handler\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/plugins/[pluginId]/[...path]\",\n\t\tentrypoint: resolveRoute(\"api/plugins/[pluginId]/[...path].ts\"),\n\t});\n\n\t// Menu API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus\",\n\t\tentrypoint: resolveRoute(\"api/menus/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus/[name]\",\n\t\tentrypoint: resolveRoute(\"api/menus/[name].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus/[name]/items\",\n\t\tentrypoint: resolveRoute(\"api/menus/[name]/items.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus/[name]/reorder\",\n\t\tentrypoint: resolveRoute(\"api/menus/[name]/reorder.ts\"),\n\t});\n\n\t// Widget area routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-components\",\n\t\tentrypoint: resolveRoute(\"api/widget-components.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]/widgets\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name]/widgets.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]/widgets/[id]\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name]/widgets/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]/reorder\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name]/reorder.ts\"),\n\t});\n\n\t// Section routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/sections\",\n\t\tentrypoint: resolveRoute(\"api/sections/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/sections/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/sections/[slug].ts\"),\n\t});\n\n\t// Redirect routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects\",\n\t\tentrypoint: resolveRoute(\"api/redirects/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects/404s/summary\",\n\t\tentrypoint: resolveRoute(\"api/redirects/404s/summary.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects/404s\",\n\t\tentrypoint: resolveRoute(\"api/redirects/404s/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects/[id]\",\n\t\tentrypoint: resolveRoute(\"api/redirects/[id].ts\"),\n\t});\n\n\t// Search routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search\",\n\t\tentrypoint: resolveRoute(\"api/search/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/suggest\",\n\t\tentrypoint: resolveRoute(\"api/search/suggest.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/stats\",\n\t\tentrypoint: resolveRoute(\"api/search/stats.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/rebuild\",\n\t\tentrypoint: resolveRoute(\"api/search/rebuild.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/enable\",\n\t\tentrypoint: resolveRoute(\"api/search/enable.ts\"),\n\t});\n\n\t// Comment routes (public)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/comments/[collection]/[contentId]\",\n\t\tentrypoint: resolveRoute(\"api/comments/[collection]/[contentId]/index.ts\"),\n\t});\n\n\t// Comment routes (admin)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/counts\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/counts.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/bulk\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/bulk.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/[id]/status\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/[id]/status.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/[id].ts\"),\n\t});\n\n\t// SEO routes (public, at site root)\n\tinjectRoute({\n\t\tpattern: \"/sitemap.xml\",\n\t\tentrypoint: resolveRoute(\"sitemap.xml.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/sitemap-[collection].xml\",\n\t\tentrypoint: resolveRoute(\"sitemap-[collection].xml.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/robots.txt\",\n\t\tentrypoint: resolveRoute(\"robots.txt.ts\"),\n\t});\n\n\t// Setup wizard API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/status\",\n\t\tentrypoint: resolveRoute(\"api/setup/status.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup\",\n\t\tentrypoint: resolveRoute(\"api/setup/index.ts\"),\n\t});\n\n\t// Auth API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/admin\",\n\t\tentrypoint: resolveRoute(\"api/setup/admin.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/admin/verify\",\n\t\tentrypoint: resolveRoute(\"api/setup/admin-verify.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/dev-bypass\",\n\t\tentrypoint: resolveRoute(\"api/setup/dev-bypass.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/dev-reset\",\n\t\tentrypoint: resolveRoute(\"api/setup/dev-reset.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/dev/emails\",\n\t\tentrypoint: resolveRoute(\"api/dev/emails.ts\"),\n\t});\n\n\t// Current user endpoint (always available)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/me\",\n\t\tentrypoint: resolveRoute(\"api/auth/me.ts\"),\n\t});\n\n\t// Logout is always available (though behavior differs by auth mode)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/logout\",\n\t\tentrypoint: resolveRoute(\"api/auth/logout.ts\"),\n\t});\n}\n\n/**\n * Injects the MCP (Model Context Protocol) server route.\n * Only injected when `mcp: true` is set in the EmDash config.\n */\nexport function injectMcpRoute(injectRoute: InjectRoute): void {\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/mcp\",\n\t\tentrypoint: resolveRoute(\"api/mcp.ts\"),\n\t});\n}\n\n/**\n * Injects passkey/oauth/magic-link auth routes.\n * Only used when NOT using external auth.\n */\nexport function injectBuiltinAuthRoutes(injectRoute: InjectRoute): void {\n\t// Passkey authentication routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/options\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/options.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/verify.ts\"),\n\t});\n\n\t// Passkey management routes (authenticated users)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/register/options\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/register/options.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/register/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/register/verify.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/[id]\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/dev-bypass\",\n\t\tentrypoint: resolveRoute(\"api/auth/dev-bypass.ts\"),\n\t});\n\n\t// Invite routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite/accept\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/accept.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite/complete\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/complete.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite/register-options\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/register-options.ts\"),\n\t});\n\n\t// Magic link routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/magic-link/send\",\n\t\tentrypoint: resolveRoute(\"api/auth/magic-link/send.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/magic-link/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/magic-link/verify.ts\"),\n\t});\n\n\t// OAuth routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/oauth/[provider]\",\n\t\tentrypoint: resolveRoute(\"api/auth/oauth/[provider].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/oauth/[provider]/callback\",\n\t\tentrypoint: resolveRoute(\"api/auth/oauth/[provider]/callback.ts\"),\n\t});\n\n\t// Self-signup routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/signup/request\",\n\t\tentrypoint: resolveRoute(\"api/auth/signup/request.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/signup/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/signup/verify.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/signup/complete\",\n\t\tentrypoint: resolveRoute(\"api/auth/signup/complete.ts\"),\n\t});\n\n\t// Allowed domains admin routes (only relevant for passkey mode)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/allowed-domains\",\n\t\tentrypoint: resolveRoute(\"api/admin/allowed-domains/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/allowed-domains/[domain]\",\n\t\tentrypoint: resolveRoute(\"api/admin/allowed-domains/[domain].ts\"),\n\t});\n}\n","/**\n * Virtual Module Generators\n *\n * Functions that generate virtual module content for Vite.\n * These modules statically import configured dependencies\n * so Vite can properly resolve and bundle them.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\n\nimport type { MediaProviderDescriptor } from \"../../media/types.js\";\nimport { defaultSeed } from \"../../seed/default.js\";\nimport type { PluginDescriptor } from \"./runtime.js\";\n\nconst TS_SOURCE_EXT_RE = /^\\.(ts|tsx|mts|cts|jsx)$/;\n\n/** Pattern to remove scoped package prefix from plugin ID */\nconst SCOPED_PREFIX_PATTERN = /^@[^/]+\\/plugin-/;\n\n/** Pattern to remove emdash-plugin- prefix from plugin ID */\nconst EMDASH_PREFIX_PATTERN = /^emdash-plugin-/;\n\n// Virtual module IDs\nexport const VIRTUAL_CONFIG_ID = \"virtual:emdash/config\";\nexport const RESOLVED_VIRTUAL_CONFIG_ID = \"\\0\" + VIRTUAL_CONFIG_ID;\n\nexport const VIRTUAL_DIALECT_ID = \"virtual:emdash/dialect\";\nexport const RESOLVED_VIRTUAL_DIALECT_ID = \"\\0\" + VIRTUAL_DIALECT_ID;\n\nexport const VIRTUAL_STORAGE_ID = \"virtual:emdash/storage\";\nexport const RESOLVED_VIRTUAL_STORAGE_ID = \"\\0\" + VIRTUAL_STORAGE_ID;\n\nexport const VIRTUAL_ADMIN_REGISTRY_ID = \"virtual:emdash/admin-registry\";\nexport const RESOLVED_VIRTUAL_ADMIN_REGISTRY_ID = \"\\0\" + VIRTUAL_ADMIN_REGISTRY_ID;\n\nexport const VIRTUAL_PLUGINS_ID = \"virtual:emdash/plugins\";\nexport const RESOLVED_VIRTUAL_PLUGINS_ID = \"\\0\" + VIRTUAL_PLUGINS_ID;\n\nexport const VIRTUAL_SANDBOX_RUNNER_ID = \"virtual:emdash/sandbox-runner\";\nexport const RESOLVED_VIRTUAL_SANDBOX_RUNNER_ID = \"\\0\" + VIRTUAL_SANDBOX_RUNNER_ID;\n\nexport const VIRTUAL_SANDBOXED_PLUGINS_ID = \"virtual:emdash/sandboxed-plugins\";\nexport const RESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID = \"\\0\" + VIRTUAL_SANDBOXED_PLUGINS_ID;\n\nexport const VIRTUAL_AUTH_ID = \"virtual:emdash/auth\";\nexport const RESOLVED_VIRTUAL_AUTH_ID = \"\\0\" + VIRTUAL_AUTH_ID;\n\nexport const VIRTUAL_MEDIA_PROVIDERS_ID = \"virtual:emdash/media-providers\";\nexport const RESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID = \"\\0\" + VIRTUAL_MEDIA_PROVIDERS_ID;\n\nexport const VIRTUAL_BLOCK_COMPONENTS_ID = \"virtual:emdash/block-components\";\nexport const RESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID = \"\\0\" + VIRTUAL_BLOCK_COMPONENTS_ID;\n\nexport const VIRTUAL_SEED_ID = \"virtual:emdash/seed\";\nexport const RESOLVED_VIRTUAL_SEED_ID = \"\\0\" + VIRTUAL_SEED_ID;\n\nexport const VIRTUAL_WAIT_UNTIL_ID = \"virtual:emdash/wait-until\";\nexport const RESOLVED_VIRTUAL_WAIT_UNTIL_ID = \"\\0\" + VIRTUAL_WAIT_UNTIL_ID;\n\n/**\n * Generates the config virtual module.\n */\nexport function generateConfigModule(serializableConfig: Record<string, unknown>): string {\n\treturn `export default ${JSON.stringify(serializableConfig)};`;\n}\n\n/**\n * Generates the dialect virtual module.\n *\n * Adapters that set `supportsRequestScope: true` on their descriptor are\n * expected to export `createRequestScopedDb` from their runtime entrypoint;\n * the generator re-exports it so middleware can ask for a per-request Kysely\n * (used for D1 Sessions API, bookmark cookies, read-replica routing). Other\n * adapters get a stub that returns null.\n */\nexport function generateDialectModule(opts: {\n\tentrypoint?: string;\n\ttype?: string;\n\tsupportsRequestScope: boolean;\n}): string {\n\tconst { entrypoint, supportsRequestScope } = opts;\n\tif (!entrypoint) {\n\t\treturn [\n\t\t\t`export const createDialect = undefined;`,\n\t\t\t`export const dialectType = \"sqlite\";`,\n\t\t\t`export const createRequestScopedDb = (_opts) => null;`,\n\t\t].join(\"\\n\");\n\t}\n\tconst type = opts.type ?? \"sqlite\";\n\n\tif (supportsRequestScope) {\n\t\treturn `\nimport { createDialect as _createDialect } from \"${entrypoint}\";\nexport { createRequestScopedDb } from \"${entrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\n`;\n\t}\n\n\treturn `\nimport { createDialect as _createDialect } from \"${entrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\nexport const createRequestScopedDb = (_opts) => null;\n`;\n}\n\n/**\n * Generates the storage virtual module.\n * Statically imports the configured storage adapter.\n */\nexport function generateStorageModule(storageEntrypoint?: string): string {\n\tif (!storageEntrypoint) {\n\t\treturn `export const createStorage = undefined;`;\n\t}\n\treturn `\nimport { createStorage as _createStorage } from \"${storageEntrypoint}\";\nexport const createStorage = _createStorage;\n`;\n}\n\n/**\n * Generates the auth virtual module.\n * Statically imports the configured auth provider.\n */\nexport function generateAuthModule(authEntrypoint?: string): string {\n\tif (!authEntrypoint) {\n\t\treturn `export const authenticate = undefined;`;\n\t}\n\treturn `\nimport { authenticate as _authenticate } from \"${authEntrypoint}\";\nexport const authenticate = _authenticate;\n`;\n}\n\n/**\n * Generates the plugins module.\n * Imports and instantiates all plugins at runtime.\n *\n * Handles two plugin formats:\n * - **Native**: imports `createPlugin` and calls it with options\n * - **Standard**: imports the default export and wraps it with `adaptSandboxEntry`\n *\n * The format is determined by `descriptor.format`:\n * - `\"standard\"` -- uses adaptSandboxEntry\n * - `\"native\"` or undefined -- uses createPlugin\n *\n * This is critical for Cloudflare Workers where globals don't persist\n * between build time and runtime.\n */\nexport function generatePluginsModule(descriptors: PluginDescriptor[]): string {\n\tif (descriptors.length === 0) {\n\t\treturn `export const plugins = [];`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst instantiations: string[] = [];\n\n\t// Track whether we need the adapter import\n\tlet needsAdapter = false;\n\n\tdescriptors.forEach((descriptor, index) => {\n\t\tif (descriptor.format === \"standard\") {\n\t\t\t// Standard format: import default export, wrap with adaptSandboxEntry\n\t\t\tneedsAdapter = true;\n\t\t\tconst varName = `pluginDef${index}`;\n\t\t\timports.push(`import ${varName} from \"${descriptor.entrypoint}\";`);\n\t\t\tinstantiations.push(\n\t\t\t\t`adaptSandboxEntry(${varName}, ${JSON.stringify({\n\t\t\t\t\tid: descriptor.id,\n\t\t\t\t\tversion: descriptor.version,\n\t\t\t\t\tcapabilities: descriptor.capabilities,\n\t\t\t\t\tallowedHosts: descriptor.allowedHosts,\n\t\t\t\t\tstorage: descriptor.storage,\n\t\t\t\t\tadminPages: descriptor.adminPages,\n\t\t\t\t\tadminWidgets: descriptor.adminWidgets,\n\t\t\t\t})})`,\n\t\t\t);\n\t\t} else {\n\t\t\t// Native format: import createPlugin and call with options\n\t\t\tconst varName = `createPlugin${index}`;\n\t\t\timports.push(`import { createPlugin as ${varName} } from \"${descriptor.entrypoint}\";`);\n\t\t\tinstantiations.push(`${varName}(${JSON.stringify(descriptor.options ?? {})})`);\n\t\t}\n\t});\n\n\tconst adapterImport = needsAdapter\n\t\t? `import { adaptSandboxEntry } from \"emdash/plugins/adapt-sandbox-entry\";\\n`\n\t\t: \"\";\n\n\treturn `\n// Auto-generated plugins module\n// Imports and instantiates all configured plugins at runtime\n\n${adapterImport}${imports.join(\"\\n\")}\n\n/** Resolved plugins array */\nexport const plugins = [\n ${instantiations.join(\",\\n \")}\n];\n`;\n}\n\n/**\n * Generates the admin registry module.\n * Uses adminEntry from plugin descriptors to statically import admin modules.\n */\nexport function generateAdminRegistryModule(descriptors: PluginDescriptor[]): string {\n\t// Filter to descriptors with admin entries\n\tconst adminDescriptors = descriptors.filter((d) => d.adminEntry);\n\n\tif (adminDescriptors.length === 0) {\n\t\treturn `export const pluginAdmins = {};`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst entries: string[] = [];\n\n\tadminDescriptors.forEach((descriptor, index) => {\n\t\tconst varName = `admin${index}`;\n\t\t// Use explicit ID from descriptor if available, otherwise derive from entrypoint\n\t\tconst pluginId =\n\t\t\tdescriptor.id ??\n\t\t\tdescriptor.entrypoint.replace(SCOPED_PREFIX_PATTERN, \"\").replace(EMDASH_PREFIX_PATTERN, \"\");\n\n\t\timports.push(`import * as ${varName} from \"${descriptor.adminEntry}\";`);\n\t\tentries.push(` \"${pluginId}\": ${varName},`);\n\t});\n\n\treturn `\n// Auto-generated plugin admin registry\n${imports.join(\"\\n\")}\n\nexport const pluginAdmins = {\n${entries.join(\"\\n\")}\n};\n`;\n}\n\n/**\n * Generates the sandbox runner module.\n * Imports the configured sandbox runner factory or provides a noop default.\n */\nexport function generateSandboxRunnerModule(sandboxRunner?: string): string {\n\tif (!sandboxRunner) {\n\t\t// No sandbox runner configured - use noop\n\t\treturn `\n// No sandbox runner configured - sandboxed plugins disabled\nimport { createNoopSandboxRunner } from \"emdash\";\n\nexport const createSandboxRunner = createNoopSandboxRunner;\nexport const sandboxEnabled = false;\n`;\n\t}\n\n\treturn `\n// Auto-generated sandbox runner module\nimport { createSandboxRunner as _createSandboxRunner } from \"${sandboxRunner}\";\n\nexport const createSandboxRunner = _createSandboxRunner;\nexport const sandboxEnabled = true;\n`;\n}\n\n/**\n * Generates the media providers module.\n * Imports and instantiates configured media providers at runtime.\n */\nexport function generateMediaProvidersModule(descriptors: MediaProviderDescriptor[]): string {\n\t// Always include local provider by default unless explicitly disabled\n\tconst localDisabled = descriptors.some((d) => d.id === \"local\" && d.config.enabled === false);\n\n\tconst imports: string[] = [];\n\tconst entries: string[] = [];\n\n\t// Add local provider first if not disabled\n\tif (!localDisabled) {\n\t\timports.push(\n\t\t\t`import { createMediaProvider as createLocalProvider } from \"emdash/media/local-runtime\";`,\n\t\t);\n\t\tentries.push(`{\n\tid: \"local\",\n\tname: \"Library\",\n\ticon: \"folder\",\n\tcapabilities: { browse: true, search: false, upload: true, delete: true },\n\tcreateProvider: (ctx) => createLocalProvider({ ...ctx, enabled: true }),\n}`);\n\t}\n\n\t// Add custom providers\n\tdescriptors\n\t\t.filter((d) => d.id !== \"local\" || d.config.enabled !== false)\n\t\t.filter((d) => d.id !== \"local\") // Skip local if we already added it\n\t\t.forEach((descriptor, index) => {\n\t\t\tconst varName = `createProvider${index}`;\n\t\t\timports.push(`import { createMediaProvider as ${varName} } from \"${descriptor.entrypoint}\";`);\n\t\t\tentries.push(`{\n\tid: ${JSON.stringify(descriptor.id)},\n\tname: ${JSON.stringify(descriptor.name)},\n\ticon: ${JSON.stringify(descriptor.icon)},\n\tcapabilities: ${JSON.stringify(descriptor.capabilities)},\n\tcreateProvider: (ctx) => ${varName}({ ...${JSON.stringify(descriptor.config)}, ...ctx }),\n}`);\n\t\t});\n\n\treturn `\n// Auto-generated media providers module\n${imports.join(\"\\n\")}\n\n/** Media provider descriptors with factory functions */\nexport const mediaProviders = [\n ${entries.join(\",\\n \")}\n];\n`;\n}\n\n/**\n * Generates the block components module.\n * Collects and merges `blockComponents` exports from plugin component entries.\n */\nexport function generateBlockComponentsModule(descriptors: PluginDescriptor[]): string {\n\tconst withComponents = descriptors.filter((d) => d.componentsEntry);\n\tif (withComponents.length === 0) {\n\t\treturn `export const pluginBlockComponents = {};`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst spreads: string[] = [];\n\twithComponents.forEach((d, i) => {\n\t\timports.push(`import { blockComponents as bc${i} } from \"${d.componentsEntry}\";`);\n\t\tspreads.push(`...bc${i}`);\n\t});\n\n\treturn `${imports.join(\"\\n\")}\\nexport const pluginBlockComponents = { ${spreads.join(\", \")} };`;\n}\n\n/**\n * Generates the wait-until virtual module.\n *\n * Under @astrojs/cloudflare, re-exports `waitUntil` from `cloudflare:workers`\n * so `after(fn)` in core can extend the worker's lifetime past the response\n * for deferred bookkeeping. For any other adapter, exports `undefined` —\n * Node's long-lived event loop keeps deferred promises running without a\n * lifetime extender.\n *\n * Keeping the adapter check here — rather than in core — means core itself\n * has no Cloudflare-specific imports or code paths.\n */\nexport function generateWaitUntilModule(adapterName: string | undefined): string {\n\tif (adapterName === \"@astrojs/cloudflare\") {\n\t\treturn `export { waitUntil } from \"cloudflare:workers\";`;\n\t}\n\treturn `export const waitUntil = undefined;`;\n}\n\n/**\n * Generates the seed virtual module.\n * Reads the user's seed file at build time (in Node context) and embeds it,\n * so the runtime doesn't need filesystem access (required for workerd).\n *\n * Exports `userSeed` (user's seed or null) and `seed` (user's seed or default).\n */\nexport function generateSeedModule(projectRoot: string): string {\n\tlet userSeedJson: string | null = null;\n\n\t// Try .emdash/seed.json\n\ttry {\n\t\tconst seedPath = resolve(projectRoot, \".emdash\", \"seed.json\");\n\t\tconst content = readFileSync(seedPath, \"utf-8\");\n\t\tJSON.parse(content); // validate\n\t\tuserSeedJson = content;\n\t} catch {\n\t\t// Not found, try next\n\t}\n\n\t// Try package.json → emdash.seed reference\n\tif (!userSeedJson) {\n\t\ttry {\n\t\t\tconst pkgPath = resolve(projectRoot, \"package.json\");\n\t\t\tconst pkgContent = readFileSync(pkgPath, \"utf-8\");\n\t\t\tconst pkg: { emdash?: { seed?: string } } = JSON.parse(pkgContent);\n\n\t\t\tif (pkg.emdash?.seed) {\n\t\t\t\tconst seedPath = resolve(projectRoot, pkg.emdash.seed);\n\t\t\t\tconst content = readFileSync(seedPath, \"utf-8\");\n\t\t\t\tJSON.parse(content); // validate\n\t\t\t\tuserSeedJson = content;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not found\n\t\t}\n\t}\n\n\tif (userSeedJson) {\n\t\treturn [`export const userSeed = ${userSeedJson};`, `export const seed = userSeed;`].join(\"\\n\");\n\t}\n\n\t// No user seed — inline the default\n\treturn [\n\t\t`export const userSeed = null;`,\n\t\t`export const seed = ${JSON.stringify(defaultSeed)};`,\n\t].join(\"\\n\");\n}\n\n/**\n * Resolve a module specifier from the project's context.\n * Uses Node.js require.resolve with the project root as base.\n */\nfunction resolveModulePathFromProject(specifier: string, projectRoot: string): string {\n\t// Create require from the project's package.json location\n\tconst projectPackageJson = resolve(projectRoot, \"package.json\");\n\tconst require = createRequire(projectPackageJson);\n\treturn require.resolve(specifier);\n}\n\n/**\n * Generates the sandboxed plugins module.\n * Resolves plugin entrypoints to files, reads them, and embeds the code.\n *\n * At runtime, middleware uses SandboxRunner to load these into isolates.\n */\nexport function generateSandboxedPluginsModule(\n\tsandboxed: PluginDescriptor[],\n\tprojectRoot: string,\n): string {\n\tif (sandboxed.length === 0) {\n\t\treturn `\n// No sandboxed plugins configured\nexport const sandboxedPlugins = [];\n`;\n\t}\n\n\tconst pluginEntries: string[] = [];\n\n\tfor (const descriptor of sandboxed) {\n\t\tconst bundleSpecifier = descriptor.entrypoint;\n\n\t\t// Resolve the bundle to a file path using project's require context\n\t\tconst filePath = resolveModulePathFromProject(bundleSpecifier, projectRoot);\n\n\t\tconst ext = filePath.slice(filePath.lastIndexOf(\".\"));\n\t\tif (TS_SOURCE_EXT_RE.test(ext)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Sandboxed plugin \"${descriptor.id}\" entrypoint \"${bundleSpecifier}\" resolves to ` +\n\t\t\t\t\t`unbuilt source (${filePath}). Sandbox entries must be pre-built JavaScript. ` +\n\t\t\t\t\t`Ensure the plugin's package.json exports point to built files (e.g. dist/*.mjs) ` +\n\t\t\t\t\t`and run the plugin's build step before building the site.`,\n\t\t\t);\n\t\t}\n\n\t\tconst code = readFileSync(filePath, \"utf-8\");\n\n\t\t// Create the plugin entry with embedded code and sandbox config\n\t\tpluginEntries.push(`{\n id: ${JSON.stringify(descriptor.id)},\n version: ${JSON.stringify(descriptor.version)},\n options: ${JSON.stringify(descriptor.options ?? {})},\n capabilities: ${JSON.stringify(descriptor.capabilities ?? [])},\n allowedHosts: ${JSON.stringify(descriptor.allowedHosts ?? [])},\n storage: ${JSON.stringify(descriptor.storage ?? {})},\n adminPages: ${JSON.stringify(descriptor.adminPages ?? [])},\n adminWidgets: ${JSON.stringify(descriptor.adminWidgets ?? [])},\n adminEntry: ${JSON.stringify(descriptor.adminEntry)},\n // Code read from: ${filePath}\n code: ${JSON.stringify(code)},\n }`);\n\t}\n\n\treturn `\n// Auto-generated sandboxed plugins module\n// Plugin code is embedded at build time\n\n/**\n * Sandboxed plugin entries with embedded code.\n * Loaded at runtime via SandboxRunner.\n */\nexport const sandboxedPlugins = [\n ${pluginEntries.join(\",\\n \")}\n];\n`;\n}\n","/**\n * Vite Plugin Configuration\n *\n * Defines the Vite plugin that handles virtual modules and other\n * Vite-specific configuration for EmDash.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { AstroConfig } from \"astro\";\nimport type { Plugin } from \"vite\";\n\nimport { COMMIT, VERSION } from \"../../version.js\";\nimport type { EmDashConfig, PluginDescriptor } from \"./runtime.js\";\nimport {\n\tVIRTUAL_CONFIG_ID,\n\tRESOLVED_VIRTUAL_CONFIG_ID,\n\tVIRTUAL_DIALECT_ID,\n\tRESOLVED_VIRTUAL_DIALECT_ID,\n\tVIRTUAL_STORAGE_ID,\n\tRESOLVED_VIRTUAL_STORAGE_ID,\n\tVIRTUAL_ADMIN_REGISTRY_ID,\n\tRESOLVED_VIRTUAL_ADMIN_REGISTRY_ID,\n\tVIRTUAL_PLUGINS_ID,\n\tRESOLVED_VIRTUAL_PLUGINS_ID,\n\tVIRTUAL_SANDBOX_RUNNER_ID,\n\tRESOLVED_VIRTUAL_SANDBOX_RUNNER_ID,\n\tVIRTUAL_SANDBOXED_PLUGINS_ID,\n\tRESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID,\n\tVIRTUAL_AUTH_ID,\n\tRESOLVED_VIRTUAL_AUTH_ID,\n\tVIRTUAL_MEDIA_PROVIDERS_ID,\n\tRESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID,\n\tVIRTUAL_BLOCK_COMPONENTS_ID,\n\tRESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID,\n\tVIRTUAL_SEED_ID,\n\tRESOLVED_VIRTUAL_SEED_ID,\n\tVIRTUAL_WAIT_UNTIL_ID,\n\tRESOLVED_VIRTUAL_WAIT_UNTIL_ID,\n\tgenerateSeedModule,\n\tgenerateWaitUntilModule,\n\tgenerateConfigModule,\n\tgenerateDialectModule,\n\tgenerateStorageModule,\n\tgenerateAuthModule,\n\tgeneratePluginsModule,\n\tgenerateAdminRegistryModule,\n\tgenerateSandboxRunnerModule,\n\tgenerateSandboxedPluginsModule,\n\tgenerateMediaProvidersModule,\n\tgenerateBlockComponentsModule,\n} from \"./virtual-modules.js\";\n\nconst LOCALE_MESSAGES_RE = /[/\\\\]([a-z]{2}(?:-[A-Z]{2})?)[/\\\\]messages\\.mjs$/;\n/**\n * Vite plugin that compiles Lingui macros in admin source files.\n * Only active in dev mode when the admin package is aliased to source for HMR.\n * @babel/core is dynamically imported from admin's devDependencies —\n * not declared by core, never ships to end users.\n */\nfunction linguiMacroPlugin(adminSourcePath: string, adminDistPath: string): Plugin {\n\t// Resolve @babel/core from admin's devDependencies, not core's.\n\tconst adminRequire = createRequire(resolve(adminDistPath, \"index.js\"));\n\tconst babelCorePath = adminRequire.resolve(\"@babel/core\");\n\n\treturn {\n\t\tname: \"emdash-lingui-macro\",\n\t\tenforce: \"pre\",\n\t\tresolveId(id, importer) {\n\t\t\t// Redirect relative locale catalog imports (e.g. ./de/messages.mjs) from\n\t\t\t// within admin source to the compiled dist/locales/ directory, since\n\t\t\t// lingui compile only runs during build — not in dev watch mode.\n\t\t\tif (!importer?.startsWith(adminSourcePath)) return;\n\t\t\tconst match = id.match(LOCALE_MESSAGES_RE);\n\t\t\tif (match?.[1]) {\n\t\t\t\treturn resolve(adminDistPath, \"locales\", match[1], \"messages.mjs\");\n\t\t\t}\n\t\t},\n\t\tasync transform(code, id) {\n\t\t\tif (!id.startsWith(adminSourcePath) || !code.includes(\"@lingui\")) return;\n\t\t\tconst { transformAsync } = (await import(babelCorePath)) as typeof import(\"@babel/core\");\n\t\t\tconst result = await transformAsync(code, {\n\t\t\t\tfilename: id,\n\t\t\t\tplugins: [\"@lingui/babel-plugin-lingui-macro\"],\n\t\t\t\tparserOpts: { plugins: [\"jsx\", \"typescript\"] },\n\t\t\t});\n\t\t\tif (!result?.code) return;\n\t\t\treturn { code: result.code, map: result.map ?? undefined };\n\t\t},\n\t};\n}\n\n/**\n * Resolve path to the admin package dist directory.\n * Used for Vite alias to ensure the package is found in pnpm's isolated node_modules.\n */\nfunction resolveAdminDist(): string {\n\tconst require = createRequire(import.meta.url);\n\tconst adminPath = require.resolve(\"@emdash-cms/admin\");\n\t// Return the directory containing the built package (dist/)\n\treturn dirname(adminPath);\n}\n\n/**\n * Resolve path to the admin package source directory.\n * In dev mode, we alias @emdash-cms/admin to the source so Vite processes it\n * directly — giving instant HMR instead of requiring a rebuild + restart.\n */\nfunction resolveAdminSource(): string | undefined {\n\tconst require = createRequire(import.meta.url);\n\tconst adminPath = require.resolve(\"@emdash-cms/admin\");\n\t// dist/index.js -> go up to package root, then into src/\n\tconst packageRoot = resolve(dirname(adminPath), \"..\");\n\tconst srcEntry = resolve(packageRoot, \"src\", \"index.ts\");\n\n\ttry {\n\t\tif (existsSync(srcEntry)) {\n\t\t\treturn resolve(packageRoot, \"src\");\n\t\t}\n\t} catch {\n\t\t// Not in monorepo — fall back to dist\n\t}\n\treturn undefined;\n}\n\nexport interface VitePluginOptions {\n\t/** Serializable config (database, storage, auth descriptors) */\n\tserializableConfig: Record<string, unknown>;\n\t/** Resolved EmDash config */\n\tresolvedConfig: EmDashConfig;\n\t/** Plugin descriptors */\n\tpluginDescriptors: PluginDescriptor[];\n\t/** Astro config */\n\tastroConfig: AstroConfig;\n}\n\n/**\n * Creates the EmDash virtual modules Vite plugin.\n */\nexport function createVirtualModulesPlugin(options: VitePluginOptions): Plugin {\n\tconst { serializableConfig, resolvedConfig, pluginDescriptors, astroConfig } = options;\n\n\treturn {\n\t\tname: \"emdash-virtual-modules\",\n\t\tresolveId(id: string) {\n\t\t\tif (id === VIRTUAL_CONFIG_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_CONFIG_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_DIALECT_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_DIALECT_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_STORAGE_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_STORAGE_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_ADMIN_REGISTRY_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_ADMIN_REGISTRY_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_PLUGINS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_PLUGINS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_SANDBOX_RUNNER_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_SANDBOX_RUNNER_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_SANDBOXED_PLUGINS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_AUTH_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_AUTH_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_MEDIA_PROVIDERS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_BLOCK_COMPONENTS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_SEED_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_SEED_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_WAIT_UNTIL_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_WAIT_UNTIL_ID;\n\t\t\t}\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id === RESOLVED_VIRTUAL_CONFIG_ID) {\n\t\t\t\treturn generateConfigModule(serializableConfig);\n\t\t\t}\n\t\t\t// Generate a module that statically imports the configured dialect\n\t\t\t// This allows Vite to properly resolve and bundle it\n\t\t\tif (id === RESOLVED_VIRTUAL_DIALECT_ID) {\n\t\t\t\treturn generateDialectModule({\n\t\t\t\t\tentrypoint: resolvedConfig.database?.entrypoint,\n\t\t\t\t\ttype: resolvedConfig.database?.type,\n\t\t\t\t\tsupportsRequestScope: resolvedConfig.database?.supportsRequestScope ?? false,\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Generate a module that statically imports the configured storage\n\t\t\tif (id === RESOLVED_VIRTUAL_STORAGE_ID) {\n\t\t\t\treturn generateStorageModule(resolvedConfig.storage?.entrypoint);\n\t\t\t}\n\t\t\t// Generate plugins module that imports and instantiates all plugins\n\t\t\tif (id === RESOLVED_VIRTUAL_PLUGINS_ID) {\n\t\t\t\treturn generatePluginsModule(pluginDescriptors);\n\t\t\t}\n\t\t\t// Generate admin registry module with plugin components\n\t\t\tif (id === RESOLVED_VIRTUAL_ADMIN_REGISTRY_ID) {\n\t\t\t\t// Include both trusted and sandboxed plugins\n\t\t\t\tconst allDescriptors = [...pluginDescriptors, ...(resolvedConfig.sandboxed ?? [])];\n\t\t\t\treturn generateAdminRegistryModule(allDescriptors);\n\t\t\t}\n\t\t\t// Generate sandbox runner module\n\t\t\tif (id === RESOLVED_VIRTUAL_SANDBOX_RUNNER_ID) {\n\t\t\t\treturn generateSandboxRunnerModule(resolvedConfig.sandboxRunner);\n\t\t\t}\n\t\t\t// Generate sandboxed plugins config module\n\t\t\tif (id === RESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID) {\n\t\t\t\t// Pass project root for proper module resolution\n\t\t\t\tconst projectRoot = fileURLToPath(astroConfig.root);\n\t\t\t\treturn generateSandboxedPluginsModule(resolvedConfig.sandboxed ?? [], projectRoot);\n\t\t\t}\n\t\t\t// Generate auth module that statically imports the configured auth provider\n\t\t\tif (id === RESOLVED_VIRTUAL_AUTH_ID) {\n\t\t\t\tconst authDescriptor = resolvedConfig.auth;\n\t\t\t\tif (!authDescriptor || !(\"entrypoint\" in authDescriptor)) {\n\t\t\t\t\treturn generateAuthModule(undefined);\n\t\t\t\t}\n\t\t\t\treturn generateAuthModule(authDescriptor.entrypoint);\n\t\t\t}\n\t\t\t// Generate media providers module\n\t\t\tif (id === RESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID) {\n\t\t\t\treturn generateMediaProvidersModule(resolvedConfig.mediaProviders ?? []);\n\t\t\t}\n\t\t\t// Generate block components module (plugin rendering components for PortableText)\n\t\t\tif (id === RESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID) {\n\t\t\t\treturn generateBlockComponentsModule(pluginDescriptors);\n\t\t\t}\n\t\t\t// Generate seed module — embeds user seed or default at build time\n\t\t\tif (id === RESOLVED_VIRTUAL_SEED_ID) {\n\t\t\t\tconst projectRoot = fileURLToPath(astroConfig.root);\n\t\t\t\treturn generateSeedModule(projectRoot);\n\t\t\t}\n\t\t\t// Generate wait-until module — re-exports cloudflare:workers'\n\t\t\t// waitUntil under the Cloudflare adapter, undefined otherwise.\n\t\t\tif (id === RESOLVED_VIRTUAL_WAIT_UNTIL_ID) {\n\t\t\t\treturn generateWaitUntilModule(astroConfig.adapter?.name);\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Modules that contain native Node.js addons or Node-only code.\n * These must be external in SSR to avoid bundling failures on Node.\n * On Cloudflare, the adapter handles its own externalization — setting\n * ssr.external there conflicts with @cloudflare/vite-plugin's validation.\n */\nconst NODE_NATIVE_EXTERNALS = [\n\t\"better-sqlite3\",\n\t\"bindings\",\n\t\"file-uri-to-path\",\n\t\"@libsql/kysely-libsql\",\n\t\"pg\",\n];\n\n/**\n * Detect whether the Cloudflare adapter is being used.\n */\nfunction isCloudflareAdapter(astroConfig: AstroConfig): boolean {\n\treturn astroConfig.adapter?.name === \"@astrojs/cloudflare\";\n}\n\n/**\n * Creates the Vite config update for EmDash.\n */\nexport function createViteConfig(\n\toptions: VitePluginOptions,\n\tcommand: \"dev\" | \"build\" | \"preview\" | \"sync\",\n): NonNullable<AstroConfig[\"vite\"]> {\n\tconst adminDistPath = resolveAdminDist();\n\tconst cloudflare = isCloudflareAdapter(options.astroConfig);\n\tconst isDev = command === \"dev\";\n\n\t// In dev mode within the monorepo, alias JS imports to source for instant HMR.\n\t// CSS always comes from dist/ (pre-compiled by @tailwindcss/cli) since Tailwind's\n\t// Vite plugin has native deps that don't bundle well. Run `pnpm dev` in packages/admin\n\t// alongside the demo server to get CSS watch-rebuilds too.\n\tconst adminSourcePath = isDev ? resolveAdminSource() : undefined;\n\tconst useSource = adminSourcePath !== undefined;\n\n\treturn {\n\t\t// Astro SSR routes resolve version.ts from source (not tsdown dist),\n\t\t// so Vite needs its own define pass for the __EMDASH_*__ placeholders.\n\t\tdefine: {\n\t\t\t__EMDASH_VERSION__: JSON.stringify(VERSION),\n\t\t\t__EMDASH_COMMIT__: JSON.stringify(COMMIT),\n\t\t\t__EMDASH_PSEUDO_LOCALE__: JSON.stringify(\n\t\t\t\tisDev && process.env[\"EMDASH_PSEUDO_LOCALE\"] === \"1\",\n\t\t\t),\n\t\t},\n\t\tresolve: {\n\t\t\tdedupe: [\"@emdash-cms/admin\", \"react\", \"react-dom\"],\n\t\t\t// Array form so more-specific entries are checked first.\n\t\t\t// The styles.css alias must come before the package alias, otherwise\n\t\t\t// Vite's prefix matching on \"@emdash-cms/admin\" would resolve\n\t\t\t// \"@emdash-cms/admin/styles.css\" through the source directory.\n\t\t\talias: [\n\t\t\t\t{ find: \"@emdash-cms/admin/styles.css\", replacement: resolve(adminDistPath, \"styles.css\") },\n\t\t\t\t{ find: \"@emdash-cms/admin\", replacement: useSource ? adminSourcePath : adminDistPath },\n\t\t\t],\n\t\t},\n\t\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Monorepo has both vite 6 (docs) and vite 7 (core). tsgo resolves correctly.\n\t\tplugins: [\n\t\t\tcreateVirtualModulesPlugin(options),\n\t\t\t// In dev mode with source alias, compile Lingui macros on the fly\n\t\t\t// and redirect locale .mjs imports to dist/.\n\t\t\t// In production, macros are pre-compiled by tsdown in the admin package.\n\t\t\t...(useSource ? [linguiMacroPlugin(adminSourcePath!, adminDistPath)] : []),\n\t\t] as NonNullable<AstroConfig[\"vite\"]>[\"plugins\"],\n\t\t// Handle native modules for SSR.\n\t\t// On Node: external keeps native addons out of the SSR bundle.\n\t\t// On Cloudflare: skip — the adapter handles externalization, and setting\n\t\t// ssr.external conflicts with @cloudflare/vite-plugin's resolve.external validation.\n\t\tssr: cloudflare\n\t\t\t? {\n\t\t\t\t\tnoExternal: [\"emdash\", \"@emdash-cms/admin\"],\n\t\t\t\t\t// Pre-bundle EmDash's runtime deps for workerd. Without this,\n\t\t\t\t\t// Vite discovers them one-by-one on first request, causing workerd\n\t\t\t\t\t// to enter \"worker cancelled\" state on cold cache.\n\t\t\t\t\toptimizeDeps: {\n\t\t\t\t\t\t// Exclude EmDash virtual modules from esbuild's dependency\n\t\t\t\t\t\t// scan. These are resolved by the Vite plugin at transform time,\n\t\t\t\t\t\t// but esbuild encounters them when crawling emdash's dist files\n\t\t\t\t\t\t// during pre-bundling and can't resolve them. Vite's exclude\n\t\t\t\t\t\t// uses prefix matching (id.startsWith(m + \"/\")), so\n\t\t\t\t\t\t// \"virtual:emdash\" matches all \"virtual:emdash/*\" imports.\n\t\t\t\t\t\texclude: [\"virtual:emdash\"],\n\t\t\t\t\t\tinclude: [\n\t\t\t\t\t\t\t// EmDash direct deps\n\t\t\t\t\t\t\t\"emdash > @portabletext/toolkit\",\n\t\t\t\t\t\t\t\"emdash > @unpic/placeholder\",\n\t\t\t\t\t\t\t\"emdash > blurhash\",\n\t\t\t\t\t\t\t\"emdash > croner\",\n\t\t\t\t\t\t\t\"emdash > image-size\",\n\t\t\t\t\t\t\t\"emdash > jose\",\n\t\t\t\t\t\t\t\"emdash > jpeg-js\",\n\t\t\t\t\t\t\t\"emdash > kysely\",\n\t\t\t\t\t\t\t\"emdash > mime/lite\",\n\t\t\t\t\t\t\t\"emdash > modern-tar\",\n\t\t\t\t\t\t\t\"emdash > sanitize-html\",\n\t\t\t\t\t\t\t\"emdash > ulidx\",\n\t\t\t\t\t\t\t\"emdash > upng-js\",\n\t\t\t\t\t\t\t\"emdash > astro-portabletext\",\n\t\t\t\t\t\t\t\"emdash > sax\",\n\t\t\t\t\t\t\t// Deeper transitive deps\n\t\t\t\t\t\t\t\"emdash > sanitize-html > parse5\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/gutenberg-to-portable-text > @wordpress/block-serialization-default-parser\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/auth > @oslojs/crypto/ecdsa\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/auth > @oslojs/crypto/sha2\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/auth > @oslojs/webauthn\",\n\t\t\t\t\t\t\t// MCP SDK — server/index.js statically imports ajv (CJS-only).\n\t\t\t\t\t\t\t// Pre-bundling converts CJS to ESM so workerd can load it.\n\t\t\t\t\t\t\t\"emdash > @modelcontextprotocol/sdk > ajv\",\n\t\t\t\t\t\t\t\"emdash > @modelcontextprotocol/sdk > ajv-formats\",\n\t\t\t\t\t\t\t// React (commonly used, may be hoisted)\n\t\t\t\t\t\t\t\"react\",\n\t\t\t\t\t\t\t\"react/jsx-dev-runtime\",\n\t\t\t\t\t\t\t\"react/jsx-runtime\",\n\t\t\t\t\t\t\t\"react-dom\",\n\t\t\t\t\t\t\t\"react-dom/server\",\n\t\t\t\t\t\t\t// Top-level deps (use astro > path for pnpm compat)\n\t\t\t\t\t\t\t\"astro > zod/v4\",\n\t\t\t\t\t\t\t\"astro > zod/v4/core\",\n\t\t\t\t\t\t\t\"@emdash-cms/cloudflare > kysely-d1\",\n\t\t\t\t\t\t\t// Astro internal deps not covered by @astrojs/cloudflare adapter\n\t\t\t\t\t\t\t\"astro/virtual-modules/middleware.js\",\n\t\t\t\t\t\t\t\"astro/virtual-modules/live-config\",\n\t\t\t\t\t\t\t\"astro/content/runtime\",\n\t\t\t\t\t\t\t\"astro/assets/utils/inferRemoteSize.js\",\n\t\t\t\t\t\t\t\"astro/assets/fonts/runtime.js\",\n\t\t\t\t\t\t\t\"@astrojs/cloudflare/image-service\",\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\texternal: NODE_NATIVE_EXTERNALS,\n\t\t\t\t\tnoExternal: [\"emdash\", \"@emdash-cms/admin\"],\n\t\t\t\t},\n\t\toptimizeDeps: {\n\t\t\t// When using source, don't pre-bundle JS — let Vite transform on the fly for HMR.\n\t\t\t// When using dist, pre-bundle to avoid re-optimization on first hydration.\n\t\t\tinclude: useSource\n\t\t\t\t? [\"@astrojs/react/client.js\"]\n\t\t\t\t: [\"@emdash-cms/admin\", \"@astrojs/react/client.js\"],\n\t\t\texclude: cloudflare ? [\"virtual:emdash\"] : [...NODE_NATIVE_EXTERNALS, \"virtual:emdash\"],\n\t\t},\n\t};\n}\n","/**\n * Runtime utilities for EmDash\n *\n * This file contains functions that are used at runtime (in middleware, routes, etc.)\n * and must work in all environments including Cloudflare Workers.\n *\n * DO NOT import Node.js-only modules here (fs, path, module, etc.)\n */\n\nimport type { AuthDescriptor } from \"../../auth/types.js\";\nimport type { DatabaseDescriptor } from \"../../db/adapters.js\";\nimport type { MediaProviderDescriptor } from \"../../media/types.js\";\nimport type { ResolvedPlugin } from \"../../plugins/types.js\";\nimport type { StorageDescriptor } from \"../storage/types.js\";\n\nexport type { ResolvedPlugin };\nexport type { MediaProviderDescriptor };\n\n/**\n * Admin page definition (copied from plugins/types to avoid circular deps)\n */\nexport interface PluginAdminPage {\n\tpath: string;\n\tlabel: string;\n\ticon?: string;\n}\n\n/**\n * Dashboard widget definition (copied from plugins/types to avoid circular deps)\n */\nexport interface PluginDashboardWidget {\n\tid: string;\n\tsize?: \"full\" | \"half\" | \"third\";\n\ttitle?: string;\n}\n\n/**\n * Plugin descriptor - returned by plugin factory functions\n *\n * Contains all static metadata needed for manifest and admin UI,\n * plus the entrypoint for runtime instantiation.\n *\n * @example\n * ```ts\n * export function myPlugin(options?: MyPluginOptions): PluginDescriptor {\n * return {\n * id: \"my-plugin\",\n * version: \"1.0.0\",\n * entrypoint: \"@my-org/emdash-plugin-foo\",\n * options: options ?? {},\n * adminEntry: \"@my-org/emdash-plugin-foo/admin\",\n * adminPages: [{ path: \"/settings\", label: \"Settings\" }],\n * };\n * }\n * ```\n */\n/**\n * Storage collection declaration for sandboxed plugins\n */\nexport interface StorageCollectionDeclaration {\n\tindexes?: string[];\n\tuniqueIndexes?: string[];\n}\n\nexport interface PluginDescriptor<TOptions = Record<string, unknown>> {\n\t/** Unique plugin identifier */\n\tid: string;\n\t/** Plugin version (semver) */\n\tversion: string;\n\t/** Module specifier to import (e.g., \"@emdash-cms/plugin-api-test\") */\n\tentrypoint: string;\n\t/**\n\t * Options to pass to createPlugin(). Native format only.\n\t * Standard-format plugins configure themselves via KV settings\n\t * and Block Kit admin pages -- not constructor options.\n\t */\n\toptions?: TOptions;\n\t/**\n\t * Plugin format. Determines how the entrypoint is loaded:\n\t * - `\"standard\"` -- exports `definePlugin({ hooks, routes })` as default.\n\t * Wrapped with `adaptSandboxEntry` for in-process execution. Can run in both\n\t * `plugins: []` (in-process) and `sandboxed: []` (isolate).\n\t * - `\"native\"` -- exports `createPlugin(options)` returning a `ResolvedPlugin`.\n\t * Can only run in `plugins: []`. Cannot be sandboxed or published to marketplace.\n\t *\n\t * Defaults to `\"native\"` when unset.\n\t *\n\t */\n\tformat?: \"standard\" | \"native\";\n\t/** Admin UI module specifier (e.g., \"@emdash-cms/plugin-audit-log/admin\") */\n\tadminEntry?: string;\n\t/** Module specifier for site-side Astro rendering components (must export `blockComponents`) */\n\tcomponentsEntry?: string;\n\t/** Admin pages for navigation */\n\tadminPages?: PluginAdminPage[];\n\t/** Dashboard widgets */\n\tadminWidgets?: PluginDashboardWidget[];\n\n\t// === Sandbox-specific fields (for sandboxed plugins) ===\n\n\t/**\n\t * Capabilities the plugin requests.\n\t * For standard-format plugins, capabilities are enforced in both trusted and\n\t * sandboxed modes via the PluginContextFactory.\n\t */\n\tcapabilities?: string[];\n\t/**\n\t * Allowed hosts for network:fetch capability\n\t * Supports wildcards like \"*.example.com\"\n\t */\n\tallowedHosts?: string[];\n\t/**\n\t * Storage collections the plugin declares\n\t * Sandboxed plugins can only access declared collections.\n\t */\n\tstorage?: Record<string, StorageCollectionDeclaration>;\n}\n\n/**\n * Sandboxed plugin descriptor - same format as PluginDescriptor\n *\n * These run in isolated V8 isolates via Worker Loader on Cloudflare.\n * The `entrypoint` is resolved to a file and bundled at build time.\n */\nexport type SandboxedPluginDescriptor<TOptions = Record<string, unknown>> =\n\tPluginDescriptor<TOptions>;\n\nexport interface EmDashConfig {\n\t/**\n\t * Database configuration\n\t *\n\t * Use one of the adapter functions:\n\t * - `sqlite({ url: \"file:./data.db\" })` - Local SQLite\n\t * - `libsql({ url: \"...\", authToken: \"...\" })` - Turso/libSQL\n\t * - `d1({ binding: \"DB\" })` - Cloudflare D1\n\t *\n\t * @example\n\t * ```ts\n\t * import { sqlite } from \"emdash/db\";\n\t *\n\t * emdash({\n\t * database: sqlite({ url: \"file:./data.db\" }),\n\t * })\n\t * ```\n\t */\n\tdatabase?: DatabaseDescriptor;\n\t/**\n\t * Storage configuration (for media)\n\t */\n\tstorage?: StorageDescriptor;\n\t/**\n\t * Trusted plugins to load (run in main isolate)\n\t *\n\t * @example\n\t * ```ts\n\t * import { auditLogPlugin } from \"@emdash-cms/plugin-audit-log\";\n\t * import { webhookNotifierPlugin } from \"@emdash-cms/plugin-webhook-notifier\";\n\t *\n\t * emdash({\n\t * plugins: [\n\t * auditLogPlugin(),\n\t * webhookNotifierPlugin({ url: \"https://example.com/webhook\" }),\n\t * ],\n\t * })\n\t * ```\n\t */\n\tplugins?: PluginDescriptor[];\n\t/**\n\t * Sandboxed plugins to load (run in isolated V8 isolates)\n\t *\n\t * Only works on Cloudflare with Worker Loader enabled.\n\t * Uses the same format as `plugins` - the difference is where they run.\n\t *\n\t * @example\n\t * ```ts\n\t * import { untrustedPlugin } from \"some-third-party-plugin\";\n\t *\n\t * emdash({\n\t * plugins: [trustedPlugin()], // runs in host\n\t * sandboxed: [untrustedPlugin()], // runs in isolate\n\t * sandboxRunner: \"@emdash-cms/sandbox-cloudflare\",\n\t * })\n\t * ```\n\t */\n\tsandboxed?: SandboxedPluginDescriptor[];\n\t/**\n\t * Module that exports the sandbox runner factory.\n\t * Required if using sandboxed plugins.\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * sandboxRunner: \"@emdash-cms/sandbox-cloudflare\",\n\t * })\n\t * ```\n\t */\n\tsandboxRunner?: string;\n\n\t/**\n\t * Authentication configuration\n\t *\n\t * Use an auth adapter function from a platform package:\n\t * - `access({ teamDomain: \"...\" })` from `@emdash-cms/cloudflare`\n\t *\n\t * When an external auth provider is configured, passkey auth is disabled.\n\t *\n\t * @example\n\t * ```ts\n\t * import { access } from \"@emdash-cms/cloudflare\";\n\t *\n\t * emdash({\n\t * auth: access({\n\t * teamDomain: \"myteam.cloudflareaccess.com\",\n\t * audience: \"abc123...\",\n\t * roleMapping: {\n\t * \"Admins\": 50,\n\t * \"Editors\": 30,\n\t * },\n\t * }),\n\t * })\n\t * ```\n\t */\n\tauth?: AuthDescriptor;\n\n\t/**\n\t * MCP (Model Context Protocol) server endpoint.\n\t *\n\t * Exposes an MCP Streamable HTTP server at `/_emdash/api/mcp`\n\t * that allows AI agents and tools to interact with the CMS using\n\t * the standardized MCP protocol.\n\t *\n\t * Enabled by default. The endpoint requires bearer token auth, so\n\t * it has no effect unless the user creates an API token and\n\t * configures a client. Set to `false` to disable.\n\t *\n\t * @default true\n\t */\n\tmcp?: boolean;\n\n\t/**\n\t * Plugin marketplace URL\n\t *\n\t * When set, enables the marketplace features: browse, install, update,\n\t * and uninstall plugins from a remote marketplace.\n\t *\n\t * Must be an HTTPS URL in production, or localhost/127.0.0.1 in dev.\n\t * Requires `sandboxRunner` to be configured (marketplace plugins run sandboxed).\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * marketplace: \"https://marketplace.emdashcms.com\",\n\t * sandboxRunner: \"@emdash-cms/sandbox-cloudflare\",\n\t * })\n\t * ```\n\t */\n\tmarketplace?: string;\n\n\t/**\n\t * Maximum allowed media file upload size in bytes.\n\t *\n\t * Applies to both direct multipart uploads and signed-URL uploads.\n\t * When unset, defaults to 52_428_800 (50 MB).\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({ maxUploadSize: 100 * 1024 * 1024 }) // 100 MB\n\t * ```\n\t */\n\tmaxUploadSize?: number;\n\n\t/**\n\t * Public browser-facing origin for the site.\n\t *\n\t * Use when `Astro.url` / `request.url` do not match what users open — common with a\n\t * **TLS-terminating reverse proxy**: the app often sees `http://` on the internal hop\n\t * while the browser uses `https://`, which breaks WebAuthn, CSRF, OAuth, and redirect URLs.\n\t *\n\t * Set to the full origin users type in the address bar (no path), e.g.\n\t * `https://mysite.example.com`. When not set, falls back to environment variables\n\t * `EMDASH_SITE_URL` > `SITE_URL`, then to the request URL's origin.\n\t *\n\t * Replaces `passkeyPublicOrigin` (which only fixed passkeys).\n\t */\n\tsiteUrl?: string;\n\n\t/**\n\t * Headers to trust for client IP resolution when running behind a reverse\n\t * proxy. The first header in this list that is present on the request\n\t * wins. Applies to rate limiting for auth endpoints and comment\n\t * submission.\n\t *\n\t * Common values:\n\t * - `x-real-ip` — nginx, Caddy, Traefik\n\t * - `fly-client-ip` — Fly.io\n\t * - `x-forwarded-for` — generic (first entry is used)\n\t *\n\t * Only set this when you **control the reverse proxy**. Untrusted\n\t * clients can set any header they like; trusting headers from an open\n\t * network is an IP-spoofing vulnerability that defeats rate limiting.\n\t *\n\t * On Cloudflare the `cf` object on the request is used automatically —\n\t * you normally don't need to set this. Leave unset (or empty) to\n\t * preserve the default: IP is resolved only when the request came\n\t * through Cloudflare's edge.\n\t *\n\t * Falls back to `EMDASH_TRUSTED_PROXY_HEADERS` env var (comma-separated)\n\t * when this option is not set, so operators can configure at deploy\n\t * time without touching the Astro config.\n\t */\n\ttrustedProxyHeaders?: string[];\n\n\t/**\n\t * Enable playground mode for ephemeral \"try EmDash\" sites.\n\t *\n\t * When set, the integration injects a playground middleware (order: \"pre\")\n\t * that runs BEFORE the normal EmDash middleware chain. It creates an\n\t * isolated Durable Object database per session, runs migrations, applies\n\t * the seed, creates an anonymous admin user, and sets the DB in ALS.\n\t * By the time the runtime middleware runs, the database is fully ready.\n\t *\n\t * Setup and auth middleware are skipped (the playground handles both).\n\t *\n\t * Requires `@emdash-cms/cloudflare` as a dependency and a DO binding\n\t * in wrangler.jsonc.\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * database: playgroundDatabase({ binding: \"PLAYGROUND_DB\" }),\n\t * playground: {\n\t * middlewareEntrypoint: \"@emdash-cms/cloudflare/db/playground-middleware\",\n\t * },\n\t * })\n\t * ```\n\t */\n\tplayground?: {\n\t\t/** Module path for the playground middleware. */\n\t\tmiddlewareEntrypoint: string;\n\t};\n\n\t/**\n\t * Media providers for browsing and uploading media\n\t *\n\t * The local media provider (using storage adapter) is available by default.\n\t * Additional providers can be added for external services like Unsplash,\n\t * Cloudinary, Mux, Cloudflare Images, etc.\n\t *\n\t * @example\n\t * ```ts\n\t * import { cloudflareImages, cloudflareStream } from \"@emdash-cms/cloudflare\";\n\t * import { unsplash } from \"@emdash-cms/provider-unsplash\";\n\t *\n\t * emdash({\n\t * mediaProviders: [\n\t * cloudflareImages({ accountId: \"...\" }),\n\t * cloudflareStream({ accountId: \"...\" }),\n\t * unsplash({ accessKey: \"...\" }),\n\t * ],\n\t * })\n\t * ```\n\t */\n\tmediaProviders?: MediaProviderDescriptor[];\n\n\t/**\n\t * Admin UI font configuration.\n\t *\n\t * By default, EmDash loads Noto Sans via the Astro Font API, covering\n\t * Latin, Latin Extended, Cyrillic, Cyrillic Extended, Greek, Greek\n\t * Extended, Devanagari, and Vietnamese. Fonts are downloaded from\n\t * Google at build time and self-hosted, so there are no runtime CDN\n\t * requests.\n\t *\n\t * To add support for additional writing systems (Arabic, CJK, etc.),\n\t * pass script names. EmDash resolves the matching Noto Sans variant\n\t * from Google Fonts and merges all script faces under a single\n\t * font-family, so the browser downloads only the glyphs it needs\n\t * via unicode-range.\n\t *\n\t * Set to `false` to disable font injection entirely and use system fonts.\n\t *\n\t * @example\n\t * ```ts\n\t * // Add Arabic and Japanese support\n\t * emdash({\n\t * fonts: {\n\t * scripts: [\"arabic\", \"japanese\"],\n\t * },\n\t * })\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * // Disable web fonts entirely (use system fonts)\n\t * emdash({\n\t * fonts: false,\n\t * })\n\t * ```\n\t */\n\tfonts?:\n\t\t| false\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * Additional Noto Sans script families to include.\n\t\t\t\t *\n\t\t\t\t * Available scripts: arabic, armenian, bengali, chinese-simplified,\n\t\t\t\t * chinese-traditional, chinese-hongkong, devanagari, ethiopic, farsi,\n\t\t\t\t * georgian, gujarati, gurmukhi, hebrew, japanese, kannada, khmer,\n\t\t\t\t * korean, lao, malayalam, myanmar, oriya, sinhala, tamil, telugu,\n\t\t\t\t * thai, tibetan.\n\t\t\t\t */\n\t\t\t\tscripts?: string[];\n\t\t };\n\n\t/**\n\t * Admin UI branding (white-labeling).\n\t *\n\t * Overrides the default EmDash logo and name in the admin panel.\n\t * Use this to white-label the CMS for agency or enterprise deployments.\n\t * These settings are separate from the public site settings (title, logo,\n\t * favicon) which remain available for SEO and front-end use.\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * admin: {\n\t * logo: \"/images/agency-logo.webp\",\n\t * siteName: \"AgencyX CMS\",\n\t * favicon: \"/favicon.ico\",\n\t * },\n\t * })\n\t * ```\n\t */\n\tadmin?: {\n\t\t/** URL or path to a custom logo image for the admin UI (login page, sidebar). */\n\t\tlogo?: string;\n\t\t/** Custom name displayed in the admin sidebar and browser tab. */\n\t\tsiteName?: string;\n\t\t/** URL or path to a custom favicon for the admin panel. */\n\t\tfavicon?: string;\n\t};\n}\n\n/**\n * Get stored config from global\n * This is set by the virtual module at build time\n */\nexport function getStoredConfig(): EmDashConfig | null {\n\treturn globalThis.__emdashConfig || null;\n}\n\n/**\n * Set stored config in global\n * Called by the integration at config time\n */\nexport function setStoredConfig(config: EmDashConfig): void {\n\tglobalThis.__emdashConfig = config;\n}\n\n// Declare global type\ndeclare global {\n\t// eslint-disable-next-line no-var\n\tvar __emdashConfig: EmDashConfig | undefined;\n}\n","/**\n * EmDash Astro Integration\n *\n * This integration:\n * - Injects the admin shell route at /_emdash/admin/[...path].astro\n * - Sets up REST API endpoints under /_emdash/api/*\n * - Configures middleware to provide database and manifest\n *\n * NOTE: This file is for build-time only. Runtime utilities are in runtime.ts\n * to avoid bundling Node.js-only code into the production build.\n */\n\nimport type { AstroIntegration, AstroIntegrationLogger } from \"astro\";\n\nimport type { ResolvedPlugin } from \"../../plugins/types.js\";\nimport { local } from \"../storage/adapters.js\";\nimport { notoSans } from \"./font-provider.js\";\nimport { injectCoreRoutes, injectBuiltinAuthRoutes, injectMcpRoute } from \"./routes.js\";\nimport type { EmDashConfig, PluginDescriptor } from \"./runtime.js\";\nimport { createViteConfig } from \"./vite-config.js\";\n\n// Re-export runtime types and functions\nexport type {\n\tEmDashConfig,\n\tPluginDescriptor,\n\tSandboxedPluginDescriptor,\n\tResolvedPlugin,\n} from \"./runtime.js\";\nexport { getStoredConfig } from \"./runtime.js\";\n\n/** Default storage: Local filesystem in .emdash directory */\nconst DEFAULT_STORAGE = local({\n\tdirectory: \"./.emdash/uploads\",\n\tbaseUrl: \"/_emdash/api/media/file\",\n});\n\n// Terminal formatting\nconst dim = (s: string) => `\\x1b[2m${s}\\x1b[22m`;\nconst bold = (s: string) => `\\x1b[1m${s}\\x1b[22m`;\nconst cyan = (s: string) => `\\x1b[36m${s}\\x1b[39m`;\n\n/** Print the EmDash startup banner */\nfunction printBanner(_logger: AstroIntegrationLogger): void {\n\tconst banner = `\n\n ${bold(cyan(\"— E M D A S H —\"))}\n `;\n\tconsole.log(banner);\n}\n\n/** Print route injection summary */\nfunction printRoutesSummary(_logger: AstroIntegrationLogger): void {\n\tconsole.log(`\\n ${dim(\"›\")} Admin UI ${cyan(\"/_emdash/admin\")}`);\n\tconsole.log(` ${dim(\"›\")} API ${cyan(\"/_emdash/api/*\")}`);\n\tconsole.log(\"\");\n}\n\n/**\n * Create the EmDash Astro integration\n */\nexport function emdash(config: EmDashConfig = {}): AstroIntegration {\n\t// Apply defaults\n\tconst resolvedConfig: EmDashConfig = {\n\t\t...config,\n\t\tstorage: config.storage ?? DEFAULT_STORAGE,\n\t};\n\n\t// Validate marketplace URL\n\tif (resolvedConfig.marketplace) {\n\t\tconst url = resolvedConfig.marketplace;\n\t\ttry {\n\t\t\tconst parsed = new URL(url);\n\t\t\tconst isLocalhost = parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\";\n\t\t\tif (parsed.protocol !== \"https:\" && !isLocalhost) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Marketplace URL must use HTTPS (got ${parsed.protocol}). ` +\n\t\t\t\t\t\t`Only localhost URLs are allowed over HTTP.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e instanceof TypeError) {\n\t\t\t\tthrow new Error(`Invalid marketplace URL: \"${url}\"`, { cause: e });\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t\tif (!resolvedConfig.sandboxRunner) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Marketplace requires `sandboxRunner` to be configured. \" +\n\t\t\t\t\t\"Marketplace plugins run in sandboxed V8 isolates.\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// Validate siteUrl if provided in astro.config.mjs.\n\t// Env-var fallback (EMDASH_SITE_URL / SITE_URL) is handled at runtime by\n\t// getPublicOrigin() in api/public-url.ts — NOT here — so Docker images built\n\t// without a domain can pick it up at container start via process.env.\n\tif (resolvedConfig.siteUrl) {\n\t\tconst raw = resolvedConfig.siteUrl;\n\t\ttry {\n\t\t\tconst parsed = new URL(raw);\n\t\t\tif (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n\t\t\t\tthrow new Error(`siteUrl must be http or https (got ${parsed.protocol})`);\n\t\t\t}\n\t\t\t// Always store origin-normalized value (no path) — security invariant L-1\n\t\t\tresolvedConfig.siteUrl = parsed.origin;\n\t\t} catch (e) {\n\t\t\tif (e instanceof TypeError) {\n\t\t\t\tthrow new Error(`Invalid siteUrl: \"${raw}\"`, { cause: e });\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\t// Plugin descriptors from config\n\tconst pluginDescriptors = resolvedConfig.plugins ?? [];\n\tconst sandboxedDescriptors = resolvedConfig.sandboxed ?? [];\n\n\t// Validate all plugin descriptors\n\tfor (const descriptor of [...pluginDescriptors, ...sandboxedDescriptors]) {\n\t\t// Standard-format plugins can't use features that require trusted mode\n\t\tif (descriptor.format === \"standard\") {\n\t\t\tif (descriptor.adminEntry) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Plugin \"${descriptor.id}\" is standard format but declares adminEntry. ` +\n\t\t\t\t\t\t`Standard plugins use Block Kit for admin UI, not React components. ` +\n\t\t\t\t\t\t`Remove adminEntry or change format to \"native\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (descriptor.componentsEntry) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Plugin \"${descriptor.id}\" is standard format but declares componentsEntry. ` +\n\t\t\t\t\t\t`Portable Text block components require native format. ` +\n\t\t\t\t\t\t`Remove componentsEntry or change format to \"native\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate: non-standard plugins cannot be placed in sandboxed: []\n\tfor (const descriptor of sandboxedDescriptors) {\n\t\tif (descriptor.format !== \"standard\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Plugin \"${descriptor.id}\" uses the native format and cannot be placed in ` +\n\t\t\t\t\t`\\`sandboxed: []\\`. Native plugins can only run in \\`plugins: []\\`. ` +\n\t\t\t\t\t`To sandbox this plugin, convert it to the standard format.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Resolved plugins (populated at build time by importing entrypoints)\n\tlet _resolvedPlugins: ResolvedPlugin[] = [];\n\n\t// Serialize config for virtual module (database/storage/auth - plugins handled separately)\n\t// i18n is populated in astro:config:setup from astroConfig.i18n\n\tconst serializableConfig: Record<string, unknown> = {\n\t\tdatabase: resolvedConfig.database,\n\t\tstorage: resolvedConfig.storage,\n\t\tauth: resolvedConfig.auth,\n\t\tmarketplace: resolvedConfig.marketplace,\n\t\tsiteUrl: resolvedConfig.siteUrl,\n\t\ttrustedProxyHeaders: resolvedConfig.trustedProxyHeaders,\n\t\tmaxUploadSize: resolvedConfig.maxUploadSize,\n\t\tadmin: resolvedConfig.admin,\n\t};\n\n\t// Determine auth mode for route injection\n\t// Check if auth is an AuthDescriptor (has entrypoint) indicating external auth\n\tconst useExternalAuth = !!(resolvedConfig.auth && \"entrypoint\" in resolvedConfig.auth);\n\n\treturn {\n\t\tname: \"emdash\",\n\t\thooks: {\n\t\t\t\"astro:config:setup\": ({\n\t\t\t\tinjectRoute,\n\t\t\t\taddMiddleware,\n\t\t\t\tlogger,\n\t\t\t\tupdateConfig,\n\t\t\t\tconfig: astroConfig,\n\t\t\t\tcommand,\n\t\t\t}) => {\n\t\t\t\tprintBanner(logger);\n\t\t\t\t// Extract i18n config from Astro config\n\t\t\t\t// Astro locales can be strings OR { path, codes } objects — normalize to paths\n\t\t\t\tif (astroConfig.i18n) {\n\t\t\t\t\tconst routing = astroConfig.i18n.routing;\n\t\t\t\t\tserializableConfig.i18n = {\n\t\t\t\t\t\tdefaultLocale: astroConfig.i18n.defaultLocale,\n\t\t\t\t\t\tlocales: astroConfig.i18n.locales.map((l) => (typeof l === \"string\" ? l : l.path)),\n\t\t\t\t\t\tfallback: astroConfig.i18n.fallback,\n\t\t\t\t\t\tprefixDefaultLocale:\n\t\t\t\t\t\t\ttypeof routing === \"object\" ? (routing.prefixDefaultLocale ?? false) : false,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Disable Astro's built-in checkOrigin -- EmDash's own CSRF\n\t\t\t\t// layer (checkPublicCsrf in api/csrf.ts) handles origin\n\t\t\t\t// validation with dual-origin support: it accepts both the\n\t\t\t\t// internal origin AND the public origin from getPublicOrigin(),\n\t\t\t\t// which resolves siteUrl from config or env vars at runtime.\n\t\t\t\t// Astro's check can't do this because allowedDomains is baked\n\t\t\t\t// at build time, which breaks Docker deployments where the\n\t\t\t\t// domain is only known at container start via EMDASH_SITE_URL.\n\t\t\t\t//\n\t\t\t\t// When siteUrl is known at build time, also set allowedDomains\n\t\t\t\t// so Astro.url reflects the public origin (helps user template\n\t\t\t\t// code that reads Astro.url directly).\n\t\t\t\tconst securityConfig: Record<string, unknown> = {\n\t\t\t\t\tcheckOrigin: false,\n\t\t\t\t\t...(resolvedConfig.siteUrl\n\t\t\t\t\t\t? { allowedDomains: [{ hostname: new URL(resolvedConfig.siteUrl).hostname }] }\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\n\t\t\t\t// Inject default Noto Sans font for the admin UI.\n\t\t\t\t// Uses the Astro Font API so fonts are downloaded at build time\n\t\t\t\t// and self-hosted (no runtime CDN requests).\n\t\t\t\t//\n\t\t\t\t// The admin CSS references var(--font-emdash) with a system font\n\t\t\t\t// fallback. Users can add extra script coverage (Arabic, CJK, etc.)\n\t\t\t\t// by passing fonts.scripts in the emdash() config. The custom\n\t\t\t\t// notoSans provider resolves all script families from Google Fonts\n\t\t\t\t// under a single font-family name, so they stack via unicode-range.\n\t\t\t\tconst fontsConfig = resolvedConfig.fonts;\n\t\t\t\tconst emdashFonts =\n\t\t\t\t\tfontsConfig === false\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tprovider: notoSans({\n\t\t\t\t\t\t\t\t\t\tscripts: fontsConfig?.scripts,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\tname: \"Noto Sans\",\n\t\t\t\t\t\t\t\t\tcssVariable: \"--font-emdash\",\n\t\t\t\t\t\t\t\t\tweights: [\"100 900\" as const],\n\t\t\t\t\t\t\t\t\tstyles: [\"normal\" as const, \"italic\" as const],\n\t\t\t\t\t\t\t\t\tsubsets: [\n\t\t\t\t\t\t\t\t\t\t\"latin\" as const,\n\t\t\t\t\t\t\t\t\t\t\"latin-ext\" as const,\n\t\t\t\t\t\t\t\t\t\t\"cyrillic\" as const,\n\t\t\t\t\t\t\t\t\t\t\"cyrillic-ext\" as const,\n\t\t\t\t\t\t\t\t\t\t\"devanagari\" as const,\n\t\t\t\t\t\t\t\t\t\t\"greek\" as const,\n\t\t\t\t\t\t\t\t\t\t\"greek-ext\" as const,\n\t\t\t\t\t\t\t\t\t\t\"vietnamese\" as const,\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\tfallbacks: [\"ui-sans-serif\", \"system-ui\", \"sans-serif\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t];\n\n\t\t\t\tupdateConfig({\n\t\t\t\t\tsecurity: securityConfig,\n\t\t\t\t\t// fonts is a valid AstroConfig key but may not be in the\n\t\t\t\t\t// type definition for the minimum supported Astro version\n\t\t\t\t\t...({ fonts: emdashFonts } as Record<string, unknown>),\n\t\t\t\t\tvite: createViteConfig(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tserializableConfig,\n\t\t\t\t\t\t\tresolvedConfig,\n\t\t\t\t\t\t\tpluginDescriptors,\n\t\t\t\t\t\t\tastroConfig,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcommand,\n\t\t\t\t\t),\n\t\t\t\t});\n\n\t\t\t\t// Inject all core routes\n\t\t\t\tinjectCoreRoutes(injectRoute);\n\n\t\t\t\t// Only inject passkey/oauth/magic-link routes when NOT using external auth\n\t\t\t\tif (!useExternalAuth) {\n\t\t\t\t\tinjectBuiltinAuthRoutes(injectRoute);\n\t\t\t\t}\n\n\t\t\t\t// Inject MCP endpoint (always on — bearer-token-only, no cost if unused)\n\t\t\t\tif (resolvedConfig.mcp !== false) {\n\t\t\t\t\tinjectMcpRoute(injectRoute);\n\t\t\t\t}\n\n\t\t\t\t// In playground mode, inject the playground middleware FIRST.\n\t\t\t\t// It sets up a per-session DO database in ALS before anything\n\t\t\t\t// else runs, so the runtime init middleware sees a real DB.\n\t\t\t\tif (resolvedConfig.playground) {\n\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\tentrypoint: resolvedConfig.playground.middlewareEntrypoint,\n\t\t\t\t\t\torder: \"pre\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Add middleware to provide database and manifest\n\t\t\t\taddMiddleware({\n\t\t\t\t\tentrypoint: \"emdash/middleware\",\n\t\t\t\t\torder: \"pre\",\n\t\t\t\t});\n\n\t\t\t\t// Add redirect middleware (runs after runtime init, before setup/auth)\n\t\t\t\taddMiddleware({\n\t\t\t\t\tentrypoint: \"emdash/middleware/redirect\",\n\t\t\t\t\torder: \"pre\",\n\t\t\t\t});\n\n\t\t\t\t// Skip setup and auth in playground mode -- the playground middleware\n\t\t\t\t// handles session creation and injects an anonymous admin user.\n\t\t\t\tif (!resolvedConfig.playground) {\n\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\tentrypoint: \"emdash/middleware/setup\",\n\t\t\t\t\t\torder: \"pre\",\n\t\t\t\t\t});\n\n\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\tentrypoint: \"emdash/middleware/auth\",\n\t\t\t\t\t\torder: \"pre\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Add request context middleware (runs after auth, on ALL routes)\n\t\t\t\t// Sets up ALS-based context for query functions (edit mode, preview)\n\t\t\t\taddMiddleware({\n\t\t\t\t\tentrypoint: \"emdash/middleware/request-context\",\n\t\t\t\t\torder: \"pre\",\n\t\t\t\t});\n\n\t\t\t\tprintRoutesSummary(logger);\n\t\t\t},\n\t\t\t\"astro:server:setup\": ({ server, logger }) => {\n\t\t\t\t// Generate types once the server is listening.\n\t\t\t\t// The endpoint returns the types content; we write the file here\n\t\t\t\t// (in Node) because workerd has no real filesystem access.\n\t\t\t\tserver.httpServer?.once(\"listening\", async () => {\n\t\t\t\t\tconst { writeFile, readFile } = await import(\"node:fs/promises\");\n\t\t\t\t\tconst { resolve } = await import(\"node:path\");\n\n\t\t\t\t\tconst address = server.httpServer?.address();\n\t\t\t\t\tif (!address || typeof address === \"string\") return;\n\n\t\t\t\t\tconst port = address.port;\n\t\t\t\t\tconst typegenUrl = `http://localhost:${port}/_emdash/api/typegen`;\n\t\t\t\t\tconst outputPath = resolve(process.cwd(), \"emdash-env.d.ts\");\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst response = await fetch(typegenUrl, {\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\t\tconst body = await response.text().catch(() => \"\");\n\t\t\t\t\t\t\tlogger.warn(`Typegen failed: ${response.status} ${body.slice(0, 200)}`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst { data: result } = (await response.json()) as {\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\ttypes: string;\n\t\t\t\t\t\t\t\thash: string;\n\t\t\t\t\t\t\t\tcollections: number;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Only write if content changed\n\t\t\t\t\t\tlet needsWrite = true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst existing = await readFile(outputPath, \"utf-8\");\n\t\t\t\t\t\t\tif (existing === result.types) needsWrite = false;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// File doesn't exist yet\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (needsWrite) {\n\t\t\t\t\t\t\tawait writeFile(outputPath, result.types, \"utf-8\");\n\t\t\t\t\t\t\tlogger.info(`Generated emdash-env.d.ts (${result.collections} collections)`);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst msg = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\tlogger.warn(`Typegen failed: ${msg}`);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\t\"astro:build:done\": ({ logger }) => {\n\t\t\t\tlogger.info(\"Build complete\");\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport default emdash;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/astro/storage/adapters.ts","../../src/astro/integration/font-provider.ts","../../src/astro/integration/routes.ts","../../src/astro/integration/virtual-modules.ts","../../src/astro/integration/vite-config.ts","../../src/astro/integration/runtime.ts","../../src/astro/integration/index.ts"],"sourcesContent":["/**\n * Storage Adapter Functions\n *\n * These run at config time (astro.config.mjs) and return serializable descriptors.\n * The actual storage is created at runtime by loading the entrypoint.\n *\n * @example\n * ```ts\n * // astro.config.mjs\n * import emdash, { s3, local } from \"emdash/astro\";\n *\n * export default defineConfig({\n * integrations: [\n * emdash({\n * storage: s3({\n * endpoint: \"https://xxx.r2.cloudflarestorage.com\",\n * bucket: \"media\",\n * accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n * }),\n * // or: storage: local({ directory: \"./uploads\", baseUrl: \"/_emdash/api/media/file\" }),\n * }),\n * ],\n * });\n * ```\n *\n * For Cloudflare R2 bindings, use `r2()` from `@emdash-cms/cloudflare`.\n */\n\nimport type { StorageDescriptor, S3StorageConfig, LocalStorageConfig } from \"./types.js\";\n\n/**\n * S3-compatible storage adapter\n *\n * Works with AWS S3, Cloudflare R2 (via S3 API), MinIO, etc.\n *\n * Any field omitted here is resolved from the matching `S3_*` environment\n * variable when the container starts (`S3_ENDPOINT`, `S3_BUCKET`,\n * `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_REGION`, `S3_PUBLIC_URL`).\n * Explicit values always take precedence over env vars.\n *\n * Note: env var resolution reads `process.env` on Node at runtime.\n * Workers users should continue passing explicit values to `s3({...})`.\n *\n * @example\n * ```ts\n * // All fields from env (container deployments)\n * storage: s3()\n *\n * // Mix: CDN from config, credentials from env\n * storage: s3({ publicUrl: \"https://cdn.example.com\" })\n *\n * // All explicit (unchanged from before)\n * storage: s3({\n * endpoint: \"https://xxx.r2.cloudflarestorage.com\",\n * bucket: \"media\",\n * accessKeyId: process.env.R2_ACCESS_KEY_ID,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,\n * })\n * ```\n */\nexport function s3(config: Partial<S3StorageConfig> = {}): StorageDescriptor {\n\treturn {\n\t\tentrypoint: \"emdash/storage/s3\",\n\t\tconfig,\n\t};\n}\n\n/**\n * Local filesystem storage adapter\n *\n * For development and testing. Stores files in a local directory.\n * Does NOT support signed upload URLs.\n *\n * @example\n * ```ts\n * storage: local({\n * directory: \"./uploads\",\n * baseUrl: \"/_emdash/api/media/file\",\n * })\n * ```\n */\nexport function local(config: LocalStorageConfig): StorageDescriptor {\n\treturn {\n\t\tentrypoint: \"emdash/storage/local\",\n\t\tconfig,\n\t};\n}\n","/**\n * EmDash Noto Sans font provider\n *\n * A custom Astro font provider that wraps Google Fonts to resolve\n * multiple Noto Sans families (Latin, Arabic, JP, etc.) under a\n * single logical font entry. This lets all @font-face blocks share\n * the same font-family name, so the browser picks the right file\n * per character via unicode-range.\n *\n * Without this, registering \"Noto Sans\" and \"Noto Sans Arabic\" as\n * separate font entries on the same cssVariable triggers an Astro\n * warning and the last entry overwrites the first.\n */\n\nimport { fontProviders } from \"astro/config\";\n\n/**\n * All subset names used by Google Fonts CSS responses.\n * Passed when resolving extra script families so the unifont\n * provider doesn't filter out any faces.\n */\nconst ALL_GOOGLE_SUBSETS = [\n\t\"arabic\",\n\t\"armenian\",\n\t\"bengali\",\n\t\"chinese-simplified\",\n\t\"chinese-traditional\",\n\t\"chinese-hongkong\",\n\t\"cyrillic\",\n\t\"cyrillic-ext\",\n\t\"devanagari\",\n\t\"ethiopic\",\n\t\"farsi\",\n\t\"georgian\",\n\t\"greek\",\n\t\"greek-ext\",\n\t\"gujarati\",\n\t\"gurmukhi\",\n\t\"hebrew\",\n\t\"japanese\",\n\t\"kannada\",\n\t\"khmer\",\n\t\"korean\",\n\t\"lao\",\n\t\"latin\",\n\t\"latin-ext\",\n\t\"malayalam\",\n\t\"math\",\n\t\"myanmar\",\n\t\"oriya\",\n\t\"sinhala\",\n\t\"symbols\",\n\t\"tamil\",\n\t\"telugu\",\n\t\"thai\",\n\t\"tibetan\",\n\t\"vietnamese\",\n];\n\n/**\n * Known Noto Sans and Sans script families on Google Fonts.\n * Maps user-friendly script names to Google Fonts family names.\n */\nconst NOTO_SCRIPT_FAMILIES: Record<string, string> = {\n\tarabic: \"Noto Sans Arabic\",\n\tarmenian: \"Noto Sans Armenian\",\n\tbengali: \"Noto Sans Bengali\",\n\t\"chinese-simplified\": \"Noto Sans SC\",\n\t\"chinese-traditional\": \"Noto Sans TC\",\n\t\"chinese-hongkong\": \"Noto Sans HK\",\n\tdevanagari: \"Noto Sans Devanagari\",\n\tethiopic: \"Noto Sans Ethiopic\",\n\tfarsi: \"Vazirmatn\",\n\tgeorgian: \"Noto Sans Georgian\",\n\tgujarati: \"Noto Sans Gujarati\",\n\tgurmukhi: \"Noto Sans Gurmukhi\",\n\thebrew: \"Noto Sans Hebrew\",\n\tjapanese: \"Noto Sans JP\",\n\tkannada: \"Noto Sans Kannada\",\n\tkhmer: \"Noto Sans Khmer\",\n\tkorean: \"Noto Sans KR\",\n\tlao: \"Noto Sans Lao\",\n\tmalayalam: \"Noto Sans Malayalam\",\n\tmyanmar: \"Noto Sans Myanmar\",\n\toriya: \"Noto Sans Oriya\",\n\tsinhala: \"Noto Sans Sinhala\",\n\ttamil: \"Noto Sans Tamil\",\n\ttelugu: \"Noto Sans Telugu\",\n\tthai: \"Noto Sans Thai\",\n\ttibetan: \"Noto Sans Tibetan\",\n};\n\nexport interface NotoSansProviderOptions {\n\t/**\n\t * Additional Noto Sans script families to include.\n\t * Use script names like \"arabic\", \"japanese\", \"chinese-simplified\".\n\t *\n\t * @see {@link NOTO_SCRIPT_FAMILIES} for the full list of supported scripts.\n\t */\n\tscripts?: string[];\n}\n\n// Use ReturnType to get the provider type without importing it directly.\n// The Astro FontProvider type is not part of the public API surface.\ntype GoogleProvider = ReturnType<typeof fontProviders.google>;\n\n/**\n * Create a font provider that resolves Noto Sans plus additional\n * script-specific Noto families from Google Fonts, all under one\n * font-family name.\n */\nexport function notoSans(options?: NotoSansProviderOptions): GoogleProvider {\n\t// Create a single Google provider instance to share initialization\n\tconst googleProvider = fontProviders.google();\n\n\treturn {\n\t\tname: \"emdash-noto\",\n\t\tasync init(context) {\n\t\t\tawait googleProvider.init?.(context);\n\t\t},\n\t\tasync resolveFont(resolveFontOptions) {\n\t\t\t// Resolve the base Noto Sans (Latin, Cyrillic, Greek, etc.)\n\t\t\tconst base = await googleProvider.resolveFont(resolveFontOptions);\n\t\t\tconst baseFonts = base?.fonts ?? [];\n\n\t\t\tif (!options?.scripts?.length) {\n\t\t\t\treturn base;\n\t\t\t}\n\n\t\t\t// Collect subset names already covered by the base font so we\n\t\t\t// can filter out duplicate faces from extra script families.\n\t\t\t// e.g. Noto Sans Arabic includes latin/latin-ext faces that\n\t\t\t// would otherwise override the base Noto Sans latin faces.\n\t\t\tconst baseSubsets = new Set(baseFonts.map((f) => f.meta?.subset).filter(Boolean));\n\n\t\t\t// Resolve additional script families\n\t\t\tconst extraFonts = await Promise.all(\n\t\t\t\toptions.scripts.map(async (script) => {\n\t\t\t\t\tconst family = NOTO_SCRIPT_FAMILIES[script];\n\t\t\t\t\tif (!family) {\n\t\t\t\t\t\t// Silently skip subset names that are already covered\n\t\t\t\t\t\t// by the base Noto Sans font (latin, cyrillic, etc.)\n\t\t\t\t\t\tif (ALL_GOOGLE_SUBSETS.includes(script)) {\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[emdash] Unknown Noto Sans script \"${script}\". ` +\n\t\t\t\t\t\t\t\t`Available: ${Object.keys(NOTO_SCRIPT_FAMILIES).join(\", \")}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn googleProvider.resolveFont({\n\t\t\t\t\t\t...resolveFontOptions,\n\t\t\t\t\t\tfamilyName: family,\n\t\t\t\t\t\t// Pass all known subset names so the unifont provider\n\t\t\t\t\t\t// doesn't filter out any faces. Each script family\n\t\t\t\t\t\t// only returns faces for its own subsets anyway.\n\t\t\t\t\t\tsubsets: ALL_GOOGLE_SUBSETS,\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\t// Merge, dropping faces from extra fonts that duplicate base subsets\n\t\t\tconst extraFaces = extraFonts.flatMap((r) =>\n\t\t\t\t(r?.fonts ?? []).filter((f) => !f.meta?.subset || !baseSubsets.has(f.meta.subset)),\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tfonts: [...baseFonts, ...extraFaces],\n\t\t\t};\n\t\t},\n\t};\n}\n\n/** Get the list of available Noto Sans script names */\nexport function getAvailableNotoScripts(): string[] {\n\treturn Object.keys(NOTO_SCRIPT_FAMILIES);\n}\n","/**\n * Route Injection\n *\n * Defines and injects all EmDash routes into the Astro application.\n */\n\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Resolve path to a route file in the package\n * Uses Node.js APIs - only call at build time\n */\nfunction resolveRoute(route: string): string {\n\t// Lazy initialization to avoid running Node.js code at import time\n\t// This prevents issues when the module is bundled for Cloudflare Workers\n\tconst require = createRequire(import.meta.url);\n\tconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n\ttry {\n\t\t// Try to resolve as package export\n\t\treturn require.resolve(`emdash/routes/${route}`);\n\t} catch {\n\t\t// Fallback to relative path (for development)\n\t\treturn resolve(__dirname, \"../routes\", route);\n\t}\n}\n\n/** Route injection function type */\ntype InjectRoute = (route: { pattern: string; entrypoint: string }) => void;\n\n/**\n * Injects all core EmDash routes.\n */\nexport function injectCoreRoutes(injectRoute: InjectRoute): void {\n\t// Inject admin shell route\n\tinjectRoute({\n\t\tpattern: \"/_emdash/admin/[...path]\",\n\t\tentrypoint: resolveRoute(\"admin.astro\"),\n\t});\n\n\t// Inject API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/manifest\",\n\t\tentrypoint: resolveRoute(\"api/manifest.ts\"),\n\t});\n\n\t// Auth mode endpoint (public — used by the login page to pick the right UI)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/mode\",\n\t\tentrypoint: resolveRoute(\"api/auth/mode.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/dashboard\",\n\t\tentrypoint: resolveRoute(\"api/dashboard.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/revisions\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/revisions.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/preview-url\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/preview-url.ts\"),\n\t});\n\n\t// Trash/restore routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/trash\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/trash.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/restore\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/restore.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/permanent\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/permanent.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/duplicate\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/duplicate.ts\"),\n\t});\n\n\t// Publishing routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/publish\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/publish.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/unpublish\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/unpublish.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/discard-draft\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/discard-draft.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/compare\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/compare.ts\"),\n\t});\n\n\t// i18n translation routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/translations\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/translations.ts\"),\n\t});\n\n\t// Scheduled publishing routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/schedule\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/schedule.ts\"),\n\t});\n\n\t// Revision management routes (for restore, etc.)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/revisions/[revisionId]\",\n\t\tentrypoint: resolveRoute(\"api/revisions/[revisionId]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/revisions/[revisionId]/restore\",\n\t\tentrypoint: resolveRoute(\"api/revisions/[revisionId]/restore.ts\"),\n\t});\n\n\t// Media API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media\",\n\t\tentrypoint: resolveRoute(\"api/media.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/upload-url\",\n\t\tentrypoint: resolveRoute(\"api/media/upload-url.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/file/[...key]\",\n\t\tentrypoint: resolveRoute(\"api/media/file/[...key].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/[id]\",\n\t\tentrypoint: resolveRoute(\"api/media/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/[id]/confirm\",\n\t\tentrypoint: resolveRoute(\"api/media/[id]/confirm.ts\"),\n\t});\n\n\t// Media provider routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/providers\",\n\t\tentrypoint: resolveRoute(\"api/media/providers/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/providers/[providerId]\",\n\t\tentrypoint: resolveRoute(\"api/media/providers/[providerId]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/media/providers/[providerId]/[itemId]\",\n\t\tentrypoint: resolveRoute(\"api/media/providers/[providerId]/[itemId].ts\"),\n\t});\n\n\t// Import API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/probe\",\n\t\tentrypoint: resolveRoute(\"api/import/probe.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/analyze\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/analyze.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/prepare\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/prepare.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/execute\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/execute.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/media\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/media.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress/rewrite-urls\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress/rewrite-urls.ts\"),\n\t});\n\n\t// WordPress Plugin (EmDash Exporter) direct import routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress-plugin/analyze\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress-plugin/analyze.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress-plugin/execute\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress-plugin/execute.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/import/wordpress-plugin/callback\",\n\t\tentrypoint: resolveRoute(\"api/import/wordpress-plugin/callback.ts\"),\n\t});\n\n\t// Schema API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema\",\n\t\tentrypoint: resolveRoute(\"api/schema/index.ts\"),\n\t});\n\n\t// Typegen endpoint (dev-only)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/typegen\",\n\t\tentrypoint: resolveRoute(\"api/typegen.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]/fields\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/fields/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]/fields/reorder\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/fields/reorder.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/collections/[slug]/fields/[fieldSlug]\",\n\t\tentrypoint: resolveRoute(\"api/schema/collections/[slug]/fields/[fieldSlug].ts\"),\n\t});\n\n\t// Orphaned tables discovery\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/orphans\",\n\t\tentrypoint: resolveRoute(\"api/schema/orphans/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/schema/orphans/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/schema/orphans/[slug].ts\"),\n\t});\n\n\t// Site settings route\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/settings\",\n\t\tentrypoint: resolveRoute(\"api/settings.ts\"),\n\t});\n\n\t// Email settings route\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/settings/email\",\n\t\tentrypoint: resolveRoute(\"api/settings/email.ts\"),\n\t});\n\n\t// Snapshot route (for DO preview database population)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/snapshot\",\n\t\tentrypoint: resolveRoute(\"api/snapshot.ts\"),\n\t});\n\n\t// Taxonomy API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/taxonomies\",\n\t\tentrypoint: resolveRoute(\"api/taxonomies/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/taxonomies/[name]/terms\",\n\t\tentrypoint: resolveRoute(\"api/taxonomies/[name]/terms/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/taxonomies/[name]/terms/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/taxonomies/[name]/terms/[slug].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/content/[collection]/[id]/terms/[taxonomy]\",\n\t\tentrypoint: resolveRoute(\"api/content/[collection]/[id]/terms/[taxonomy].ts\"),\n\t});\n\n\t// Plugin management routes (under /admin to avoid conflict with plugin API routes)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/enable\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/enable.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/disable\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/disable.ts\"),\n\t});\n\n\t// Marketplace plugin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace/[id]/icon\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/[id]/icon.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/marketplace/[id]/install\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/marketplace/[id]/install.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/update\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/update.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/[id]/uninstall\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/[id]/uninstall.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/plugins/updates\",\n\t\tentrypoint: resolveRoute(\"api/admin/plugins/updates.ts\"),\n\t});\n\n\t// Exclusive hooks admin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/hooks/exclusive\",\n\t\tentrypoint: resolveRoute(\"api/admin/hooks/exclusive/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/hooks/exclusive/[hookName]\",\n\t\tentrypoint: resolveRoute(\"api/admin/hooks/exclusive/[hookName].ts\"),\n\t});\n\n\t// Theme marketplace routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/themes/marketplace\",\n\t\tentrypoint: resolveRoute(\"api/admin/themes/marketplace/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/themes/marketplace/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/themes/marketplace/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/themes/marketplace/[id]/thumbnail\",\n\t\tentrypoint: resolveRoute(\"api/admin/themes/marketplace/[id]/thumbnail.ts\"),\n\t});\n\n\t// Theme preview signing (local, not proxied)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/themes/preview\",\n\t\tentrypoint: resolveRoute(\"api/themes/preview.ts\"),\n\t});\n\n\t// User management routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/index.ts\"),\n\t});\n\n\t// Bylines routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/bylines\",\n\t\tentrypoint: resolveRoute(\"api/admin/bylines/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/bylines/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/bylines/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]/disable\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/disable.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]/enable\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/enable.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/users/[id]/send-recovery\",\n\t\tentrypoint: resolveRoute(\"api/admin/users/[id]/send-recovery.ts\"),\n\t});\n\n\t// API token admin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/api-tokens\",\n\t\tentrypoint: resolveRoute(\"api/admin/api-tokens/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/api-tokens/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/api-tokens/[id].ts\"),\n\t});\n\n\t// OAuth client admin routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/oauth-clients\",\n\t\tentrypoint: resolveRoute(\"api/admin/oauth-clients/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/oauth-clients/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/oauth-clients/[id].ts\"),\n\t});\n\n\t// OAuth Device Flow routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/device/code\",\n\t\tentrypoint: resolveRoute(\"api/oauth/device/code.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/device/token\",\n\t\tentrypoint: resolveRoute(\"api/oauth/device/token.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/device/authorize\",\n\t\tentrypoint: resolveRoute(\"api/oauth/device/authorize.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/token/refresh\",\n\t\tentrypoint: resolveRoute(\"api/oauth/token/refresh.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/token/revoke\",\n\t\tentrypoint: resolveRoute(\"api/oauth/token/revoke.ts\"),\n\t});\n\n\t// Auth discovery endpoint\n\tinjectRoute({\n\t\tpattern: \"/_emdash/.well-known/auth\",\n\t\tentrypoint: resolveRoute(\"api/well-known/auth.ts\"),\n\t});\n\n\t// OAuth 2.1 Authorization Code flow routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/token\",\n\t\tentrypoint: resolveRoute(\"api/oauth/token.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/oauth/authorize\",\n\t\tentrypoint: resolveRoute(\"api/oauth/authorize.ts\"),\n\t});\n\n\t// OAuth discovery endpoints (RFC 9728, RFC 8414)\n\tinjectRoute({\n\t\tpattern: \"/.well-known/oauth-protected-resource\",\n\t\tentrypoint: resolveRoute(\"api/well-known/oauth-protected-resource.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/.well-known/oauth-authorization-server/_emdash\",\n\t\tentrypoint: resolveRoute(\"api/well-known/oauth-authorization-server.ts\"),\n\t});\n\n\t// RFC 7591 Dynamic Client Registration\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/oauth/register\",\n\t\tentrypoint: resolveRoute(\"api/oauth/register.ts\"),\n\t});\n\n\t// Plugin-defined API routes\n\t// All plugin routes are handled by a single catch-all handler\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/plugins/[pluginId]/[...path]\",\n\t\tentrypoint: resolveRoute(\"api/plugins/[pluginId]/[...path].ts\"),\n\t});\n\n\t// Menu API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus\",\n\t\tentrypoint: resolveRoute(\"api/menus/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus/[name]\",\n\t\tentrypoint: resolveRoute(\"api/menus/[name].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus/[name]/items\",\n\t\tentrypoint: resolveRoute(\"api/menus/[name]/items.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/menus/[name]/reorder\",\n\t\tentrypoint: resolveRoute(\"api/menus/[name]/reorder.ts\"),\n\t});\n\n\t// Widget area routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-components\",\n\t\tentrypoint: resolveRoute(\"api/widget-components.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]/widgets\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name]/widgets.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]/widgets/[id]\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name]/widgets/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/widget-areas/[name]/reorder\",\n\t\tentrypoint: resolveRoute(\"api/widget-areas/[name]/reorder.ts\"),\n\t});\n\n\t// Section routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/sections\",\n\t\tentrypoint: resolveRoute(\"api/sections/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/sections/[slug]\",\n\t\tentrypoint: resolveRoute(\"api/sections/[slug].ts\"),\n\t});\n\n\t// Redirect routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects\",\n\t\tentrypoint: resolveRoute(\"api/redirects/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects/404s/summary\",\n\t\tentrypoint: resolveRoute(\"api/redirects/404s/summary.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects/404s\",\n\t\tentrypoint: resolveRoute(\"api/redirects/404s/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/redirects/[id]\",\n\t\tentrypoint: resolveRoute(\"api/redirects/[id].ts\"),\n\t});\n\n\t// Search routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search\",\n\t\tentrypoint: resolveRoute(\"api/search/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/suggest\",\n\t\tentrypoint: resolveRoute(\"api/search/suggest.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/stats\",\n\t\tentrypoint: resolveRoute(\"api/search/stats.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/rebuild\",\n\t\tentrypoint: resolveRoute(\"api/search/rebuild.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/search/enable\",\n\t\tentrypoint: resolveRoute(\"api/search/enable.ts\"),\n\t});\n\n\t// Comment routes (public)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/comments/[collection]/[contentId]\",\n\t\tentrypoint: resolveRoute(\"api/comments/[collection]/[contentId]/index.ts\"),\n\t});\n\n\t// Comment routes (admin)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/counts\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/counts.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/bulk\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/bulk.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/[id]/status\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/[id]/status.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/comments/[id]\",\n\t\tentrypoint: resolveRoute(\"api/admin/comments/[id].ts\"),\n\t});\n\n\t// SEO routes (public, at site root)\n\tinjectRoute({\n\t\tpattern: \"/sitemap.xml\",\n\t\tentrypoint: resolveRoute(\"sitemap.xml.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/sitemap-[collection].xml\",\n\t\tentrypoint: resolveRoute(\"sitemap-[collection].xml.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/robots.txt\",\n\t\tentrypoint: resolveRoute(\"robots.txt.ts\"),\n\t});\n\n\t// Setup wizard API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/status\",\n\t\tentrypoint: resolveRoute(\"api/setup/status.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup\",\n\t\tentrypoint: resolveRoute(\"api/setup/index.ts\"),\n\t});\n\n\t// Auth API routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/admin\",\n\t\tentrypoint: resolveRoute(\"api/setup/admin.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/admin/verify\",\n\t\tentrypoint: resolveRoute(\"api/setup/admin-verify.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/dev-bypass\",\n\t\tentrypoint: resolveRoute(\"api/setup/dev-bypass.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/setup/dev-reset\",\n\t\tentrypoint: resolveRoute(\"api/setup/dev-reset.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/dev/emails\",\n\t\tentrypoint: resolveRoute(\"api/dev/emails.ts\"),\n\t});\n\n\t// Current user endpoint (always available)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/me\",\n\t\tentrypoint: resolveRoute(\"api/auth/me.ts\"),\n\t});\n\n\t// Logout is always available (though behavior differs by auth mode)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/logout\",\n\t\tentrypoint: resolveRoute(\"api/auth/logout.ts\"),\n\t});\n}\n\n/**\n * Injects the MCP (Model Context Protocol) server route.\n * Only injected when `mcp: true` is set in the EmDash config.\n */\nexport function injectMcpRoute(injectRoute: InjectRoute): void {\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/mcp\",\n\t\tentrypoint: resolveRoute(\"api/mcp.ts\"),\n\t});\n}\n\n/**\n * Injects routes from pluggable auth providers.\n *\n * Each provider declares the routes it needs in its `AuthProviderDescriptor.routes` array.\n * Routes are injected at build time so Vite can bundle them.\n */\nexport function injectAuthProviderRoutes(\n\tinjectRoute: InjectRoute,\n\tproviders: Array<{ routes?: Array<{ pattern: string; entrypoint: string }> }>,\n): void {\n\tfor (const provider of providers) {\n\t\tif (provider.routes) {\n\t\t\tfor (const route of provider.routes) {\n\t\t\t\tinjectRoute({\n\t\t\t\t\tpattern: route.pattern,\n\t\t\t\t\tentrypoint: route.entrypoint,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Injects passkey/oauth/magic-link auth routes.\n * Only used when NOT using external auth.\n */\nexport function injectBuiltinAuthRoutes(injectRoute: InjectRoute): void {\n\t// Passkey authentication routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/options\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/options.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/verify.ts\"),\n\t});\n\n\t// Passkey management routes (authenticated users)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/register/options\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/register/options.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/register/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/register/verify.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/passkey/[id]\",\n\t\tentrypoint: resolveRoute(\"api/auth/passkey/[id].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/dev-bypass\",\n\t\tentrypoint: resolveRoute(\"api/auth/dev-bypass.ts\"),\n\t});\n\n\t// Invite routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite/accept\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/accept.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite/complete\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/complete.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/invite/register-options\",\n\t\tentrypoint: resolveRoute(\"api/auth/invite/register-options.ts\"),\n\t});\n\n\t// Magic link routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/magic-link/send\",\n\t\tentrypoint: resolveRoute(\"api/auth/magic-link/send.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/magic-link/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/magic-link/verify.ts\"),\n\t});\n\n\t// OAuth routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/oauth/[provider]\",\n\t\tentrypoint: resolveRoute(\"api/auth/oauth/[provider].ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/oauth/[provider]/callback\",\n\t\tentrypoint: resolveRoute(\"api/auth/oauth/[provider]/callback.ts\"),\n\t});\n\n\t// Self-signup routes\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/signup/request\",\n\t\tentrypoint: resolveRoute(\"api/auth/signup/request.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/signup/verify\",\n\t\tentrypoint: resolveRoute(\"api/auth/signup/verify.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/auth/signup/complete\",\n\t\tentrypoint: resolveRoute(\"api/auth/signup/complete.ts\"),\n\t});\n\n\t// Allowed domains admin routes (only relevant for passkey mode)\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/allowed-domains\",\n\t\tentrypoint: resolveRoute(\"api/admin/allowed-domains/index.ts\"),\n\t});\n\n\tinjectRoute({\n\t\tpattern: \"/_emdash/api/admin/allowed-domains/[domain]\",\n\t\tentrypoint: resolveRoute(\"api/admin/allowed-domains/[domain].ts\"),\n\t});\n}\n","/**\n * Virtual Module Generators\n *\n * Functions that generate virtual module content for Vite.\n * These modules statically import configured dependencies\n * so Vite can properly resolve and bundle them.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\n\nimport type { AuthProviderDescriptor } from \"../../auth/types.js\";\nimport type { MediaProviderDescriptor } from \"../../media/types.js\";\nimport { defaultSeed } from \"../../seed/default.js\";\nimport type { PluginDescriptor } from \"./runtime.js\";\n\nconst TS_SOURCE_EXT_RE = /^\\.(ts|tsx|mts|cts|jsx)$/;\n\n/** Pattern to remove scoped package prefix from plugin ID */\nconst SCOPED_PREFIX_PATTERN = /^@[^/]+\\/plugin-/;\n\n/** Pattern to remove emdash-plugin- prefix from plugin ID */\nconst EMDASH_PREFIX_PATTERN = /^emdash-plugin-/;\n\n// Virtual module IDs\nexport const VIRTUAL_CONFIG_ID = \"virtual:emdash/config\";\nexport const RESOLVED_VIRTUAL_CONFIG_ID = \"\\0\" + VIRTUAL_CONFIG_ID;\n\nexport const VIRTUAL_DIALECT_ID = \"virtual:emdash/dialect\";\nexport const RESOLVED_VIRTUAL_DIALECT_ID = \"\\0\" + VIRTUAL_DIALECT_ID;\n\nexport const VIRTUAL_STORAGE_ID = \"virtual:emdash/storage\";\nexport const RESOLVED_VIRTUAL_STORAGE_ID = \"\\0\" + VIRTUAL_STORAGE_ID;\n\nexport const VIRTUAL_ADMIN_REGISTRY_ID = \"virtual:emdash/admin-registry\";\nexport const RESOLVED_VIRTUAL_ADMIN_REGISTRY_ID = \"\\0\" + VIRTUAL_ADMIN_REGISTRY_ID;\n\nexport const VIRTUAL_PLUGINS_ID = \"virtual:emdash/plugins\";\nexport const RESOLVED_VIRTUAL_PLUGINS_ID = \"\\0\" + VIRTUAL_PLUGINS_ID;\n\nexport const VIRTUAL_SANDBOX_RUNNER_ID = \"virtual:emdash/sandbox-runner\";\nexport const RESOLVED_VIRTUAL_SANDBOX_RUNNER_ID = \"\\0\" + VIRTUAL_SANDBOX_RUNNER_ID;\n\nexport const VIRTUAL_SANDBOXED_PLUGINS_ID = \"virtual:emdash/sandboxed-plugins\";\nexport const RESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID = \"\\0\" + VIRTUAL_SANDBOXED_PLUGINS_ID;\n\nexport const VIRTUAL_AUTH_ID = \"virtual:emdash/auth\";\nexport const RESOLVED_VIRTUAL_AUTH_ID = \"\\0\" + VIRTUAL_AUTH_ID;\n\nexport const VIRTUAL_AUTH_PROVIDERS_ID = \"virtual:emdash/auth-providers\";\nexport const RESOLVED_VIRTUAL_AUTH_PROVIDERS_ID = \"\\0\" + VIRTUAL_AUTH_PROVIDERS_ID;\n\nexport const VIRTUAL_MEDIA_PROVIDERS_ID = \"virtual:emdash/media-providers\";\nexport const RESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID = \"\\0\" + VIRTUAL_MEDIA_PROVIDERS_ID;\n\nexport const VIRTUAL_BLOCK_COMPONENTS_ID = \"virtual:emdash/block-components\";\nexport const RESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID = \"\\0\" + VIRTUAL_BLOCK_COMPONENTS_ID;\n\nexport const VIRTUAL_SEED_ID = \"virtual:emdash/seed\";\nexport const RESOLVED_VIRTUAL_SEED_ID = \"\\0\" + VIRTUAL_SEED_ID;\n\nexport const VIRTUAL_WAIT_UNTIL_ID = \"virtual:emdash/wait-until\";\nexport const RESOLVED_VIRTUAL_WAIT_UNTIL_ID = \"\\0\" + VIRTUAL_WAIT_UNTIL_ID;\n\n/**\n * Generates the config virtual module.\n */\nexport function generateConfigModule(serializableConfig: Record<string, unknown>): string {\n\treturn `export default ${JSON.stringify(serializableConfig)};`;\n}\n\n/**\n * Generates the dialect virtual module.\n *\n * Adapters that set `supportsRequestScope: true` on their descriptor are\n * expected to export `createRequestScopedDb` from their runtime entrypoint;\n * the generator re-exports it so middleware can ask for a per-request Kysely\n * (used for D1 Sessions API, bookmark cookies, read-replica routing). Other\n * adapters get a stub that returns null.\n */\nexport function generateDialectModule(opts: {\n\tentrypoint?: string;\n\ttype?: string;\n\tsupportsRequestScope: boolean;\n}): string {\n\tconst { entrypoint, supportsRequestScope } = opts;\n\tif (!entrypoint) {\n\t\treturn [\n\t\t\t`export const createDialect = undefined;`,\n\t\t\t`export const dialectType = \"sqlite\";`,\n\t\t\t`export const createRequestScopedDb = (_opts) => null;`,\n\t\t].join(\"\\n\");\n\t}\n\tconst type = opts.type ?? \"sqlite\";\n\n\tif (supportsRequestScope) {\n\t\treturn `\nimport { createDialect as _createDialect } from \"${entrypoint}\";\nexport { createRequestScopedDb } from \"${entrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\n`;\n\t}\n\n\treturn `\nimport { createDialect as _createDialect } from \"${entrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\nexport const createRequestScopedDb = (_opts) => null;\n`;\n}\n\n/**\n * Generates the storage virtual module.\n * Statically imports the configured storage adapter.\n */\nexport function generateStorageModule(storageEntrypoint?: string): string {\n\tif (!storageEntrypoint) {\n\t\treturn `export const createStorage = undefined;`;\n\t}\n\treturn `\nimport { createStorage as _createStorage } from \"${storageEntrypoint}\";\nexport const createStorage = _createStorage;\n`;\n}\n\n/**\n * Generates the auth virtual module.\n * Statically imports the configured auth provider.\n */\nexport function generateAuthModule(authEntrypoint?: string): string {\n\tif (!authEntrypoint) {\n\t\treturn `export const authenticate = undefined;`;\n\t}\n\treturn `\nimport { authenticate as _authenticate } from \"${authEntrypoint}\";\nexport const authenticate = _authenticate;\n`;\n}\n\n/**\n * Generates the auth providers module.\n *\n * Statically imports each auth provider's `adminEntry` module and exports\n * a registry keyed by provider ID. The admin UI uses this to render\n * provider-specific login buttons/forms and setup steps.\n *\n * Follows the same pattern as `generateAdminRegistryModule()` for plugins.\n */\nexport function generateAuthProvidersModule(descriptors: AuthProviderDescriptor[]): string {\n\tconst withAdmin = descriptors.filter((d) => d.adminEntry);\n\n\tif (withAdmin.length === 0) {\n\t\treturn `export const authProviders = {};`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst entries: string[] = [];\n\n\twithAdmin.forEach((descriptor, index) => {\n\t\tconst varName = `authProvider${index}`;\n\t\timports.push(`import * as ${varName} from ${JSON.stringify(descriptor.adminEntry)};`);\n\t\tentries.push(\n\t\t\t` ${JSON.stringify(descriptor.id)}: { ...${varName}, id: ${JSON.stringify(descriptor.id)}, label: ${JSON.stringify(descriptor.label)} },`,\n\t\t);\n\t});\n\n\treturn `\n// Auto-generated auth provider registry\n${imports.join(\"\\n\")}\n\nexport const authProviders = {\n${entries.join(\"\\n\")}\n};\n`;\n}\n\n/**\n * Generates the plugins module.\n * Imports and instantiates all plugins at runtime.\n *\n * Handles two plugin formats:\n * - **Native**: imports `createPlugin` and calls it with options\n * - **Standard**: imports the default export and wraps it with `adaptSandboxEntry`\n *\n * The format is determined by `descriptor.format`:\n * - `\"standard\"` -- uses adaptSandboxEntry\n * - `\"native\"` or undefined -- uses createPlugin\n *\n * This is critical for Cloudflare Workers where globals don't persist\n * between build time and runtime.\n */\nexport function generatePluginsModule(descriptors: PluginDescriptor[]): string {\n\tif (descriptors.length === 0) {\n\t\treturn `export const plugins = [];`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst instantiations: string[] = [];\n\n\t// Track whether we need the adapter import\n\tlet needsAdapter = false;\n\n\tdescriptors.forEach((descriptor, index) => {\n\t\tif (descriptor.format === \"standard\") {\n\t\t\t// Standard format: import default export, wrap with adaptSandboxEntry\n\t\t\tneedsAdapter = true;\n\t\t\tconst varName = `pluginDef${index}`;\n\t\t\timports.push(`import ${varName} from \"${descriptor.entrypoint}\";`);\n\t\t\tinstantiations.push(\n\t\t\t\t`adaptSandboxEntry(${varName}, ${JSON.stringify({\n\t\t\t\t\tid: descriptor.id,\n\t\t\t\t\tversion: descriptor.version,\n\t\t\t\t\tcapabilities: descriptor.capabilities,\n\t\t\t\t\tallowedHosts: descriptor.allowedHosts,\n\t\t\t\t\tstorage: descriptor.storage,\n\t\t\t\t\tadminPages: descriptor.adminPages,\n\t\t\t\t\tadminWidgets: descriptor.adminWidgets,\n\t\t\t\t})})`,\n\t\t\t);\n\t\t} else {\n\t\t\t// Native format: import createPlugin and call with options\n\t\t\tconst varName = `createPlugin${index}`;\n\t\t\timports.push(`import { createPlugin as ${varName} } from \"${descriptor.entrypoint}\";`);\n\t\t\tinstantiations.push(`${varName}(${JSON.stringify(descriptor.options ?? {})})`);\n\t\t}\n\t});\n\n\tconst adapterImport = needsAdapter\n\t\t? `import { adaptSandboxEntry } from \"emdash/plugins/adapt-sandbox-entry\";\\n`\n\t\t: \"\";\n\n\treturn `\n// Auto-generated plugins module\n// Imports and instantiates all configured plugins at runtime\n\n${adapterImport}${imports.join(\"\\n\")}\n\n/** Resolved plugins array */\nexport const plugins = [\n ${instantiations.join(\",\\n \")}\n];\n`;\n}\n\n/**\n * Generates the admin registry module.\n * Uses adminEntry from plugin descriptors to statically import admin modules.\n */\nexport function generateAdminRegistryModule(descriptors: PluginDescriptor[]): string {\n\t// Filter to descriptors with admin entries\n\tconst adminDescriptors = descriptors.filter((d) => d.adminEntry);\n\n\tif (adminDescriptors.length === 0) {\n\t\treturn `export const pluginAdmins = {};`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst entries: string[] = [];\n\n\tadminDescriptors.forEach((descriptor, index) => {\n\t\tconst varName = `admin${index}`;\n\t\t// Use explicit ID from descriptor if available, otherwise derive from entrypoint\n\t\tconst pluginId =\n\t\t\tdescriptor.id ??\n\t\t\tdescriptor.entrypoint.replace(SCOPED_PREFIX_PATTERN, \"\").replace(EMDASH_PREFIX_PATTERN, \"\");\n\n\t\timports.push(`import * as ${varName} from \"${descriptor.adminEntry}\";`);\n\t\tentries.push(` \"${pluginId}\": ${varName},`);\n\t});\n\n\treturn `\n// Auto-generated plugin admin registry\n${imports.join(\"\\n\")}\n\nexport const pluginAdmins = {\n${entries.join(\"\\n\")}\n};\n`;\n}\n\n/**\n * Generates the sandbox runner module.\n * Imports the configured sandbox runner factory or provides a noop default.\n */\nexport function generateSandboxRunnerModule(sandboxRunner?: string): string {\n\tif (!sandboxRunner) {\n\t\t// No sandbox runner configured - use noop\n\t\treturn `\n// No sandbox runner configured - sandboxed plugins disabled\nimport { createNoopSandboxRunner } from \"emdash\";\n\nexport const createSandboxRunner = createNoopSandboxRunner;\nexport const sandboxEnabled = false;\n`;\n\t}\n\n\treturn `\n// Auto-generated sandbox runner module\nimport { createSandboxRunner as _createSandboxRunner } from \"${sandboxRunner}\";\n\nexport const createSandboxRunner = _createSandboxRunner;\nexport const sandboxEnabled = true;\n`;\n}\n\n/**\n * Generates the media providers module.\n * Imports and instantiates configured media providers at runtime.\n */\nexport function generateMediaProvidersModule(descriptors: MediaProviderDescriptor[]): string {\n\t// Always include local provider by default unless explicitly disabled\n\tconst localDisabled = descriptors.some((d) => d.id === \"local\" && d.config.enabled === false);\n\n\tconst imports: string[] = [];\n\tconst entries: string[] = [];\n\n\t// Add local provider first if not disabled\n\tif (!localDisabled) {\n\t\timports.push(\n\t\t\t`import { createMediaProvider as createLocalProvider } from \"emdash/media/local-runtime\";`,\n\t\t);\n\t\tentries.push(`{\n\tid: \"local\",\n\tname: \"Library\",\n\ticon: \"folder\",\n\tcapabilities: { browse: true, search: false, upload: true, delete: true },\n\tcreateProvider: (ctx) => createLocalProvider({ ...ctx, enabled: true }),\n}`);\n\t}\n\n\t// Add custom providers\n\tdescriptors\n\t\t.filter((d) => d.id !== \"local\" || d.config.enabled !== false)\n\t\t.filter((d) => d.id !== \"local\") // Skip local if we already added it\n\t\t.forEach((descriptor, index) => {\n\t\t\tconst varName = `createProvider${index}`;\n\t\t\timports.push(`import { createMediaProvider as ${varName} } from \"${descriptor.entrypoint}\";`);\n\t\t\tentries.push(`{\n\tid: ${JSON.stringify(descriptor.id)},\n\tname: ${JSON.stringify(descriptor.name)},\n\ticon: ${JSON.stringify(descriptor.icon)},\n\tcapabilities: ${JSON.stringify(descriptor.capabilities)},\n\tcreateProvider: (ctx) => ${varName}({ ...${JSON.stringify(descriptor.config)}, ...ctx }),\n}`);\n\t\t});\n\n\treturn `\n// Auto-generated media providers module\n${imports.join(\"\\n\")}\n\n/** Media provider descriptors with factory functions */\nexport const mediaProviders = [\n ${entries.join(\",\\n \")}\n];\n`;\n}\n\n/**\n * Generates the block components module.\n * Collects and merges `blockComponents` exports from plugin component entries.\n */\nexport function generateBlockComponentsModule(descriptors: PluginDescriptor[]): string {\n\tconst withComponents = descriptors.filter((d) => d.componentsEntry);\n\tif (withComponents.length === 0) {\n\t\treturn `export const pluginBlockComponents = {};`;\n\t}\n\n\tconst imports: string[] = [];\n\tconst spreads: string[] = [];\n\twithComponents.forEach((d, i) => {\n\t\timports.push(`import { blockComponents as bc${i} } from \"${d.componentsEntry}\";`);\n\t\tspreads.push(`...bc${i}`);\n\t});\n\n\treturn `${imports.join(\"\\n\")}\\nexport const pluginBlockComponents = { ${spreads.join(\", \")} };`;\n}\n\n/**\n * Generates the wait-until virtual module.\n *\n * Under @astrojs/cloudflare, re-exports `waitUntil` from `cloudflare:workers`\n * so `after(fn)` in core can extend the worker's lifetime past the response\n * for deferred bookkeeping. For any other adapter, exports `undefined` —\n * Node's long-lived event loop keeps deferred promises running without a\n * lifetime extender.\n *\n * Keeping the adapter check here — rather than in core — means core itself\n * has no Cloudflare-specific imports or code paths.\n */\nexport function generateWaitUntilModule(adapterName: string | undefined): string {\n\tif (adapterName === \"@astrojs/cloudflare\") {\n\t\treturn `export { waitUntil } from \"cloudflare:workers\";`;\n\t}\n\treturn `export const waitUntil = undefined;`;\n}\n\n/**\n * Generates the seed virtual module.\n * Reads the user's seed file at build time (in Node context) and embeds it,\n * so the runtime doesn't need filesystem access (required for workerd).\n *\n * Exports `userSeed` (user's seed or null) and `seed` (user's seed or default).\n */\nexport function generateSeedModule(projectRoot: string): string {\n\tlet userSeedJson: string | null = null;\n\n\t// Try .emdash/seed.json\n\ttry {\n\t\tconst seedPath = resolve(projectRoot, \".emdash\", \"seed.json\");\n\t\tconst content = readFileSync(seedPath, \"utf-8\");\n\t\tJSON.parse(content); // validate\n\t\tuserSeedJson = content;\n\t} catch {\n\t\t// Not found, try next\n\t}\n\n\t// Try package.json → emdash.seed reference\n\tif (!userSeedJson) {\n\t\ttry {\n\t\t\tconst pkgPath = resolve(projectRoot, \"package.json\");\n\t\t\tconst pkgContent = readFileSync(pkgPath, \"utf-8\");\n\t\t\tconst pkg: { emdash?: { seed?: string } } = JSON.parse(pkgContent);\n\n\t\t\tif (pkg.emdash?.seed) {\n\t\t\t\tconst seedPath = resolve(projectRoot, pkg.emdash.seed);\n\t\t\t\tconst content = readFileSync(seedPath, \"utf-8\");\n\t\t\t\tJSON.parse(content); // validate\n\t\t\t\tuserSeedJson = content;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not found\n\t\t}\n\t}\n\n\tif (userSeedJson) {\n\t\treturn [`export const userSeed = ${userSeedJson};`, `export const seed = userSeed;`].join(\"\\n\");\n\t}\n\n\t// No user seed — inline the default\n\treturn [\n\t\t`export const userSeed = null;`,\n\t\t`export const seed = ${JSON.stringify(defaultSeed)};`,\n\t].join(\"\\n\");\n}\n\n/**\n * Resolve a module specifier from the project's context.\n * Uses Node.js require.resolve with the project root as base.\n */\nfunction resolveModulePathFromProject(specifier: string, projectRoot: string): string {\n\t// Create require from the project's package.json location\n\tconst projectPackageJson = resolve(projectRoot, \"package.json\");\n\tconst require = createRequire(projectPackageJson);\n\treturn require.resolve(specifier);\n}\n\n/**\n * Generates the sandboxed plugins module.\n * Resolves plugin entrypoints to files, reads them, and embeds the code.\n *\n * At runtime, middleware uses SandboxRunner to load these into isolates.\n */\nexport function generateSandboxedPluginsModule(\n\tsandboxed: PluginDescriptor[],\n\tprojectRoot: string,\n): string {\n\tif (sandboxed.length === 0) {\n\t\treturn `\n// No sandboxed plugins configured\nexport const sandboxedPlugins = [];\n`;\n\t}\n\n\tconst pluginEntries: string[] = [];\n\n\tfor (const descriptor of sandboxed) {\n\t\tconst bundleSpecifier = descriptor.entrypoint;\n\n\t\t// Resolve the bundle to a file path using project's require context\n\t\tconst filePath = resolveModulePathFromProject(bundleSpecifier, projectRoot);\n\n\t\tconst ext = filePath.slice(filePath.lastIndexOf(\".\"));\n\t\tif (TS_SOURCE_EXT_RE.test(ext)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Sandboxed plugin \"${descriptor.id}\" entrypoint \"${bundleSpecifier}\" resolves to ` +\n\t\t\t\t\t`unbuilt source (${filePath}). Sandbox entries must be pre-built JavaScript. ` +\n\t\t\t\t\t`Ensure the plugin's package.json exports point to built files (e.g. dist/*.mjs) ` +\n\t\t\t\t\t`and run the plugin's build step before building the site.`,\n\t\t\t);\n\t\t}\n\n\t\tconst code = readFileSync(filePath, \"utf-8\");\n\n\t\t// Create the plugin entry with embedded code and sandbox config\n\t\tpluginEntries.push(`{\n id: ${JSON.stringify(descriptor.id)},\n version: ${JSON.stringify(descriptor.version)},\n options: ${JSON.stringify(descriptor.options ?? {})},\n capabilities: ${JSON.stringify(descriptor.capabilities ?? [])},\n allowedHosts: ${JSON.stringify(descriptor.allowedHosts ?? [])},\n storage: ${JSON.stringify(descriptor.storage ?? {})},\n adminPages: ${JSON.stringify(descriptor.adminPages ?? [])},\n adminWidgets: ${JSON.stringify(descriptor.adminWidgets ?? [])},\n adminEntry: ${JSON.stringify(descriptor.adminEntry)},\n // Code read from: ${filePath}\n code: ${JSON.stringify(code)},\n }`);\n\t}\n\n\treturn `\n// Auto-generated sandboxed plugins module\n// Plugin code is embedded at build time\n\n/**\n * Sandboxed plugin entries with embedded code.\n * Loaded at runtime via SandboxRunner.\n */\nexport const sandboxedPlugins = [\n ${pluginEntries.join(\",\\n \")}\n];\n`;\n}\n","/**\n * Vite Plugin Configuration\n *\n * Defines the Vite plugin that handles virtual modules and other\n * Vite-specific configuration for EmDash.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { AstroConfig } from \"astro\";\nimport type { Plugin } from \"vite\";\n\nimport { COMMIT, VERSION } from \"../../version.js\";\nimport type { EmDashConfig, PluginDescriptor } from \"./runtime.js\";\nimport {\n\tVIRTUAL_CONFIG_ID,\n\tRESOLVED_VIRTUAL_CONFIG_ID,\n\tVIRTUAL_DIALECT_ID,\n\tRESOLVED_VIRTUAL_DIALECT_ID,\n\tVIRTUAL_STORAGE_ID,\n\tRESOLVED_VIRTUAL_STORAGE_ID,\n\tVIRTUAL_ADMIN_REGISTRY_ID,\n\tRESOLVED_VIRTUAL_ADMIN_REGISTRY_ID,\n\tVIRTUAL_PLUGINS_ID,\n\tRESOLVED_VIRTUAL_PLUGINS_ID,\n\tVIRTUAL_SANDBOX_RUNNER_ID,\n\tRESOLVED_VIRTUAL_SANDBOX_RUNNER_ID,\n\tVIRTUAL_SANDBOXED_PLUGINS_ID,\n\tRESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID,\n\tVIRTUAL_AUTH_ID,\n\tRESOLVED_VIRTUAL_AUTH_ID,\n\tVIRTUAL_AUTH_PROVIDERS_ID,\n\tRESOLVED_VIRTUAL_AUTH_PROVIDERS_ID,\n\tVIRTUAL_MEDIA_PROVIDERS_ID,\n\tRESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID,\n\tVIRTUAL_BLOCK_COMPONENTS_ID,\n\tRESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID,\n\tVIRTUAL_SEED_ID,\n\tRESOLVED_VIRTUAL_SEED_ID,\n\tVIRTUAL_WAIT_UNTIL_ID,\n\tRESOLVED_VIRTUAL_WAIT_UNTIL_ID,\n\tgenerateSeedModule,\n\tgenerateWaitUntilModule,\n\tgenerateConfigModule,\n\tgenerateDialectModule,\n\tgenerateStorageModule,\n\tgenerateAuthModule,\n\tgenerateAuthProvidersModule,\n\tgeneratePluginsModule,\n\tgenerateAdminRegistryModule,\n\tgenerateSandboxRunnerModule,\n\tgenerateSandboxedPluginsModule,\n\tgenerateMediaProvidersModule,\n\tgenerateBlockComponentsModule,\n} from \"./virtual-modules.js\";\n\nconst LOCALE_MESSAGES_RE = /[/\\\\]([a-z]{2}(?:-[A-Z]{2})?)[/\\\\]messages\\.mjs$/;\n/**\n * Vite plugin that compiles Lingui macros in admin source files.\n * Only active in dev mode when the admin package is aliased to source for HMR.\n * @babel/core is dynamically imported from admin's devDependencies —\n * not declared by core, never ships to end users.\n */\nfunction linguiMacroPlugin(adminSourcePath: string, adminDistPath: string): Plugin {\n\t// Resolve @babel/core from admin's devDependencies, not core's.\n\tconst adminRequire = createRequire(resolve(adminDistPath, \"index.js\"));\n\tconst babelCorePath = adminRequire.resolve(\"@babel/core\");\n\n\treturn {\n\t\tname: \"emdash-lingui-macro\",\n\t\tenforce: \"pre\",\n\t\tresolveId(id, importer) {\n\t\t\t// Redirect relative locale catalog imports (e.g. ./de/messages.mjs) from\n\t\t\t// within admin source to the compiled dist/locales/ directory, since\n\t\t\t// lingui compile only runs during build — not in dev watch mode.\n\t\t\tif (!importer?.startsWith(adminSourcePath)) return;\n\t\t\tconst match = id.match(LOCALE_MESSAGES_RE);\n\t\t\tif (match?.[1]) {\n\t\t\t\treturn resolve(adminDistPath, \"locales\", match[1], \"messages.mjs\");\n\t\t\t}\n\t\t},\n\t\tasync transform(code, id) {\n\t\t\tif (!id.startsWith(adminSourcePath) || !code.includes(\"@lingui\")) return;\n\t\t\tconst { transformAsync } = (await import(babelCorePath)) as typeof import(\"@babel/core\");\n\t\t\tconst result = await transformAsync(code, {\n\t\t\t\tfilename: id,\n\t\t\t\tplugins: [\"@lingui/babel-plugin-lingui-macro\"],\n\t\t\t\tparserOpts: { plugins: [\"jsx\", \"typescript\"] },\n\t\t\t});\n\t\t\tif (!result?.code) return;\n\t\t\treturn { code: result.code, map: result.map ?? undefined };\n\t\t},\n\t};\n}\n\n/**\n * Resolve path to the admin package dist directory.\n * Used for Vite alias to ensure the package is found in pnpm's isolated node_modules.\n */\nfunction resolveAdminDist(): string {\n\tconst require = createRequire(import.meta.url);\n\tconst adminPath = require.resolve(\"@emdash-cms/admin\");\n\t// Return the directory containing the built package (dist/)\n\treturn dirname(adminPath);\n}\n\n/**\n * Check whether child is inside parent without relying on simple prefix checks.\n */\nfunction isInside(parent: string, child: string): boolean {\n\tconst relativePath = relative(parent, child);\n\treturn relativePath === \"\" || (!relativePath.startsWith(\"..\") && !isAbsolute(relativePath));\n}\n\n/**\n * Resolve path to the admin package source directory.\n * In dev mode inside this repo, we alias @emdash-cms/admin to the source so\n * Vite processes it directly — giving instant HMR instead of requiring a\n * rebuild + restart. External apps should use the built package surface.\n */\nfunction resolveAdminSource(projectRoot: string): string | undefined {\n\tconst require = createRequire(import.meta.url);\n\tconst adminPath = require.resolve(\"@emdash-cms/admin\");\n\t// dist/index.js -> go up to package root, then into src/\n\tconst packageRoot = resolve(dirname(adminPath), \"..\");\n\tconst repoRoot = resolve(packageRoot, \"..\", \"..\");\n\tconst srcEntry = resolve(packageRoot, \"src\", \"index.ts\");\n\n\ttry {\n\t\tif (existsSync(srcEntry) && isInside(repoRoot, projectRoot)) {\n\t\t\treturn resolve(packageRoot, \"src\");\n\t\t}\n\t} catch {\n\t\t// Not in local repo — fall back to dist\n\t}\n\treturn undefined;\n}\n\nexport interface VitePluginOptions {\n\t/** Serializable config (database, storage, auth descriptors) */\n\tserializableConfig: Record<string, unknown>;\n\t/** Resolved EmDash config */\n\tresolvedConfig: EmDashConfig;\n\t/** Plugin descriptors */\n\tpluginDescriptors: PluginDescriptor[];\n\t/** Astro config */\n\tastroConfig: AstroConfig;\n}\n\n/**\n * Creates the EmDash virtual modules Vite plugin.\n */\nexport function createVirtualModulesPlugin(options: VitePluginOptions): Plugin {\n\tconst { serializableConfig, resolvedConfig, pluginDescriptors, astroConfig } = options;\n\n\treturn {\n\t\tname: \"emdash-virtual-modules\",\n\t\tresolveId(id: string) {\n\t\t\tif (id === VIRTUAL_CONFIG_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_CONFIG_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_DIALECT_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_DIALECT_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_STORAGE_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_STORAGE_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_ADMIN_REGISTRY_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_ADMIN_REGISTRY_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_PLUGINS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_PLUGINS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_SANDBOX_RUNNER_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_SANDBOX_RUNNER_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_SANDBOXED_PLUGINS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_AUTH_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_AUTH_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_AUTH_PROVIDERS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_AUTH_PROVIDERS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_MEDIA_PROVIDERS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_BLOCK_COMPONENTS_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_SEED_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_SEED_ID;\n\t\t\t}\n\t\t\tif (id === VIRTUAL_WAIT_UNTIL_ID) {\n\t\t\t\treturn RESOLVED_VIRTUAL_WAIT_UNTIL_ID;\n\t\t\t}\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id === RESOLVED_VIRTUAL_CONFIG_ID) {\n\t\t\t\treturn generateConfigModule(serializableConfig);\n\t\t\t}\n\t\t\t// Generate a module that statically imports the configured dialect\n\t\t\t// This allows Vite to properly resolve and bundle it\n\t\t\tif (id === RESOLVED_VIRTUAL_DIALECT_ID) {\n\t\t\t\treturn generateDialectModule({\n\t\t\t\t\tentrypoint: resolvedConfig.database?.entrypoint,\n\t\t\t\t\ttype: resolvedConfig.database?.type,\n\t\t\t\t\tsupportsRequestScope: resolvedConfig.database?.supportsRequestScope ?? false,\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Generate a module that statically imports the configured storage\n\t\t\tif (id === RESOLVED_VIRTUAL_STORAGE_ID) {\n\t\t\t\treturn generateStorageModule(resolvedConfig.storage?.entrypoint);\n\t\t\t}\n\t\t\t// Generate plugins module that imports and instantiates all plugins\n\t\t\tif (id === RESOLVED_VIRTUAL_PLUGINS_ID) {\n\t\t\t\treturn generatePluginsModule(pluginDescriptors);\n\t\t\t}\n\t\t\t// Generate admin registry module with plugin components\n\t\t\tif (id === RESOLVED_VIRTUAL_ADMIN_REGISTRY_ID) {\n\t\t\t\t// Include both trusted and sandboxed plugins\n\t\t\t\tconst allDescriptors = [...pluginDescriptors, ...(resolvedConfig.sandboxed ?? [])];\n\t\t\t\treturn generateAdminRegistryModule(allDescriptors);\n\t\t\t}\n\t\t\t// Generate sandbox runner module\n\t\t\tif (id === RESOLVED_VIRTUAL_SANDBOX_RUNNER_ID) {\n\t\t\t\treturn generateSandboxRunnerModule(resolvedConfig.sandboxRunner);\n\t\t\t}\n\t\t\t// Generate sandboxed plugins config module\n\t\t\tif (id === RESOLVED_VIRTUAL_SANDBOXED_PLUGINS_ID) {\n\t\t\t\t// Pass project root for proper module resolution\n\t\t\t\tconst projectRoot = fileURLToPath(astroConfig.root);\n\t\t\t\treturn generateSandboxedPluginsModule(resolvedConfig.sandboxed ?? [], projectRoot);\n\t\t\t}\n\t\t\t// Generate auth module that statically imports the configured auth provider\n\t\t\tif (id === RESOLVED_VIRTUAL_AUTH_ID) {\n\t\t\t\tconst authDescriptor = resolvedConfig.auth;\n\t\t\t\tif (!authDescriptor || !(\"entrypoint\" in authDescriptor)) {\n\t\t\t\t\treturn generateAuthModule(undefined);\n\t\t\t\t}\n\t\t\t\treturn generateAuthModule(authDescriptor.entrypoint);\n\t\t\t}\n\t\t\t// Generate auth providers module (pluggable login methods)\n\t\t\tif (id === RESOLVED_VIRTUAL_AUTH_PROVIDERS_ID) {\n\t\t\t\treturn generateAuthProvidersModule(resolvedConfig.authProviders ?? []);\n\t\t\t}\n\t\t\t// Generate media providers module\n\t\t\tif (id === RESOLVED_VIRTUAL_MEDIA_PROVIDERS_ID) {\n\t\t\t\treturn generateMediaProvidersModule(resolvedConfig.mediaProviders ?? []);\n\t\t\t}\n\t\t\t// Generate block components module (plugin rendering components for PortableText)\n\t\t\tif (id === RESOLVED_VIRTUAL_BLOCK_COMPONENTS_ID) {\n\t\t\t\treturn generateBlockComponentsModule(pluginDescriptors);\n\t\t\t}\n\t\t\t// Generate seed module — embeds user seed or default at build time\n\t\t\tif (id === RESOLVED_VIRTUAL_SEED_ID) {\n\t\t\t\tconst projectRoot = fileURLToPath(astroConfig.root);\n\t\t\t\treturn generateSeedModule(projectRoot);\n\t\t\t}\n\t\t\t// Generate wait-until module — re-exports cloudflare:workers'\n\t\t\t// waitUntil under the Cloudflare adapter, undefined otherwise.\n\t\t\tif (id === RESOLVED_VIRTUAL_WAIT_UNTIL_ID) {\n\t\t\t\treturn generateWaitUntilModule(astroConfig.adapter?.name);\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Modules that contain native Node.js addons or Node-only code.\n * These must be external in SSR to avoid bundling failures on Node.\n * On Cloudflare, the adapter handles its own externalization — setting\n * ssr.external there conflicts with @cloudflare/vite-plugin's validation.\n */\nconst NODE_NATIVE_EXTERNALS = [\n\t\"better-sqlite3\",\n\t\"bindings\",\n\t\"file-uri-to-path\",\n\t\"@libsql/kysely-libsql\",\n\t\"pg\",\n];\n\n/**\n * Detect whether the Cloudflare adapter is being used.\n */\nfunction isCloudflareAdapter(astroConfig: AstroConfig): boolean {\n\treturn astroConfig.adapter?.name === \"@astrojs/cloudflare\";\n}\n\n/**\n * Creates the Vite config update for EmDash.\n */\nexport function createViteConfig(\n\toptions: VitePluginOptions,\n\tcommand: \"dev\" | \"build\" | \"preview\" | \"sync\",\n): NonNullable<AstroConfig[\"vite\"]> {\n\tconst adminDistPath = resolveAdminDist();\n\tconst cloudflare = isCloudflareAdapter(options.astroConfig);\n\tconst isDev = command === \"dev\";\n\tconst projectRoot = fileURLToPath(options.astroConfig.root);\n\n\tconst adminSourcePath = isDev ? resolveAdminSource(projectRoot) : undefined;\n\tconst useSource = adminSourcePath !== undefined;\n\n\treturn {\n\t\t// Astro SSR routes resolve version.ts from source (not tsdown dist),\n\t\t// so Vite needs its own define pass for the __EMDASH_*__ placeholders.\n\t\tdefine: {\n\t\t\t__EMDASH_VERSION__: JSON.stringify(VERSION),\n\t\t\t__EMDASH_COMMIT__: JSON.stringify(COMMIT),\n\t\t\t__EMDASH_PSEUDO_LOCALE__: JSON.stringify(\n\t\t\t\tisDev && process.env[\"EMDASH_PSEUDO_LOCALE\"] === \"1\",\n\t\t\t),\n\t\t},\n\t\tresolve: {\n\t\t\tdedupe: [\"@emdash-cms/admin\", \"react\", \"react-dom\"],\n\t\t\t// Array form so more-specific entries are checked first.\n\t\t\t// The styles.css alias must come before the package alias, otherwise\n\t\t\t// Vite's prefix matching on \"@emdash-cms/admin\" would resolve\n\t\t\t// \"@emdash-cms/admin/styles.css\" through the source directory.\n\t\t\talias: [\n\t\t\t\t{ find: \"@emdash-cms/admin/styles.css\", replacement: resolve(adminDistPath, \"styles.css\") },\n\t\t\t\t{ find: \"@emdash-cms/admin\", replacement: useSource ? adminSourcePath : adminDistPath },\n\t\t\t\t// `use-sync-external-store/shim` is a React <18 polyfill that ships\n\t\t\t\t// only as CJS. It's pulled in transitively by `@tiptap/react`. With\n\t\t\t\t// pnpm's virtual store the file lives under .pnpm/, where Vite's\n\t\t\t\t// dep scanner can't reach it for pre-bundling — so the browser is\n\t\t\t\t// served raw `module.exports` and hydration fails with\n\t\t\t\t// `SyntaxError: ... does not provide an export named\n\t\t\t\t// 'useSyncExternalStore'`. Redirect both shim entry points to the\n\t\t\t\t// main `use-sync-external-store` package, which on React >=18\n\t\t\t\t// (our peer-dep floor) delegates to React's built-in hook.\n\t\t\t\t{\n\t\t\t\t\tfind: \"use-sync-external-store/shim/index.js\",\n\t\t\t\t\treplacement: \"use-sync-external-store\",\n\t\t\t\t},\n\t\t\t\t{ find: \"use-sync-external-store/shim\", replacement: \"use-sync-external-store\" },\n\t\t\t],\n\t\t},\n\t\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Monorepo has both vite 6 (docs) and vite 7 (core). tsgo resolves correctly.\n\t\tplugins: [\n\t\t\tcreateVirtualModulesPlugin(options),\n\t\t\t// In dev mode with source alias, compile Lingui macros on the fly\n\t\t\t// and redirect locale .mjs imports to dist/.\n\t\t\t// In production, macros are pre-compiled by tsdown in the admin package.\n\t\t\t...(useSource ? [linguiMacroPlugin(adminSourcePath, adminDistPath)] : []),\n\t\t] as NonNullable<AstroConfig[\"vite\"]>[\"plugins\"],\n\t\t// Handle native modules for SSR.\n\t\t// On Node: external keeps native addons out of the SSR bundle.\n\t\t// On Cloudflare: skip — the adapter handles externalization, and setting\n\t\t// ssr.external conflicts with @cloudflare/vite-plugin's resolve.external validation.\n\t\tssr: cloudflare\n\t\t\t? {\n\t\t\t\t\tnoExternal: [\"emdash\", \"@emdash-cms/admin\"],\n\t\t\t\t\t// Pre-bundle EmDash's runtime deps for workerd. Without this,\n\t\t\t\t\t// Vite discovers them one-by-one on first request, causing workerd\n\t\t\t\t\t// to enter \"worker cancelled\" state on cold cache.\n\t\t\t\t\toptimizeDeps: {\n\t\t\t\t\t\t// Exclude EmDash virtual modules from esbuild's dependency\n\t\t\t\t\t\t// scan. These are resolved by the Vite plugin at transform time,\n\t\t\t\t\t\t// but esbuild encounters them when crawling emdash's dist files\n\t\t\t\t\t\t// during pre-bundling and can't resolve them. Vite's exclude\n\t\t\t\t\t\t// uses prefix matching (id.startsWith(m + \"/\")), so\n\t\t\t\t\t\t// \"virtual:emdash\" matches all \"virtual:emdash/*\" imports.\n\t\t\t\t\t\texclude: [\"virtual:emdash\"],\n\t\t\t\t\t\tinclude: [\n\t\t\t\t\t\t\t// EmDash direct deps\n\t\t\t\t\t\t\t\"emdash > @portabletext/toolkit\",\n\t\t\t\t\t\t\t\"emdash > @unpic/placeholder\",\n\t\t\t\t\t\t\t\"emdash > blurhash\",\n\t\t\t\t\t\t\t\"emdash > croner\",\n\t\t\t\t\t\t\t\"emdash > image-size\",\n\t\t\t\t\t\t\t\"emdash > jose\",\n\t\t\t\t\t\t\t\"emdash > jpeg-js\",\n\t\t\t\t\t\t\t\"emdash > kysely\",\n\t\t\t\t\t\t\t\"emdash > mime/lite\",\n\t\t\t\t\t\t\t\"emdash > modern-tar\",\n\t\t\t\t\t\t\t\"emdash > sanitize-html\",\n\t\t\t\t\t\t\t\"emdash > ulidx\",\n\t\t\t\t\t\t\t\"emdash > upng-js\",\n\t\t\t\t\t\t\t\"emdash > astro-portabletext\",\n\t\t\t\t\t\t\t\"emdash > sax\",\n\t\t\t\t\t\t\t// Deeper transitive deps\n\t\t\t\t\t\t\t\"emdash > sanitize-html > parse5\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/gutenberg-to-portable-text > @wordpress/block-serialization-default-parser\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/auth > @oslojs/crypto/ecdsa\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/auth > @oslojs/crypto/sha2\",\n\t\t\t\t\t\t\t\"emdash > @emdash-cms/auth > @oslojs/webauthn\",\n\t\t\t\t\t\t\t// MCP SDK — server/index.js statically imports ajv (CJS-only).\n\t\t\t\t\t\t\t// Pre-bundling converts CJS to ESM so workerd can load it.\n\t\t\t\t\t\t\t\"emdash > @modelcontextprotocol/sdk > ajv\",\n\t\t\t\t\t\t\t\"emdash > @modelcontextprotocol/sdk > ajv-formats\",\n\t\t\t\t\t\t\t// React (commonly used, may be hoisted)\n\t\t\t\t\t\t\t\"react\",\n\t\t\t\t\t\t\t\"react/jsx-dev-runtime\",\n\t\t\t\t\t\t\t\"react/jsx-runtime\",\n\t\t\t\t\t\t\t\"react-dom\",\n\t\t\t\t\t\t\t\"react-dom/server\",\n\t\t\t\t\t\t\t// Top-level deps (use astro > path for pnpm compat)\n\t\t\t\t\t\t\t\"astro > zod/v4\",\n\t\t\t\t\t\t\t\"astro > zod/v4/core\",\n\t\t\t\t\t\t\t\"@emdash-cms/cloudflare > kysely-d1\",\n\t\t\t\t\t\t\t// Astro internal deps not covered by @astrojs/cloudflare adapter\n\t\t\t\t\t\t\t\"astro/virtual-modules/middleware.js\",\n\t\t\t\t\t\t\t\"astro/virtual-modules/live-config\",\n\t\t\t\t\t\t\t\"astro/content/runtime\",\n\t\t\t\t\t\t\t\"astro/assets/utils/inferRemoteSize.js\",\n\t\t\t\t\t\t\t\"astro/assets/fonts/runtime.js\",\n\t\t\t\t\t\t\t\"@astrojs/cloudflare/image-service\",\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\texternal: NODE_NATIVE_EXTERNALS,\n\t\t\t\t\tnoExternal: [\"emdash\", \"@emdash-cms/admin\"],\n\t\t\t\t},\n\t\toptimizeDeps: {\n\t\t\t// When using source, don't pre-bundle JS — let Vite transform on the fly for HMR.\n\t\t\t// When using dist, pre-bundle to avoid re-optimization on first hydration.\n\t\t\tinclude: useSource\n\t\t\t\t? [\"@astrojs/react/client.js\"]\n\t\t\t\t: [\"@emdash-cms/admin\", \"@astrojs/react/client.js\"],\n\t\t\texclude: cloudflare ? [\"virtual:emdash\"] : [...NODE_NATIVE_EXTERNALS, \"virtual:emdash\"],\n\t\t},\n\t};\n}\n","/**\n * Runtime utilities for EmDash\n *\n * This file contains functions that are used at runtime (in middleware, routes, etc.)\n * and must work in all environments including Cloudflare Workers.\n *\n * DO NOT import Node.js-only modules here (fs, path, module, etc.)\n */\n\nimport type { AuthDescriptor, AuthProviderDescriptor } from \"../../auth/types.js\";\nimport type { DatabaseDescriptor } from \"../../db/adapters.js\";\nimport type { MediaProviderDescriptor } from \"../../media/types.js\";\nimport type { ResolvedPlugin } from \"../../plugins/types.js\";\nimport type { StorageDescriptor } from \"../storage/types.js\";\n\nexport type { ResolvedPlugin };\nexport type { MediaProviderDescriptor };\n\n/**\n * Admin page definition (copied from plugins/types to avoid circular deps)\n */\nexport interface PluginAdminPage {\n\tpath: string;\n\tlabel: string;\n\ticon?: string;\n}\n\n/**\n * Dashboard widget definition (copied from plugins/types to avoid circular deps)\n */\nexport interface PluginDashboardWidget {\n\tid: string;\n\tsize?: \"full\" | \"half\" | \"third\";\n\ttitle?: string;\n}\n\n/**\n * Plugin descriptor - returned by plugin factory functions\n *\n * Contains all static metadata needed for manifest and admin UI,\n * plus the entrypoint for runtime instantiation.\n *\n * @example\n * ```ts\n * export function myPlugin(options?: MyPluginOptions): PluginDescriptor {\n * return {\n * id: \"my-plugin\",\n * version: \"1.0.0\",\n * entrypoint: \"@my-org/emdash-plugin-foo\",\n * options: options ?? {},\n * adminEntry: \"@my-org/emdash-plugin-foo/admin\",\n * adminPages: [{ path: \"/settings\", label: \"Settings\" }],\n * };\n * }\n * ```\n */\n/**\n * Storage collection declaration for sandboxed plugins\n */\nexport interface StorageCollectionDeclaration {\n\tindexes?: string[];\n\tuniqueIndexes?: string[];\n}\n\nexport interface PluginDescriptor<TOptions = Record<string, unknown>> {\n\t/** Unique plugin identifier */\n\tid: string;\n\t/** Plugin version (semver) */\n\tversion: string;\n\t/** Module specifier to import (e.g., \"@emdash-cms/plugin-api-test\") */\n\tentrypoint: string;\n\t/**\n\t * Options to pass to createPlugin(). Native format only.\n\t * Standard-format plugins configure themselves via KV settings\n\t * and Block Kit admin pages -- not constructor options.\n\t */\n\toptions?: TOptions;\n\t/**\n\t * Plugin format. Determines how the entrypoint is loaded:\n\t * - `\"standard\"` -- exports `definePlugin({ hooks, routes })` as default.\n\t * Wrapped with `adaptSandboxEntry` for in-process execution. Can run in both\n\t * `plugins: []` (in-process) and `sandboxed: []` (isolate).\n\t * - `\"native\"` -- exports `createPlugin(options)` returning a `ResolvedPlugin`.\n\t * Can only run in `plugins: []`. Cannot be sandboxed or published to marketplace.\n\t *\n\t * Defaults to `\"native\"` when unset.\n\t *\n\t */\n\tformat?: \"standard\" | \"native\";\n\t/** Admin UI module specifier (e.g., \"@emdash-cms/plugin-audit-log/admin\") */\n\tadminEntry?: string;\n\t/** Module specifier for site-side Astro rendering components (must export `blockComponents`) */\n\tcomponentsEntry?: string;\n\t/** Admin pages for navigation */\n\tadminPages?: PluginAdminPage[];\n\t/** Dashboard widgets */\n\tadminWidgets?: PluginDashboardWidget[];\n\n\t// === Sandbox-specific fields (for sandboxed plugins) ===\n\n\t/**\n\t * Capabilities the plugin requests.\n\t * For standard-format plugins, capabilities are enforced in both trusted and\n\t * sandboxed modes via the PluginContextFactory.\n\t */\n\tcapabilities?: string[];\n\t/**\n\t * Allowed hosts for network:fetch capability\n\t * Supports wildcards like \"*.example.com\"\n\t */\n\tallowedHosts?: string[];\n\t/**\n\t * Storage collections the plugin declares\n\t * Sandboxed plugins can only access declared collections.\n\t */\n\tstorage?: Record<string, StorageCollectionDeclaration>;\n}\n\n/**\n * Sandboxed plugin descriptor - same format as PluginDescriptor\n *\n * These run in isolated V8 isolates via Worker Loader on Cloudflare.\n * The `entrypoint` is resolved to a file and bundled at build time.\n */\nexport type SandboxedPluginDescriptor<TOptions = Record<string, unknown>> =\n\tPluginDescriptor<TOptions>;\n\nexport interface EmDashConfig {\n\t/**\n\t * Database configuration\n\t *\n\t * Use one of the adapter functions:\n\t * - `sqlite({ url: \"file:./data.db\" })` - Local SQLite\n\t * - `libsql({ url: \"...\", authToken: \"...\" })` - Turso/libSQL\n\t * - `d1({ binding: \"DB\" })` - Cloudflare D1\n\t *\n\t * @example\n\t * ```ts\n\t * import { sqlite } from \"emdash/db\";\n\t *\n\t * emdash({\n\t * database: sqlite({ url: \"file:./data.db\" }),\n\t * })\n\t * ```\n\t */\n\tdatabase?: DatabaseDescriptor;\n\t/**\n\t * Storage configuration (for media)\n\t */\n\tstorage?: StorageDescriptor;\n\t/**\n\t * Trusted plugins to load (run in main isolate)\n\t *\n\t * @example\n\t * ```ts\n\t * import { auditLogPlugin } from \"@emdash-cms/plugin-audit-log\";\n\t * import { webhookNotifierPlugin } from \"@emdash-cms/plugin-webhook-notifier\";\n\t *\n\t * emdash({\n\t * plugins: [\n\t * auditLogPlugin(),\n\t * webhookNotifierPlugin({ url: \"https://example.com/webhook\" }),\n\t * ],\n\t * })\n\t * ```\n\t */\n\tplugins?: PluginDescriptor[];\n\t/**\n\t * Sandboxed plugins to load (run in isolated V8 isolates)\n\t *\n\t * Only works on Cloudflare with Worker Loader enabled.\n\t * Uses the same format as `plugins` - the difference is where they run.\n\t *\n\t * @example\n\t * ```ts\n\t * import { untrustedPlugin } from \"some-third-party-plugin\";\n\t *\n\t * emdash({\n\t * plugins: [trustedPlugin()], // runs in host\n\t * sandboxed: [untrustedPlugin()], // runs in isolate\n\t * sandboxRunner: \"@emdash-cms/sandbox-cloudflare\",\n\t * })\n\t * ```\n\t */\n\tsandboxed?: SandboxedPluginDescriptor[];\n\t/**\n\t * Module that exports the sandbox runner factory.\n\t * Required if using sandboxed plugins.\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * sandboxRunner: \"@emdash-cms/sandbox-cloudflare\",\n\t * })\n\t * ```\n\t */\n\tsandboxRunner?: string;\n\n\t/**\n\t * Authentication configuration\n\t *\n\t * Use an auth adapter function from a platform package:\n\t * - `access({ teamDomain: \"...\" })` from `@emdash-cms/cloudflare`\n\t *\n\t * When an external auth provider is configured, passkey auth is disabled.\n\t *\n\t * @example\n\t * ```ts\n\t * import { access } from \"@emdash-cms/cloudflare\";\n\t *\n\t * emdash({\n\t * auth: access({\n\t * teamDomain: \"myteam.cloudflareaccess.com\",\n\t * audience: \"abc123...\",\n\t * roleMapping: {\n\t * \"Admins\": 50,\n\t * \"Editors\": 30,\n\t * },\n\t * }),\n\t * })\n\t * ```\n\t */\n\tauth?: AuthDescriptor;\n\n\t/**\n\t * Pluggable auth providers (login methods on the login page).\n\t *\n\t * Auth providers appear as options alongside passkey on the login page\n\t * and setup wizard. Any provider can be used to create the initial\n\t * admin account. Passkey is built-in; providers listed here are additive.\n\t *\n\t * @example\n\t * ```ts\n\t * import { atproto } from \"@emdash-cms/auth-atproto\";\n\t *\n\t * emdash({\n\t * authProviders: [atproto()],\n\t * })\n\t * ```\n\t */\n\tauthProviders?: AuthProviderDescriptor[];\n\n\t/**\n\t * MCP (Model Context Protocol) server endpoint.\n\t *\n\t * Exposes an MCP Streamable HTTP server at `/_emdash/api/mcp`\n\t * that allows AI agents and tools to interact with the CMS using\n\t * the standardized MCP protocol.\n\t *\n\t * Enabled by default. The endpoint requires bearer token auth, so\n\t * it has no effect unless the user creates an API token and\n\t * configures a client. Set to `false` to disable.\n\t *\n\t * @default true\n\t */\n\tmcp?: boolean;\n\n\t/**\n\t * Plugin marketplace URL\n\t *\n\t * When set, enables the marketplace features: browse, install, update,\n\t * and uninstall plugins from a remote marketplace.\n\t *\n\t * Must be an HTTPS URL in production, or localhost/127.0.0.1 in dev.\n\t * Requires `sandboxRunner` to be configured (marketplace plugins run sandboxed).\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * marketplace: \"https://marketplace.emdashcms.com\",\n\t * sandboxRunner: \"@emdash-cms/sandbox-cloudflare\",\n\t * })\n\t * ```\n\t */\n\tmarketplace?: string;\n\n\t/**\n\t * Maximum allowed media file upload size in bytes.\n\t *\n\t * Applies to both direct multipart uploads and signed-URL uploads.\n\t * When unset, defaults to 52_428_800 (50 MB).\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({ maxUploadSize: 100 * 1024 * 1024 }) // 100 MB\n\t * ```\n\t */\n\tmaxUploadSize?: number;\n\n\t/**\n\t * Public browser-facing origin for the site.\n\t *\n\t * Use when `Astro.url` / `request.url` do not match what users open — common with a\n\t * **TLS-terminating reverse proxy**: the app often sees `http://` on the internal hop\n\t * while the browser uses `https://`, which breaks WebAuthn, CSRF, OAuth, and redirect URLs.\n\t *\n\t * Set to the full origin users type in the address bar (no path), e.g.\n\t * `https://mysite.example.com`. When not set, falls back to environment variables\n\t * `EMDASH_SITE_URL` > `SITE_URL`, then to the request URL's origin.\n\t *\n\t * Replaces `passkeyPublicOrigin` (which only fixed passkeys).\n\t */\n\tsiteUrl?: string;\n\n\t/**\n\t * Headers to trust for client IP resolution when running behind a reverse\n\t * proxy. The first header in this list that is present on the request\n\t * wins. Applies to rate limiting for auth endpoints and comment\n\t * submission.\n\t *\n\t * Common values:\n\t * - `x-real-ip` — nginx, Caddy, Traefik\n\t * - `fly-client-ip` — Fly.io\n\t * - `x-forwarded-for` — generic (first entry is used)\n\t *\n\t * Only set this when you **control the reverse proxy**. Untrusted\n\t * clients can set any header they like; trusting headers from an open\n\t * network is an IP-spoofing vulnerability that defeats rate limiting.\n\t *\n\t * On Cloudflare the `cf` object on the request is used automatically —\n\t * you normally don't need to set this. Leave unset (or empty) to\n\t * preserve the default: IP is resolved only when the request came\n\t * through Cloudflare's edge.\n\t *\n\t * Falls back to `EMDASH_TRUSTED_PROXY_HEADERS` env var (comma-separated)\n\t * when this option is not set, so operators can configure at deploy\n\t * time without touching the Astro config.\n\t */\n\ttrustedProxyHeaders?: string[];\n\n\t/**\n\t * Enable playground mode for ephemeral \"try EmDash\" sites.\n\t *\n\t * When set, the integration injects a playground middleware (order: \"pre\")\n\t * that runs BEFORE the normal EmDash middleware chain. It creates an\n\t * isolated Durable Object database per session, runs migrations, applies\n\t * the seed, creates an anonymous admin user, and sets the DB in ALS.\n\t * By the time the runtime middleware runs, the database is fully ready.\n\t *\n\t * Setup and auth middleware are skipped (the playground handles both).\n\t *\n\t * Requires `@emdash-cms/cloudflare` as a dependency and a DO binding\n\t * in wrangler.jsonc.\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * database: playgroundDatabase({ binding: \"PLAYGROUND_DB\" }),\n\t * playground: {\n\t * middlewareEntrypoint: \"@emdash-cms/cloudflare/db/playground-middleware\",\n\t * },\n\t * })\n\t * ```\n\t */\n\tplayground?: {\n\t\t/** Module path for the playground middleware. */\n\t\tmiddlewareEntrypoint: string;\n\t};\n\n\t/**\n\t * Media providers for browsing and uploading media\n\t *\n\t * The local media provider (using storage adapter) is available by default.\n\t * Additional providers can be added for external services like Unsplash,\n\t * Cloudinary, Mux, Cloudflare Images, etc.\n\t *\n\t * @example\n\t * ```ts\n\t * import { cloudflareImages, cloudflareStream } from \"@emdash-cms/cloudflare\";\n\t * import { unsplash } from \"@emdash-cms/provider-unsplash\";\n\t *\n\t * emdash({\n\t * mediaProviders: [\n\t * cloudflareImages({ accountId: \"...\" }),\n\t * cloudflareStream({ accountId: \"...\" }),\n\t * unsplash({ accessKey: \"...\" }),\n\t * ],\n\t * })\n\t * ```\n\t */\n\tmediaProviders?: MediaProviderDescriptor[];\n\n\t/**\n\t * Admin UI font configuration.\n\t *\n\t * By default, EmDash loads Noto Sans via the Astro Font API, covering\n\t * Latin, Latin Extended, Cyrillic, Cyrillic Extended, Greek, Greek\n\t * Extended, Devanagari, and Vietnamese. Fonts are downloaded from\n\t * Google at build time and self-hosted, so there are no runtime CDN\n\t * requests.\n\t *\n\t * To add support for additional writing systems (Arabic, CJK, etc.),\n\t * pass script names. EmDash resolves the matching Noto Sans variant\n\t * from Google Fonts and merges all script faces under a single\n\t * font-family, so the browser downloads only the glyphs it needs\n\t * via unicode-range.\n\t *\n\t * Set to `false` to disable font injection entirely and use system fonts.\n\t *\n\t * @example\n\t * ```ts\n\t * // Add Arabic and Japanese support\n\t * emdash({\n\t * fonts: {\n\t * scripts: [\"arabic\", \"japanese\"],\n\t * },\n\t * })\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * // Disable web fonts entirely (use system fonts)\n\t * emdash({\n\t * fonts: false,\n\t * })\n\t * ```\n\t */\n\tfonts?:\n\t\t| false\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * Additional Noto Sans script families to include.\n\t\t\t\t *\n\t\t\t\t * Available scripts: arabic, armenian, bengali, chinese-simplified,\n\t\t\t\t * chinese-traditional, chinese-hongkong, devanagari, ethiopic, farsi,\n\t\t\t\t * georgian, gujarati, gurmukhi, hebrew, japanese, kannada, khmer,\n\t\t\t\t * korean, lao, malayalam, myanmar, oriya, sinhala, tamil, telugu,\n\t\t\t\t * thai, tibetan.\n\t\t\t\t */\n\t\t\t\tscripts?: string[];\n\t\t };\n\n\t/**\n\t * Admin UI branding (white-labeling).\n\t *\n\t * Overrides the default EmDash logo and name in the admin panel.\n\t * Use this to white-label the CMS for agency or enterprise deployments.\n\t * These settings are separate from the public site settings (title, logo,\n\t * favicon) which remain available for SEO and front-end use.\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * admin: {\n\t * logo: \"/images/agency-logo.webp\",\n\t * siteName: \"AgencyX CMS\",\n\t * favicon: \"/favicon.ico\",\n\t * },\n\t * })\n\t * ```\n\t */\n\tadmin?: {\n\t\t/** URL or path to a custom logo image for the admin UI (login page, sidebar). */\n\t\tlogo?: string;\n\t\t/** Custom name displayed in the admin sidebar and browser tab. */\n\t\tsiteName?: string;\n\t\t/** URL or path to a custom favicon for the admin panel. */\n\t\tfavicon?: string;\n\t};\n}\n\n/**\n * Get stored config from global\n * This is set by the virtual module at build time\n */\nexport function getStoredConfig(): EmDashConfig | null {\n\treturn globalThis.__emdashConfig || null;\n}\n\n/**\n * Set stored config in global\n * Called by the integration at config time\n */\nexport function setStoredConfig(config: EmDashConfig): void {\n\tglobalThis.__emdashConfig = config;\n}\n\n// Declare global type\ndeclare global {\n\t// eslint-disable-next-line no-var\n\tvar __emdashConfig: EmDashConfig | undefined;\n}\n","/**\n * EmDash Astro Integration\n *\n * This integration:\n * - Injects the admin shell route at /_emdash/admin/[...path].astro\n * - Sets up REST API endpoints under /_emdash/api/*\n * - Configures middleware to provide database and manifest\n *\n * NOTE: This file is for build-time only. Runtime utilities are in runtime.ts\n * to avoid bundling Node.js-only code into the production build.\n */\n\nimport type { AstroIntegration, AstroIntegrationLogger } from \"astro\";\n\nimport type { ResolvedPlugin } from \"../../plugins/types.js\";\nimport { local } from \"../storage/adapters.js\";\nimport { notoSans } from \"./font-provider.js\";\nimport {\n\tinjectCoreRoutes,\n\tinjectBuiltinAuthRoutes,\n\tinjectAuthProviderRoutes,\n\tinjectMcpRoute,\n} from \"./routes.js\";\nimport type { EmDashConfig, PluginDescriptor } from \"./runtime.js\";\nimport { createViteConfig } from \"./vite-config.js\";\n\n// Re-export runtime types and functions\nexport type {\n\tEmDashConfig,\n\tPluginDescriptor,\n\tSandboxedPluginDescriptor,\n\tResolvedPlugin,\n} from \"./runtime.js\";\nexport { getStoredConfig } from \"./runtime.js\";\n\n/** Default storage: Local filesystem in .emdash directory */\nconst DEFAULT_STORAGE = local({\n\tdirectory: \"./.emdash/uploads\",\n\tbaseUrl: \"/_emdash/api/media/file\",\n});\n\n// Terminal formatting\nconst dim = (s: string) => `\\x1b[2m${s}\\x1b[22m`;\nconst bold = (s: string) => `\\x1b[1m${s}\\x1b[22m`;\nconst cyan = (s: string) => `\\x1b[36m${s}\\x1b[39m`;\n\n/** Print the EmDash startup banner */\nfunction printBanner(_logger: AstroIntegrationLogger): void {\n\tconst banner = `\n\n ${bold(cyan(\"— E M D A S H —\"))}\n `;\n\tconsole.log(banner);\n}\n\n/** Print route injection summary */\nfunction printRoutesSummary(_logger: AstroIntegrationLogger): void {\n\tconsole.log(`\\n ${dim(\"›\")} Admin UI ${cyan(\"/_emdash/admin\")}`);\n\tconsole.log(` ${dim(\"›\")} API ${cyan(\"/_emdash/api/*\")}`);\n\tconsole.log(\"\");\n}\n\n/**\n * Create the EmDash Astro integration\n */\nexport function emdash(config: EmDashConfig = {}): AstroIntegration {\n\t// Apply defaults\n\tconst resolvedConfig: EmDashConfig = {\n\t\t...config,\n\t\tstorage: config.storage ?? DEFAULT_STORAGE,\n\t};\n\n\t// Validate marketplace URL\n\tif (resolvedConfig.marketplace) {\n\t\tconst url = resolvedConfig.marketplace;\n\t\ttry {\n\t\t\tconst parsed = new URL(url);\n\t\t\tconst isLocalhost = parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\";\n\t\t\tif (parsed.protocol !== \"https:\" && !isLocalhost) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Marketplace URL must use HTTPS (got ${parsed.protocol}). ` +\n\t\t\t\t\t\t`Only localhost URLs are allowed over HTTP.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e instanceof TypeError) {\n\t\t\t\tthrow new Error(`Invalid marketplace URL: \"${url}\"`, { cause: e });\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t\tif (!resolvedConfig.sandboxRunner) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Marketplace requires `sandboxRunner` to be configured. \" +\n\t\t\t\t\t\"Marketplace plugins run in sandboxed V8 isolates.\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// Validate siteUrl if provided in astro.config.mjs.\n\t// Env-var fallback (EMDASH_SITE_URL / SITE_URL) is handled at runtime by\n\t// getPublicOrigin() in api/public-url.ts — NOT here — so Docker images built\n\t// without a domain can pick it up at container start via process.env.\n\tif (resolvedConfig.siteUrl) {\n\t\tconst raw = resolvedConfig.siteUrl;\n\t\ttry {\n\t\t\tconst parsed = new URL(raw);\n\t\t\tif (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n\t\t\t\tthrow new Error(`siteUrl must be http or https (got ${parsed.protocol})`);\n\t\t\t}\n\t\t\t// Always store origin-normalized value (no path) — security invariant L-1\n\t\t\tresolvedConfig.siteUrl = parsed.origin;\n\t\t} catch (e) {\n\t\t\tif (e instanceof TypeError) {\n\t\t\t\tthrow new Error(`Invalid siteUrl: \"${raw}\"`, { cause: e });\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\t// Plugin descriptors from config\n\tconst pluginDescriptors = resolvedConfig.plugins ?? [];\n\tconst sandboxedDescriptors = resolvedConfig.sandboxed ?? [];\n\n\t// Validate all plugin descriptors\n\tfor (const descriptor of [...pluginDescriptors, ...sandboxedDescriptors]) {\n\t\t// Standard-format plugins can't use features that require trusted mode\n\t\tif (descriptor.format === \"standard\") {\n\t\t\tif (descriptor.adminEntry) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Plugin \"${descriptor.id}\" is standard format but declares adminEntry. ` +\n\t\t\t\t\t\t`Standard plugins use Block Kit for admin UI, not React components. ` +\n\t\t\t\t\t\t`Remove adminEntry or change format to \"native\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (descriptor.componentsEntry) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Plugin \"${descriptor.id}\" is standard format but declares componentsEntry. ` +\n\t\t\t\t\t\t`Portable Text block components require native format. ` +\n\t\t\t\t\t\t`Remove componentsEntry or change format to \"native\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate: non-standard plugins cannot be placed in sandboxed: []\n\tfor (const descriptor of sandboxedDescriptors) {\n\t\tif (descriptor.format !== \"standard\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Plugin \"${descriptor.id}\" uses the native format and cannot be placed in ` +\n\t\t\t\t\t`\\`sandboxed: []\\`. Native plugins can only run in \\`plugins: []\\`. ` +\n\t\t\t\t\t`To sandbox this plugin, convert it to the standard format.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Resolved plugins (populated at build time by importing entrypoints)\n\tlet _resolvedPlugins: ResolvedPlugin[] = [];\n\n\t// Serialize config for virtual module (database/storage/auth - plugins handled separately)\n\t// i18n is populated in astro:config:setup from astroConfig.i18n\n\tconst serializableConfig: Record<string, unknown> = {\n\t\tdatabase: resolvedConfig.database,\n\t\tstorage: resolvedConfig.storage,\n\t\tauth: resolvedConfig.auth,\n\t\tauthProviders: resolvedConfig.authProviders,\n\t\tmarketplace: resolvedConfig.marketplace,\n\t\tsiteUrl: resolvedConfig.siteUrl,\n\t\ttrustedProxyHeaders: resolvedConfig.trustedProxyHeaders,\n\t\tmaxUploadSize: resolvedConfig.maxUploadSize,\n\t\tadmin: resolvedConfig.admin,\n\t};\n\n\t// Determine auth mode for route injection\n\t// Check if auth is an AuthDescriptor (has entrypoint) indicating external auth\n\tconst useExternalAuth = !!(resolvedConfig.auth && \"entrypoint\" in resolvedConfig.auth);\n\n\treturn {\n\t\tname: \"emdash\",\n\t\thooks: {\n\t\t\t\"astro:config:setup\": ({\n\t\t\t\tinjectRoute,\n\t\t\t\taddMiddleware,\n\t\t\t\tlogger,\n\t\t\t\tupdateConfig,\n\t\t\t\tconfig: astroConfig,\n\t\t\t\tcommand,\n\t\t\t}) => {\n\t\t\t\tprintBanner(logger);\n\t\t\t\t// Extract i18n config from Astro config\n\t\t\t\t// Astro locales can be strings OR { path, codes } objects — normalize to paths\n\t\t\t\tif (astroConfig.i18n) {\n\t\t\t\t\tconst routing = astroConfig.i18n.routing;\n\t\t\t\t\tserializableConfig.i18n = {\n\t\t\t\t\t\tdefaultLocale: astroConfig.i18n.defaultLocale,\n\t\t\t\t\t\tlocales: astroConfig.i18n.locales.map((l) => (typeof l === \"string\" ? l : l.path)),\n\t\t\t\t\t\tfallback: astroConfig.i18n.fallback,\n\t\t\t\t\t\tprefixDefaultLocale:\n\t\t\t\t\t\t\ttypeof routing === \"object\" ? (routing.prefixDefaultLocale ?? false) : false,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Disable Astro's built-in checkOrigin -- EmDash's own CSRF\n\t\t\t\t// layer (checkPublicCsrf in api/csrf.ts) handles origin\n\t\t\t\t// validation with dual-origin support: it accepts both the\n\t\t\t\t// internal origin AND the public origin from getPublicOrigin(),\n\t\t\t\t// which resolves siteUrl from config or env vars at runtime.\n\t\t\t\t// Astro's check can't do this because allowedDomains is baked\n\t\t\t\t// at build time, which breaks Docker deployments where the\n\t\t\t\t// domain is only known at container start via EMDASH_SITE_URL.\n\t\t\t\t//\n\t\t\t\t// When siteUrl is known at build time, also set allowedDomains\n\t\t\t\t// so Astro.url reflects the public origin (helps user template\n\t\t\t\t// code that reads Astro.url directly).\n\t\t\t\tconst securityConfig: Record<string, unknown> = {\n\t\t\t\t\tcheckOrigin: false,\n\t\t\t\t\t...(resolvedConfig.siteUrl\n\t\t\t\t\t\t? { allowedDomains: [{ hostname: new URL(resolvedConfig.siteUrl).hostname }] }\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\n\t\t\t\t// Inject default Noto Sans font for the admin UI.\n\t\t\t\t// Uses the Astro Font API so fonts are downloaded at build time\n\t\t\t\t// and self-hosted (no runtime CDN requests).\n\t\t\t\t//\n\t\t\t\t// The admin CSS references var(--font-emdash) with a system font\n\t\t\t\t// fallback. Users can add extra script coverage (Arabic, CJK, etc.)\n\t\t\t\t// by passing fonts.scripts in the emdash() config. The custom\n\t\t\t\t// notoSans provider resolves all script families from Google Fonts\n\t\t\t\t// under a single font-family name, so they stack via unicode-range.\n\t\t\t\tconst fontsConfig = resolvedConfig.fonts;\n\t\t\t\tconst emdashFonts =\n\t\t\t\t\tfontsConfig === false\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tprovider: notoSans({\n\t\t\t\t\t\t\t\t\t\tscripts: fontsConfig?.scripts,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\tname: \"Noto Sans\",\n\t\t\t\t\t\t\t\t\tcssVariable: \"--font-emdash\",\n\t\t\t\t\t\t\t\t\tweights: [\"100 900\" as const],\n\t\t\t\t\t\t\t\t\tstyles: [\"normal\" as const, \"italic\" as const],\n\t\t\t\t\t\t\t\t\tsubsets: [\n\t\t\t\t\t\t\t\t\t\t\"latin\" as const,\n\t\t\t\t\t\t\t\t\t\t\"latin-ext\" as const,\n\t\t\t\t\t\t\t\t\t\t\"cyrillic\" as const,\n\t\t\t\t\t\t\t\t\t\t\"cyrillic-ext\" as const,\n\t\t\t\t\t\t\t\t\t\t\"devanagari\" as const,\n\t\t\t\t\t\t\t\t\t\t\"greek\" as const,\n\t\t\t\t\t\t\t\t\t\t\"greek-ext\" as const,\n\t\t\t\t\t\t\t\t\t\t\"vietnamese\" as const,\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\tfallbacks: [\"ui-sans-serif\", \"system-ui\", \"sans-serif\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t];\n\n\t\t\t\tupdateConfig({\n\t\t\t\t\tsecurity: securityConfig,\n\t\t\t\t\t// fonts is a valid AstroConfig key but may not be in the\n\t\t\t\t\t// type definition for the minimum supported Astro version\n\t\t\t\t\t...({ fonts: emdashFonts } as Record<string, unknown>),\n\t\t\t\t\tvite: createViteConfig(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tserializableConfig,\n\t\t\t\t\t\t\tresolvedConfig,\n\t\t\t\t\t\t\tpluginDescriptors,\n\t\t\t\t\t\t\tastroConfig,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcommand,\n\t\t\t\t\t),\n\t\t\t\t});\n\n\t\t\t\t// Inject all core routes\n\t\t\t\tinjectCoreRoutes(injectRoute);\n\n\t\t\t\t// Inject routes from pluggable auth providers (authProviders config)\n\t\t\t\tif (resolvedConfig.authProviders?.length) {\n\t\t\t\t\tinjectAuthProviderRoutes(injectRoute, resolvedConfig.authProviders);\n\t\t\t\t}\n\n\t\t\t\t// Inject passkey/oauth/magic-link routes unless transparent external auth is active\n\t\t\t\tif (!useExternalAuth) {\n\t\t\t\t\tinjectBuiltinAuthRoutes(injectRoute);\n\t\t\t\t}\n\n\t\t\t\t// Inject MCP endpoint (always on — bearer-token-only, no cost if unused)\n\t\t\t\tif (resolvedConfig.mcp !== false) {\n\t\t\t\t\tinjectMcpRoute(injectRoute);\n\t\t\t\t}\n\n\t\t\t\t// In playground mode, inject the playground middleware FIRST.\n\t\t\t\t// It sets up a per-session DO database in ALS before anything\n\t\t\t\t// else runs, so the runtime init middleware sees a real DB.\n\t\t\t\tif (resolvedConfig.playground) {\n\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\tentrypoint: resolvedConfig.playground.middlewareEntrypoint,\n\t\t\t\t\t\torder: \"pre\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Add middleware to provide database and manifest\n\t\t\t\taddMiddleware({\n\t\t\t\t\tentrypoint: \"emdash/middleware\",\n\t\t\t\t\torder: \"pre\",\n\t\t\t\t});\n\n\t\t\t\t// Add redirect middleware (runs after runtime init, before setup/auth)\n\t\t\t\taddMiddleware({\n\t\t\t\t\tentrypoint: \"emdash/middleware/redirect\",\n\t\t\t\t\torder: \"pre\",\n\t\t\t\t});\n\n\t\t\t\t// Skip setup and auth in playground mode -- the playground middleware\n\t\t\t\t// handles session creation and injects an anonymous admin user.\n\t\t\t\tif (!resolvedConfig.playground) {\n\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\tentrypoint: \"emdash/middleware/setup\",\n\t\t\t\t\t\torder: \"pre\",\n\t\t\t\t\t});\n\n\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\tentrypoint: \"emdash/middleware/auth\",\n\t\t\t\t\t\torder: \"pre\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Add request context middleware (runs after auth, on ALL routes)\n\t\t\t\t// Sets up ALS-based context for query functions (edit mode, preview)\n\t\t\t\taddMiddleware({\n\t\t\t\t\tentrypoint: \"emdash/middleware/request-context\",\n\t\t\t\t\torder: \"pre\",\n\t\t\t\t});\n\n\t\t\t\tprintRoutesSummary(logger);\n\t\t\t},\n\t\t\t\"astro:server:setup\": ({ server, logger }) => {\n\t\t\t\t// Generate types once the server is listening.\n\t\t\t\t// The endpoint returns the types content; we write the file here\n\t\t\t\t// (in Node) because workerd has no real filesystem access.\n\t\t\t\tserver.httpServer?.once(\"listening\", async () => {\n\t\t\t\t\tconst { writeFile, readFile } = await import(\"node:fs/promises\");\n\t\t\t\t\tconst { resolve } = await import(\"node:path\");\n\n\t\t\t\t\tconst address = server.httpServer?.address();\n\t\t\t\t\tif (!address || typeof address === \"string\") return;\n\n\t\t\t\t\tconst port = address.port;\n\t\t\t\t\tconst typegenUrl = `http://localhost:${port}/_emdash/api/typegen`;\n\t\t\t\t\tconst outputPath = resolve(process.cwd(), \"emdash-env.d.ts\");\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst response = await fetch(typegenUrl, {\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\t\tconst body = await response.text().catch(() => \"\");\n\t\t\t\t\t\t\tlogger.warn(`Typegen failed: ${response.status} ${body.slice(0, 200)}`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst { data: result } = (await response.json()) as {\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\ttypes: string;\n\t\t\t\t\t\t\t\thash: string;\n\t\t\t\t\t\t\t\tcollections: number;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Only write if content changed\n\t\t\t\t\t\tlet needsWrite = true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst existing = await readFile(outputPath, \"utf-8\");\n\t\t\t\t\t\t\tif (existing === result.types) needsWrite = false;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// File doesn't exist yet\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (needsWrite) {\n\t\t\t\t\t\t\tawait writeFile(outputPath, result.types, \"utf-8\");\n\t\t\t\t\t\t\tlogger.info(`Generated emdash-env.d.ts (${result.collections} collections)`);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst msg = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\tlogger.warn(`Typegen failed: ${msg}`);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\t\"astro:build:done\": ({ logger }) => {\n\t\t\t\tlogger.info(\"Build complete\");\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport default emdash;\n"],"mappings":"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"}