emdash 0.2.0 → 0.4.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 (197) hide show
  1. package/dist/{adapters-N6BF7RCD.d.mts → adapters-C2BzVy0p.d.mts} +1 -1
  2. package/dist/{adapters-N6BF7RCD.d.mts.map → adapters-C2BzVy0p.d.mts.map} +1 -1
  3. package/dist/{apply-wmVEOSbR.mjs → apply-Cma_PiF6.mjs} +38 -23
  4. package/dist/apply-Cma_PiF6.mjs.map +1 -0
  5. package/dist/astro/index.d.mts +25 -11
  6. package/dist/astro/index.d.mts.map +1 -1
  7. package/dist/astro/index.mjs +38 -25
  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.mjs +2 -2
  11. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  12. package/dist/astro/middleware/redirect.mjs +20 -8
  13. package/dist/astro/middleware/redirect.mjs.map +1 -1
  14. package/dist/astro/middleware/request-context.mjs +12 -2
  15. package/dist/astro/middleware/request-context.mjs.map +1 -1
  16. package/dist/astro/middleware/setup.mjs +1 -1
  17. package/dist/astro/middleware.d.mts.map +1 -1
  18. package/dist/astro/middleware.mjs +52 -45
  19. package/dist/astro/middleware.mjs.map +1 -1
  20. package/dist/astro/types.d.mts +9 -9
  21. package/dist/astro/types.d.mts.map +1 -1
  22. package/dist/{byline-1WQPlISL.mjs → byline-WuOq9MFJ.mjs} +5 -4
  23. package/dist/byline-WuOq9MFJ.mjs.map +1 -0
  24. package/dist/{bylines-BYdTYmia.mjs → bylines-C_Wsnz4L.mjs} +38 -6
  25. package/dist/bylines-C_Wsnz4L.mjs.map +1 -0
  26. package/dist/cache-E3Dts-yT.mjs +56 -0
  27. package/dist/cache-E3Dts-yT.mjs.map +1 -0
  28. package/dist/cli/index.mjs +13 -13
  29. package/dist/cli/index.mjs.map +1 -1
  30. package/dist/client/cf-access.d.mts +1 -1
  31. package/dist/client/index.d.mts +1 -1
  32. package/dist/client/index.mjs +1 -1
  33. package/dist/{config-Cq8H0SfX.mjs → config-DkxPrM9l.mjs} +1 -1
  34. package/dist/{config-Cq8H0SfX.mjs.map → config-DkxPrM9l.mjs.map} +1 -1
  35. package/dist/{content-BmXndhdi.mjs → content-BsBoyj8G.mjs} +20 -3
  36. package/dist/content-BsBoyj8G.mjs.map +1 -0
  37. package/dist/db/index.d.mts +3 -3
  38. package/dist/db/index.mjs +2 -2
  39. package/dist/db/libsql.d.mts +1 -1
  40. package/dist/db/postgres.d.mts +1 -1
  41. package/dist/db/sqlite.d.mts +1 -1
  42. package/dist/{default-WYlzADZL.mjs → default-PUx9RK6u.mjs} +1 -1
  43. package/dist/{default-WYlzADZL.mjs.map → default-PUx9RK6u.mjs.map} +1 -1
  44. package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +4 -1
  45. package/dist/dialect-helpers-DhTzaUxP.mjs.map +1 -0
  46. package/dist/{error-DrxtnGPg.mjs → error-HBeQbVhV.mjs} +1 -1
  47. package/dist/{error-DrxtnGPg.mjs.map → error-HBeQbVhV.mjs.map} +1 -1
  48. package/dist/{index-UHEVQMus.d.mts → index-CRg3PWfZ.d.mts} +59 -33
  49. package/dist/index-CRg3PWfZ.d.mts.map +1 -0
  50. package/dist/index.d.mts +11 -11
  51. package/dist/index.mjs +20 -20
  52. package/dist/{load-Veizk2cT.mjs → load-BhSSm-TS.mjs} +1 -1
  53. package/dist/{load-Veizk2cT.mjs.map → load-BhSSm-TS.mjs.map} +1 -1
  54. package/dist/{loader-CHb2v0jm.mjs → loader-BYzwzORf.mjs} +4 -2
  55. package/dist/loader-BYzwzORf.mjs.map +1 -0
  56. package/dist/{manifest-schema-CuMio1A9.mjs → manifest-schema-BsXINkQD.mjs} +1 -1
  57. package/dist/{manifest-schema-CuMio1A9.mjs.map → manifest-schema-BsXINkQD.mjs.map} +1 -1
  58. package/dist/media/index.d.mts +1 -1
  59. package/dist/media/index.mjs +1 -1
  60. package/dist/media/local-runtime.d.mts +7 -7
  61. package/dist/{mode-CYeM2rPt.mjs → mode-CyPLdO3C.mjs} +1 -1
  62. package/dist/{mode-CYeM2rPt.mjs.map → mode-CyPLdO3C.mjs.map} +1 -1
  63. package/dist/page/index.d.mts +1 -1
  64. package/dist/patterns-CrCYkMBb.mjs +93 -0
  65. package/dist/patterns-CrCYkMBb.mjs.map +1 -0
  66. package/dist/{placeholder-bOx1xCTY.d.mts → placeholder-BBCtpTES.d.mts} +1 -1
  67. package/dist/{placeholder-bOx1xCTY.d.mts.map → placeholder-BBCtpTES.d.mts.map} +1 -1
  68. package/dist/{placeholder-aiCD8aSZ.mjs → placeholder-DntBEQo7.mjs} +1 -1
  69. package/dist/{placeholder-aiCD8aSZ.mjs.map → placeholder-DntBEQo7.mjs.map} +1 -1
  70. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  71. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  72. package/dist/{query-5Hcv_5ER.mjs → query-B6Vu0d2i.mjs} +35 -16
  73. package/dist/{query-5Hcv_5ER.mjs.map → query-B6Vu0d2i.mjs.map} +1 -1
  74. package/dist/{redirect-DIfIni3r.mjs → redirect-7lGhLBNZ.mjs} +10 -93
  75. package/dist/redirect-7lGhLBNZ.mjs.map +1 -0
  76. package/dist/{registry-1EvbAfsC.mjs → registry-BgnP3ysR.mjs} +27 -37
  77. package/dist/registry-BgnP3ysR.mjs.map +1 -0
  78. package/dist/{runner-BoN0-FPi.mjs → runner-Cd-_WyDo.mjs} +18 -6
  79. package/dist/runner-Cd-_WyDo.mjs.map +1 -0
  80. package/dist/{runner-DTqkzOzc.d.mts → runner-DYv3rX8P.d.mts} +10 -3
  81. package/dist/runner-DYv3rX8P.d.mts.map +1 -0
  82. package/dist/runtime.d.mts +6 -6
  83. package/dist/runtime.mjs +2 -2
  84. package/dist/{search-BsYMed12.mjs → search-B5p9D36n.mjs} +108 -57
  85. package/dist/search-B5p9D36n.mjs.map +1 -0
  86. package/dist/seed/index.d.mts +2 -2
  87. package/dist/seed/index.mjs +10 -10
  88. package/dist/seo/index.d.mts +1 -1
  89. package/dist/storage/local.d.mts +1 -1
  90. package/dist/storage/local.mjs +1 -1
  91. package/dist/storage/s3.d.mts +11 -3
  92. package/dist/storage/s3.d.mts.map +1 -1
  93. package/dist/storage/s3.mjs +76 -15
  94. package/dist/storage/s3.mjs.map +1 -1
  95. package/dist/{tokens-DrB-W6Q-.mjs → tokens-DKHiCYCB.mjs} +1 -1
  96. package/dist/{tokens-DrB-W6Q-.mjs.map → tokens-DKHiCYCB.mjs.map} +1 -1
  97. package/dist/transaction-Cn2rjY78.mjs +28 -0
  98. package/dist/transaction-Cn2rjY78.mjs.map +1 -0
  99. package/dist/{transport-Bl8cTdYt.mjs → transport-BtcQ-Z7T.mjs} +1 -1
  100. package/dist/{transport-Bl8cTdYt.mjs.map → transport-BtcQ-Z7T.mjs.map} +1 -1
  101. package/dist/{transport-COOs9GSE.d.mts → transport-CKQA_G44.d.mts} +1 -1
  102. package/dist/{transport-COOs9GSE.d.mts.map → transport-CKQA_G44.d.mts.map} +1 -1
  103. package/dist/{types-7-UjSEyB.d.mts → types-B6BzlZxx.d.mts} +1 -1
  104. package/dist/{types-7-UjSEyB.d.mts.map → types-B6BzlZxx.d.mts.map} +1 -1
  105. package/dist/{types-6dqxBqsH.d.mts → types-BYWYxLcp.d.mts} +109 -5
  106. package/dist/types-BYWYxLcp.d.mts.map +1 -0
  107. package/dist/{types-CIsTnQvJ.d.mts → types-BmkQR1En.d.mts} +1 -1
  108. package/dist/{types-CIsTnQvJ.d.mts.map → types-BmkQR1En.d.mts.map} +1 -1
  109. package/dist/{types-BljtYPSd.d.mts → types-DNZpaCBk.d.mts} +14 -6
  110. package/dist/types-DNZpaCBk.d.mts.map +1 -0
  111. package/dist/{types-Bec-r_3_.mjs → types-Dz9_WMS6.mjs} +1 -1
  112. package/dist/types-Dz9_WMS6.mjs.map +1 -0
  113. package/dist/{types-CcreFIIH.d.mts → types-gLYVCXCQ.d.mts} +1 -1
  114. package/dist/{types-CcreFIIH.d.mts.map → types-gLYVCXCQ.d.mts.map} +1 -1
  115. package/dist/{types-DuNbGKjF.mjs → types-xxCWI3j0.mjs} +1 -1
  116. package/dist/{types-DuNbGKjF.mjs.map → types-xxCWI3j0.mjs.map} +1 -1
  117. package/dist/{validate-B7KP7VLM.d.mts → validate-CcNRWH6I.d.mts} +4 -4
  118. package/dist/{validate-B7KP7VLM.d.mts.map → validate-CcNRWH6I.d.mts.map} +1 -1
  119. package/dist/{validate-CXnRKfJK.mjs → validate-DuZDIxfy.mjs} +2 -2
  120. package/dist/{validate-CXnRKfJK.mjs.map → validate-DuZDIxfy.mjs.map} +1 -1
  121. package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +11 -11
  122. package/dist/{validate-CqRJb_xU.mjs.map → validate-VPnKoIzW.mjs.map} +1 -1
  123. package/dist/version-DlTDRdpv.mjs +7 -0
  124. package/dist/version-DlTDRdpv.mjs.map +1 -0
  125. package/package.json +7 -5
  126. package/src/api/handlers/content.ts +36 -25
  127. package/src/api/handlers/menus.ts +19 -16
  128. package/src/api/handlers/redirects.ts +95 -3
  129. package/src/api/schemas/redirects.ts +1 -0
  130. package/src/astro/integration/index.ts +2 -3
  131. package/src/astro/integration/runtime.ts +8 -14
  132. package/src/astro/integration/vite-config.ts +14 -4
  133. package/src/astro/middleware/redirect.ts +30 -15
  134. package/src/astro/middleware.ts +11 -19
  135. package/src/astro/routes/admin.astro +2 -2
  136. package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -0
  137. package/src/astro/routes/api/admin/bylines/index.ts +2 -0
  138. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -0
  139. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +2 -0
  140. package/src/astro/routes/api/manifest.ts +3 -1
  141. package/src/astro/routes/api/redirects/[id].ts +3 -0
  142. package/src/astro/routes/api/redirects/index.ts +2 -0
  143. package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -0
  144. package/src/astro/routes/api/schema/collections/index.ts +1 -0
  145. package/src/astro/storage/adapters.ts +19 -5
  146. package/src/astro/storage/types.ts +12 -4
  147. package/src/astro/types.ts +1 -0
  148. package/src/bylines/index.ts +50 -2
  149. package/src/cleanup.ts +3 -3
  150. package/src/cli/commands/bundle-utils.ts +5 -5
  151. package/src/database/dialect-helpers.ts +3 -0
  152. package/src/database/migrations/011_sections.ts +2 -2
  153. package/src/database/migrations/runner.ts +23 -2
  154. package/src/database/repositories/byline.ts +2 -1
  155. package/src/database/repositories/content.ts +5 -0
  156. package/src/database/repositories/redirect.ts +13 -0
  157. package/src/database/validate.ts +10 -10
  158. package/src/emdash-runtime.ts +23 -9
  159. package/src/index.ts +3 -0
  160. package/src/loader.ts +2 -0
  161. package/src/mcp/server.ts +40 -67
  162. package/src/menus/index.ts +4 -0
  163. package/src/plugins/context.ts +28 -4
  164. package/src/plugins/cron.ts +29 -4
  165. package/src/plugins/hooks.ts +22 -10
  166. package/src/plugins/index.ts +1 -0
  167. package/src/plugins/manager.ts +6 -2
  168. package/src/plugins/marketplace.ts +33 -3
  169. package/src/plugins/routes.ts +3 -3
  170. package/src/plugins/types.ts +7 -0
  171. package/src/query.ts +37 -14
  172. package/src/redirects/cache.ts +68 -0
  173. package/src/redirects/loops.ts +318 -0
  174. package/src/schema/registry.ts +3 -0
  175. package/src/search/fts-manager.ts +24 -11
  176. package/src/search/query.ts +8 -9
  177. package/src/seed/apply.ts +49 -28
  178. package/src/storage/s3.ts +94 -25
  179. package/src/storage/types.ts +13 -5
  180. package/src/utils/slugify.ts +11 -0
  181. package/src/version.ts +12 -0
  182. package/src/visual-editing/toolbar.ts +11 -1
  183. package/dist/apply-wmVEOSbR.mjs.map +0 -1
  184. package/dist/byline-1WQPlISL.mjs.map +0 -1
  185. package/dist/bylines-BYdTYmia.mjs.map +0 -1
  186. package/dist/content-BmXndhdi.mjs.map +0 -1
  187. package/dist/dialect-helpers-B9uSp2GJ.mjs.map +0 -1
  188. package/dist/index-UHEVQMus.d.mts.map +0 -1
  189. package/dist/loader-CHb2v0jm.mjs.map +0 -1
  190. package/dist/redirect-DIfIni3r.mjs.map +0 -1
  191. package/dist/registry-1EvbAfsC.mjs.map +0 -1
  192. package/dist/runner-BoN0-FPi.mjs.map +0 -1
  193. package/dist/runner-DTqkzOzc.d.mts.map +0 -1
  194. package/dist/search-BsYMed12.mjs.map +0 -1
  195. package/dist/types-6dqxBqsH.d.mts.map +0 -1
  196. package/dist/types-Bec-r_3_.mjs.map +0 -1
  197. package/dist/types-BljtYPSd.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/astro/storage/adapters.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 * @example\n * ```ts\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 * publicUrl: \"https://cdn.example.com\", // optional CDN\n * })\n * ```\n */\nexport function s3(config: 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 * 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: \"/_emdash/.well-known/oauth-authorization-server\",\n\t\tentrypoint: resolveRoute(\"api/well-known/oauth-authorization-server.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\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\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\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 * Statically imports the configured database dialect and exports the dialect type.\n *\n * For D1 adapters, also re-exports session helpers (isSessionEnabled, getD1Binding,\n * getDefaultConstraint, getBookmarkCookieName, createSessionDialect) used by\n * middleware for per-request read replica sessions.\n *\n * For non-D1 adapters, session exports are no-ops.\n */\nexport function generateDialectModule(\n\tdbEntrypoint?: string,\n\tdbType?: string,\n\tdbConfig?: unknown,\n): string {\n\tif (!dbEntrypoint) {\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 isSessionEnabled = () => false;`,\n\t\t\t`export const getD1Binding = () => null;`,\n\t\t\t`export const getDefaultConstraint = () => \"first-unconstrained\";`,\n\t\t\t`export const getBookmarkCookieName = () => \"\";`,\n\t\t\t`export const createSessionDialect = undefined;`,\n\t\t].join(\"\\n\");\n\t}\n\tconst type = dbType ?? \"sqlite\";\n\n\t// Check if the adapter is D1 (has session helpers)\n\tconst isD1 = dbEntrypoint.includes(\"cloudflare\") && dbEntrypoint.includes(\"d1\");\n\n\t// Check if sessions are enabled in the config\n\tconst sessionMode =\n\t\tisD1 && dbConfig && typeof dbConfig === \"object\" && \"session\" in dbConfig\n\t\t\t? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- runtime-checked above\n\t\t\t\t(dbConfig as { session?: string }).session\n\t\t\t: undefined;\n\tconst sessionEnabled = !!sessionMode && sessionMode !== \"disabled\";\n\n\tif (isD1 && sessionEnabled) {\n\t\treturn `\nimport { createDialect as _createDialect } from \"${dbEntrypoint}\";\nexport { isSessionEnabled, getD1Binding, getDefaultConstraint, getBookmarkCookieName, createSessionDialect } from \"${dbEntrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\n`;\n\t}\n\n\t// Non-D1 or sessions disabled: export no-ops\n\treturn `\nimport { createDialect as _createDialect } from \"${dbEntrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\nexport const isSessionEnabled = () => false;\nexport const getD1Binding = () => null;\nexport const getDefaultConstraint = () => \"first-unconstrained\";\nexport const getBookmarkCookieName = () => \"\";\nexport const createSessionDialect = undefined;\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 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 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\tgenerateSeedModule,\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},\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\tresolvedConfig.database?.entrypoint,\n\t\t\t\t\tresolvedConfig.database?.type,\n\t\t\t\t\tresolvedConfig.database?.config,\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},\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\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{\n\t\t\t\t\tfind: \"@emdash-cms/admin/locales/*\",\n\t\t\t\t\treplacement: resolve(adminDistPath, \"locales\", \"*\"),\n\t\t\t\t},\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// 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 * Enable the MCP (Model Context Protocol) server endpoint.\n\t *\n\t * When enabled, exposes an MCP Streamable HTTP server at\n\t * `/_emdash/api/mcp` that allows AI agents and tools to interact\n\t * with the CMS using the standardized MCP protocol.\n\t *\n\t * Authentication is handled by the existing EmDash auth middleware —\n\t * agents must authenticate with an API token or session cookie.\n\t *\n\t * @default false\n\t *\n\t * @example\n\t * ```ts\n\t * emdash({\n\t * mcp: true,\n\t * })\n\t * ```\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 * 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 * 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\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 { 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};\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\t\t\t\tupdateConfig({\n\t\t\t\t\tsecurity: securityConfig,\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 when enabled\n\t\t\t\tif (resolvedConfig.mcp) {\n\t\t\t\t\tinjectMcpRoute(injectRoute);\n\t\t\t\t\tlogger.info(\"MCP server enabled at /_emdash/api/mcp\");\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/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 * 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: \"/_emdash/.well-known/oauth-authorization-server\",\n\t\tentrypoint: resolveRoute(\"api/well-known/oauth-authorization-server.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\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\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\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 * Statically imports the configured database dialect and exports the dialect type.\n *\n * For D1 adapters, also re-exports session helpers (isSessionEnabled, getD1Binding,\n * getDefaultConstraint, getBookmarkCookieName, createSessionDialect) used by\n * middleware for per-request read replica sessions.\n *\n * For non-D1 adapters, session exports are no-ops.\n */\nexport function generateDialectModule(\n\tdbEntrypoint?: string,\n\tdbType?: string,\n\tdbConfig?: unknown,\n): string {\n\tif (!dbEntrypoint) {\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 isSessionEnabled = () => false;`,\n\t\t\t`export const getD1Binding = () => null;`,\n\t\t\t`export const getDefaultConstraint = () => \"first-unconstrained\";`,\n\t\t\t`export const getBookmarkCookieName = () => \"\";`,\n\t\t\t`export const createSessionDialect = undefined;`,\n\t\t].join(\"\\n\");\n\t}\n\tconst type = dbType ?? \"sqlite\";\n\n\t// Check if the adapter is D1 (has session helpers)\n\tconst isD1 = dbEntrypoint.includes(\"cloudflare\") && dbEntrypoint.includes(\"d1\");\n\n\t// Check if sessions are enabled in the config\n\tconst sessionMode =\n\t\tisD1 && dbConfig && typeof dbConfig === \"object\" && \"session\" in dbConfig\n\t\t\t? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- runtime-checked above\n\t\t\t\t(dbConfig as { session?: string }).session\n\t\t\t: undefined;\n\tconst sessionEnabled = !!sessionMode && sessionMode !== \"disabled\";\n\n\tif (isD1 && sessionEnabled) {\n\t\treturn `\nimport { createDialect as _createDialect } from \"${dbEntrypoint}\";\nexport { isSessionEnabled, getD1Binding, getDefaultConstraint, getBookmarkCookieName, createSessionDialect } from \"${dbEntrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\n`;\n\t}\n\n\t// Non-D1 or sessions disabled: export no-ops\n\treturn `\nimport { createDialect as _createDialect } from \"${dbEntrypoint}\";\nexport const createDialect = _createDialect;\nexport const dialectType = ${JSON.stringify(type)};\nexport const isSessionEnabled = () => false;\nexport const getD1Binding = () => null;\nexport const getDefaultConstraint = () => \"first-unconstrained\";\nexport const getBookmarkCookieName = () => \"\";\nexport const createSessionDialect = undefined;\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 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\tgenerateSeedModule,\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},\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\tresolvedConfig.database?.entrypoint,\n\t\t\t\t\tresolvedConfig.database?.type,\n\t\t\t\t\tresolvedConfig.database?.config,\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},\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 * 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 * 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\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 { 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};\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\t\t\t\tupdateConfig({\n\t\t\t\t\tsecurity: securityConfig,\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,8 +1,8 @@
1
- import "../../types-7-UjSEyB.mjs";
2
- import "../../index-UHEVQMus.mjs";
3
- import "../../runner-DTqkzOzc.mjs";
4
- import "../../types-6dqxBqsH.mjs";
5
- import "../../validate-B7KP7VLM.mjs";
1
+ import "../../types-B6BzlZxx.mjs";
2
+ import "../../index-CRg3PWfZ.mjs";
3
+ import "../../runner-DYv3rX8P.mjs";
4
+ import "../../types-BYWYxLcp.mjs";
5
+ import "../../validate-CcNRWH6I.mjs";
6
6
  import { EmDashHandlers, EmDashManifest } from "../types.mjs";
7
7
  import { User } from "@emdash-cms/auth";
8
8
  import * as astro from "astro";
@@ -1,5 +1,5 @@
1
- import { t as apiError } from "../../error-DrxtnGPg.mjs";
2
- import { t as getAuthMode } from "../../mode-CYeM2rPt.mjs";
1
+ import { t as apiError } from "../../error-HBeQbVhV.mjs";
2
+ import { t as getAuthMode } from "../../mode-CyPLdO3C.mjs";
3
3
  import { ulid } from "ulidx";
4
4
  import { defineMiddleware } from "astro:middleware";
5
5
  import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
@@ -1 +1 @@
1
- {"version":3,"file":"redirect.d.mts","names":[],"sources":["../../../src/astro/middleware/redirect.ts"],"mappings":";;;;;;AAgCA;;;;;;;;;;;;cAAa,SAAA,EAwDX,KAAA,CAxDoB,iBAAA"}
1
+ {"version":3,"file":"redirect.d.mts","names":[],"sources":["../../../src/astro/middleware/redirect.ts"],"mappings":";;;;;;AAqCA;;;;;;;;;;;;cAAa,SAAA,EAkEX,KAAA,CAlEoB,iBAAA"}