emdash 0.0.0-b → 0.0.2

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 (661) hide show
  1. package/README.md +87 -43
  2. package/dist/adapters-BLMa4JGD.d.mts +106 -0
  3. package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
  4. package/dist/apply-Bjfq_b4-.mjs +1293 -0
  5. package/dist/apply-Bjfq_b4-.mjs.map +1 -0
  6. package/dist/astro/index.d.mts +51 -0
  7. package/dist/astro/index.d.mts.map +1 -0
  8. package/dist/astro/index.mjs +1336 -0
  9. package/dist/astro/index.mjs.map +1 -0
  10. package/dist/astro/middleware/auth.d.mts +31 -0
  11. package/dist/astro/middleware/auth.d.mts.map +1 -0
  12. package/dist/astro/middleware/auth.mjs +654 -0
  13. package/dist/astro/middleware/auth.mjs.map +1 -0
  14. package/dist/astro/middleware/redirect.d.mts +22 -0
  15. package/dist/astro/middleware/redirect.d.mts.map +1 -0
  16. package/dist/astro/middleware/redirect.mjs +63 -0
  17. package/dist/astro/middleware/redirect.mjs.map +1 -0
  18. package/dist/astro/middleware/request-context.d.mts +18 -0
  19. package/dist/astro/middleware/request-context.d.mts.map +1 -0
  20. package/dist/astro/middleware/request-context.mjs +1310 -0
  21. package/dist/astro/middleware/request-context.mjs.map +1 -0
  22. package/dist/astro/middleware/setup.d.mts +20 -0
  23. package/dist/astro/middleware/setup.d.mts.map +1 -0
  24. package/dist/astro/middleware/setup.mjs +47 -0
  25. package/dist/astro/middleware/setup.mjs.map +1 -0
  26. package/dist/astro/middleware.d.mts +13 -0
  27. package/dist/astro/middleware.d.mts.map +1 -0
  28. package/dist/astro/middleware.mjs +1613 -0
  29. package/dist/astro/middleware.mjs.map +1 -0
  30. package/dist/astro/types.d.mts +250 -0
  31. package/dist/astro/types.d.mts.map +1 -0
  32. package/dist/astro/types.mjs +1 -0
  33. package/dist/base64-MBPo9ozB.mjs +59 -0
  34. package/dist/base64-MBPo9ozB.mjs.map +1 -0
  35. package/dist/byline-CL847F26.mjs +213 -0
  36. package/dist/byline-CL847F26.mjs.map +1 -0
  37. package/dist/bylines-C2a-2TGt.mjs +136 -0
  38. package/dist/bylines-C2a-2TGt.mjs.map +1 -0
  39. package/dist/chunk-ClPoSABd.mjs +21 -0
  40. package/dist/cli/index.d.mts +1 -0
  41. package/dist/cli/index.mjs +3909 -0
  42. package/dist/cli/index.mjs.map +1 -0
  43. package/dist/client/cf-access.d.mts +60 -0
  44. package/dist/client/cf-access.d.mts.map +1 -0
  45. package/dist/client/cf-access.mjs +179 -0
  46. package/dist/client/cf-access.mjs.map +1 -0
  47. package/dist/client/index.d.mts +398 -0
  48. package/dist/client/index.d.mts.map +1 -0
  49. package/dist/client/index.mjs +346 -0
  50. package/dist/client/index.mjs.map +1 -0
  51. package/dist/config-CKE8p9xM.mjs +55 -0
  52. package/dist/config-CKE8p9xM.mjs.map +1 -0
  53. package/dist/connection-B4zVnQIa.mjs +40 -0
  54. package/dist/connection-B4zVnQIa.mjs.map +1 -0
  55. package/dist/content-D6C2WsZC.mjs +824 -0
  56. package/dist/content-D6C2WsZC.mjs.map +1 -0
  57. package/dist/db/index.d.mts +4 -0
  58. package/dist/db/index.mjs +62 -0
  59. package/dist/db/index.mjs.map +1 -0
  60. package/dist/db/libsql.d.mts +11 -0
  61. package/dist/db/libsql.d.mts.map +1 -0
  62. package/dist/db/libsql.mjs +17 -0
  63. package/dist/db/libsql.mjs.map +1 -0
  64. package/dist/db/postgres.d.mts +11 -0
  65. package/dist/db/postgres.d.mts.map +1 -0
  66. package/dist/db/postgres.mjs +30 -0
  67. package/dist/db/postgres.mjs.map +1 -0
  68. package/dist/db/sqlite.d.mts +11 -0
  69. package/dist/db/sqlite.d.mts.map +1 -0
  70. package/dist/db/sqlite.mjs +16 -0
  71. package/dist/db/sqlite.mjs.map +1 -0
  72. package/dist/default-Cyi4aAxu.mjs +81 -0
  73. package/dist/default-Cyi4aAxu.mjs.map +1 -0
  74. package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
  75. package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
  76. package/dist/error-Cxz0tQeO.mjs +27 -0
  77. package/dist/error-Cxz0tQeO.mjs.map +1 -0
  78. package/dist/index-C1xF3OGh.d.mts +4527 -0
  79. package/dist/index-C1xF3OGh.d.mts.map +1 -0
  80. package/dist/index.d.mts +16 -0
  81. package/dist/index.mjs +30 -0
  82. package/dist/load-yOOlckBj.mjs +28 -0
  83. package/dist/load-yOOlckBj.mjs.map +1 -0
  84. package/dist/loader-fz8Q_3EO.mjs +447 -0
  85. package/dist/loader-fz8Q_3EO.mjs.map +1 -0
  86. package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
  87. package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
  88. package/dist/media/index.d.mts +26 -0
  89. package/dist/media/index.d.mts.map +1 -0
  90. package/dist/media/index.mjs +55 -0
  91. package/dist/media/index.mjs.map +1 -0
  92. package/dist/media/local-runtime.d.mts +39 -0
  93. package/dist/media/local-runtime.d.mts.map +1 -0
  94. package/dist/media/local-runtime.mjs +133 -0
  95. package/dist/media/local-runtime.mjs.map +1 -0
  96. package/dist/media-DqHVh136.mjs +200 -0
  97. package/dist/media-DqHVh136.mjs.map +1 -0
  98. package/dist/mode-C2EzN1uE.mjs +23 -0
  99. package/dist/mode-C2EzN1uE.mjs.map +1 -0
  100. package/dist/page/index.d.mts +140 -0
  101. package/dist/page/index.d.mts.map +1 -0
  102. package/dist/page/index.mjs +416 -0
  103. package/dist/page/index.mjs.map +1 -0
  104. package/dist/placeholder-CmGAmqeO.d.mts +276 -0
  105. package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
  106. package/dist/placeholder-SmpOx-_v.mjs +243 -0
  107. package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
  108. package/dist/plugin-utils.d.mts +58 -0
  109. package/dist/plugin-utils.d.mts.map +1 -0
  110. package/dist/plugin-utils.mjs +78 -0
  111. package/dist/plugin-utils.mjs.map +1 -0
  112. package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
  113. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
  114. package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
  115. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
  116. package/dist/query-CS_iSj34.mjs +460 -0
  117. package/dist/query-CS_iSj34.mjs.map +1 -0
  118. package/dist/redirect-DIfIni3r.mjs +329 -0
  119. package/dist/redirect-DIfIni3r.mjs.map +1 -0
  120. package/dist/registry-D_w5HW4G.mjs +863 -0
  121. package/dist/registry-D_w5HW4G.mjs.map +1 -0
  122. package/dist/request-context.d.mts +49 -0
  123. package/dist/request-context.d.mts.map +1 -0
  124. package/dist/request-context.mjs +43 -0
  125. package/dist/request-context.mjs.map +1 -0
  126. package/dist/runner-C0hCbYnD.mjs +1412 -0
  127. package/dist/runner-C0hCbYnD.mjs.map +1 -0
  128. package/dist/runner-EAtf0ZIe.d.mts +27 -0
  129. package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
  130. package/dist/runtime.d.mts +26 -0
  131. package/dist/runtime.d.mts.map +1 -0
  132. package/dist/runtime.mjs +42 -0
  133. package/dist/runtime.mjs.map +1 -0
  134. package/dist/search-DG603UrT.mjs +9211 -0
  135. package/dist/search-DG603UrT.mjs.map +1 -0
  136. package/dist/seed/index.d.mts +3 -0
  137. package/dist/seed/index.mjs +15 -0
  138. package/dist/seo/index.d.mts +70 -0
  139. package/dist/seo/index.d.mts.map +1 -0
  140. package/dist/seo/index.mjs +70 -0
  141. package/dist/seo/index.mjs.map +1 -0
  142. package/dist/storage/local.d.mts +39 -0
  143. package/dist/storage/local.d.mts.map +1 -0
  144. package/dist/storage/local.mjs +166 -0
  145. package/dist/storage/local.mjs.map +1 -0
  146. package/dist/storage/s3.d.mts +32 -0
  147. package/dist/storage/s3.d.mts.map +1 -0
  148. package/dist/storage/s3.mjs +175 -0
  149. package/dist/storage/s3.mjs.map +1 -0
  150. package/dist/tokens-DpgrkrXK.mjs +171 -0
  151. package/dist/tokens-DpgrkrXK.mjs.map +1 -0
  152. package/dist/transport-BFGblqwG.d.mts +42 -0
  153. package/dist/transport-BFGblqwG.d.mts.map +1 -0
  154. package/dist/transport-yxiQsi8I.mjs +418 -0
  155. package/dist/transport-yxiQsi8I.mjs.map +1 -0
  156. package/dist/types-BRuPJGdV.d.mts +102 -0
  157. package/dist/types-BRuPJGdV.d.mts.map +1 -0
  158. package/dist/types-C4-fAxN3.d.mts +182 -0
  159. package/dist/types-C4-fAxN3.d.mts.map +1 -0
  160. package/dist/types-CMMN0pNg.mjs +31 -0
  161. package/dist/types-CMMN0pNg.mjs.map +1 -0
  162. package/dist/types-CUBbjgmP.mjs +16 -0
  163. package/dist/types-CUBbjgmP.mjs.map +1 -0
  164. package/dist/types-DRjfYOEv.d.mts +426 -0
  165. package/dist/types-DRjfYOEv.d.mts.map +1 -0
  166. package/dist/types-DY5zk5HN.mjs +73 -0
  167. package/dist/types-DY5zk5HN.mjs.map +1 -0
  168. package/dist/types-DaNLHo_T.d.mts +184 -0
  169. package/dist/types-DaNLHo_T.d.mts.map +1 -0
  170. package/dist/types-DvhsUmSJ.d.mts +1111 -0
  171. package/dist/types-DvhsUmSJ.d.mts.map +1 -0
  172. package/dist/validate-CpBtVMsD.d.mts +378 -0
  173. package/dist/validate-CpBtVMsD.d.mts.map +1 -0
  174. package/dist/validate-CqRJb_xU.mjs +97 -0
  175. package/dist/validate-CqRJb_xU.mjs.map +1 -0
  176. package/dist/validate-O7PWmlnq.mjs +328 -0
  177. package/dist/validate-O7PWmlnq.mjs.map +1 -0
  178. package/locals.d.ts +46 -0
  179. package/package.json +233 -19
  180. package/src/api/authorize.ts +63 -0
  181. package/src/api/csrf.ts +48 -0
  182. package/src/api/error.ts +99 -0
  183. package/src/api/errors.ts +445 -0
  184. package/src/api/escape.ts +9 -0
  185. package/src/api/handlers/api-tokens.ts +240 -0
  186. package/src/api/handlers/comments.ts +314 -0
  187. package/src/api/handlers/content.ts +1315 -0
  188. package/src/api/handlers/dashboard.ts +205 -0
  189. package/src/api/handlers/device-flow.ts +684 -0
  190. package/src/api/handlers/index.ts +163 -0
  191. package/src/api/handlers/manifest.ts +158 -0
  192. package/src/api/handlers/marketplace.ts +930 -0
  193. package/src/api/handlers/media.ts +207 -0
  194. package/src/api/handlers/menus.ts +493 -0
  195. package/src/api/handlers/oauth-authorization.ts +429 -0
  196. package/src/api/handlers/oauth-clients.ts +349 -0
  197. package/src/api/handlers/oauth-user-lookup.ts +39 -0
  198. package/src/api/handlers/plugins.ts +254 -0
  199. package/src/api/handlers/redirects.ts +360 -0
  200. package/src/api/handlers/revision.ts +145 -0
  201. package/src/api/handlers/schema.ts +534 -0
  202. package/src/api/handlers/sections.ts +289 -0
  203. package/src/api/handlers/seo.ts +115 -0
  204. package/src/api/handlers/settings.ts +49 -0
  205. package/src/api/handlers/snapshot.ts +350 -0
  206. package/src/api/handlers/taxonomies.ts +523 -0
  207. package/src/api/index.ts +6 -0
  208. package/src/api/openapi/document.ts +2368 -0
  209. package/src/api/openapi/index.ts +1 -0
  210. package/src/api/parse.ts +139 -0
  211. package/src/api/redirect.ts +14 -0
  212. package/src/api/rev.ts +67 -0
  213. package/src/api/schemas/auth.ts +112 -0
  214. package/src/api/schemas/bylines.ts +85 -0
  215. package/src/api/schemas/comments.ts +117 -0
  216. package/src/api/schemas/common.ts +89 -0
  217. package/src/api/schemas/content.ts +191 -0
  218. package/src/api/schemas/import.ts +52 -0
  219. package/src/api/schemas/index.ts +17 -0
  220. package/src/api/schemas/media.ts +116 -0
  221. package/src/api/schemas/menus.ts +111 -0
  222. package/src/api/schemas/redirects.ts +155 -0
  223. package/src/api/schemas/schema.ts +203 -0
  224. package/src/api/schemas/search.ts +63 -0
  225. package/src/api/schemas/sections.ts +67 -0
  226. package/src/api/schemas/settings.ts +63 -0
  227. package/src/api/schemas/setup.ts +37 -0
  228. package/src/api/schemas/taxonomies.ts +113 -0
  229. package/src/api/schemas/users.ts +96 -0
  230. package/src/api/schemas/widgets.ts +80 -0
  231. package/src/api/site-url.ts +25 -0
  232. package/src/api/types.ts +82 -0
  233. package/src/astro/index.ts +27 -0
  234. package/src/astro/integration/index.ts +303 -0
  235. package/src/astro/integration/routes.ts +834 -0
  236. package/src/astro/integration/runtime.ts +338 -0
  237. package/src/astro/integration/virtual-modules.ts +469 -0
  238. package/src/astro/integration/vite-config.ts +335 -0
  239. package/src/astro/middleware/auth.ts +743 -0
  240. package/src/astro/middleware/redirect.ts +89 -0
  241. package/src/astro/middleware/request-context.ts +129 -0
  242. package/src/astro/middleware/setup.ts +89 -0
  243. package/src/astro/middleware.ts +398 -0
  244. package/src/astro/routes/PluginRegistry.tsx +15 -0
  245. package/src/astro/routes/admin.astro +81 -0
  246. package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
  247. package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
  248. package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
  249. package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
  250. package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
  251. package/src/astro/routes/api/admin/bylines/index.ts +72 -0
  252. package/src/astro/routes/api/admin/comments/[id]/status.ts +116 -0
  253. package/src/astro/routes/api/admin/comments/[id].ts +64 -0
  254. package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
  255. package/src/astro/routes/api/admin/comments/counts.ts +30 -0
  256. package/src/astro/routes/api/admin/comments/index.ts +46 -0
  257. package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
  258. package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
  259. package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
  260. package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
  261. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
  262. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
  263. package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
  264. package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
  265. package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
  266. package/src/astro/routes/api/admin/plugins/index.ts +32 -0
  267. package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
  268. package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
  269. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
  270. package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
  271. package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
  272. package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
  273. package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
  274. package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
  275. package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
  276. package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
  277. package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
  278. package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
  279. package/src/astro/routes/api/admin/users/index.ts +66 -0
  280. package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
  281. package/src/astro/routes/api/auth/invite/accept.ts +52 -0
  282. package/src/astro/routes/api/auth/invite/complete.ts +84 -0
  283. package/src/astro/routes/api/auth/invite/index.ts +99 -0
  284. package/src/astro/routes/api/auth/logout.ts +40 -0
  285. package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
  286. package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
  287. package/src/astro/routes/api/auth/me.ts +60 -0
  288. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
  289. package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
  290. package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
  291. package/src/astro/routes/api/auth/passkey/index.ts +54 -0
  292. package/src/astro/routes/api/auth/passkey/options.ts +82 -0
  293. package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
  294. package/src/astro/routes/api/auth/passkey/register/verify.ts +115 -0
  295. package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
  296. package/src/astro/routes/api/auth/signup/complete.ts +85 -0
  297. package/src/astro/routes/api/auth/signup/request.ts +77 -0
  298. package/src/astro/routes/api/auth/signup/verify.ts +53 -0
  299. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
  300. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
  301. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
  302. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
  303. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
  304. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
  305. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
  306. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
  307. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
  308. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +101 -0
  309. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
  310. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
  311. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
  312. package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
  313. package/src/astro/routes/api/content/[collection]/index.ts +59 -0
  314. package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
  315. package/src/astro/routes/api/dashboard.ts +32 -0
  316. package/src/astro/routes/api/dev/emails.ts +36 -0
  317. package/src/astro/routes/api/import/probe.ts +47 -0
  318. package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
  319. package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
  320. package/src/astro/routes/api/import/wordpress/media.ts +338 -0
  321. package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
  322. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
  323. package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
  324. package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
  325. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
  326. package/src/astro/routes/api/manifest.ts +62 -0
  327. package/src/astro/routes/api/mcp.ts +124 -0
  328. package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
  329. package/src/astro/routes/api/media/[id].ts +145 -0
  330. package/src/astro/routes/api/media/file/[key].ts +79 -0
  331. package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
  332. package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
  333. package/src/astro/routes/api/media/providers/index.ts +30 -0
  334. package/src/astro/routes/api/media/upload-url.ts +137 -0
  335. package/src/astro/routes/api/media.ts +190 -0
  336. package/src/astro/routes/api/menus/[name]/items.ts +87 -0
  337. package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
  338. package/src/astro/routes/api/menus/[name].ts +65 -0
  339. package/src/astro/routes/api/menus/index.ts +47 -0
  340. package/src/astro/routes/api/oauth/authorize.ts +412 -0
  341. package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
  342. package/src/astro/routes/api/oauth/device/code.ts +51 -0
  343. package/src/astro/routes/api/oauth/device/token.ts +69 -0
  344. package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
  345. package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
  346. package/src/astro/routes/api/oauth/token.ts +184 -0
  347. package/src/astro/routes/api/openapi.json.ts +32 -0
  348. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
  349. package/src/astro/routes/api/redirects/404s/index.ts +72 -0
  350. package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
  351. package/src/astro/routes/api/redirects/[id].ts +84 -0
  352. package/src/astro/routes/api/redirects/index.ts +52 -0
  353. package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
  354. package/src/astro/routes/api/revisions/[revisionId]/restore.ts +58 -0
  355. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
  356. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
  357. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
  358. package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
  359. package/src/astro/routes/api/schema/collections/index.ts +47 -0
  360. package/src/astro/routes/api/schema/index.ts +109 -0
  361. package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
  362. package/src/astro/routes/api/schema/orphans/index.ts +26 -0
  363. package/src/astro/routes/api/search/enable.ts +64 -0
  364. package/src/astro/routes/api/search/index.ts +55 -0
  365. package/src/astro/routes/api/search/rebuild.ts +72 -0
  366. package/src/astro/routes/api/search/stats.ts +35 -0
  367. package/src/astro/routes/api/search/suggest.ts +53 -0
  368. package/src/astro/routes/api/sections/[slug].ts +84 -0
  369. package/src/astro/routes/api/sections/index.ts +52 -0
  370. package/src/astro/routes/api/settings/email.ts +150 -0
  371. package/src/astro/routes/api/settings.ts +67 -0
  372. package/src/astro/routes/api/setup/admin-verify.ts +100 -0
  373. package/src/astro/routes/api/setup/admin.ts +94 -0
  374. package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
  375. package/src/astro/routes/api/setup/dev-reset.ts +40 -0
  376. package/src/astro/routes/api/setup/index.ts +126 -0
  377. package/src/astro/routes/api/setup/status.ts +122 -0
  378. package/src/astro/routes/api/snapshot.ts +75 -0
  379. package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
  380. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
  381. package/src/astro/routes/api/taxonomies/index.ts +59 -0
  382. package/src/astro/routes/api/themes/preview.ts +77 -0
  383. package/src/astro/routes/api/typegen.ts +114 -0
  384. package/src/astro/routes/api/well-known/auth.ts +68 -0
  385. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
  386. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
  387. package/src/astro/routes/api/widget-areas/[name]/reorder.ts +68 -0
  388. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
  389. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
  390. package/src/astro/routes/api/widget-areas/[name].ts +87 -0
  391. package/src/astro/routes/api/widget-areas/index.ts +99 -0
  392. package/src/astro/routes/api/widget-components.ts +22 -0
  393. package/src/astro/routes/robots.txt.ts +77 -0
  394. package/src/astro/routes/sitemap.xml.ts +97 -0
  395. package/src/astro/storage/adapters.ts +74 -0
  396. package/src/astro/storage/index.ts +19 -0
  397. package/src/astro/storage/types.ts +60 -0
  398. package/src/astro/types.ts +346 -0
  399. package/src/auth/api-tokens.ts +25 -0
  400. package/src/auth/challenge-store.ts +80 -0
  401. package/src/auth/mode.ts +96 -0
  402. package/src/auth/oauth-state-store.ts +96 -0
  403. package/src/auth/passkey-config.ts +27 -0
  404. package/src/auth/rate-limit.ts +158 -0
  405. package/src/auth/scopes.ts +33 -0
  406. package/src/auth/types.ts +104 -0
  407. package/src/aws-sdk.d.ts +100 -0
  408. package/src/bylines/index.ts +237 -0
  409. package/src/cleanup.ts +153 -0
  410. package/src/cli/client-factory.ts +100 -0
  411. package/src/cli/commands/auth.ts +46 -0
  412. package/src/cli/commands/bundle-utils.ts +247 -0
  413. package/src/cli/commands/bundle.ts +609 -0
  414. package/src/cli/commands/content.ts +442 -0
  415. package/src/cli/commands/dev.ts +191 -0
  416. package/src/cli/commands/doctor.ts +211 -0
  417. package/src/cli/commands/export-seed.ts +630 -0
  418. package/src/cli/commands/import/wordpress.ts +1056 -0
  419. package/src/cli/commands/init.ts +192 -0
  420. package/src/cli/commands/login.ts +547 -0
  421. package/src/cli/commands/media.ts +165 -0
  422. package/src/cli/commands/menu.ts +67 -0
  423. package/src/cli/commands/plugin-init.ts +291 -0
  424. package/src/cli/commands/plugin-validate.ts +31 -0
  425. package/src/cli/commands/plugin.ts +33 -0
  426. package/src/cli/commands/publish.ts +697 -0
  427. package/src/cli/commands/schema.ts +233 -0
  428. package/src/cli/commands/search-cmd.ts +54 -0
  429. package/src/cli/commands/seed.ts +286 -0
  430. package/src/cli/commands/taxonomy.ts +128 -0
  431. package/src/cli/commands/types.ts +68 -0
  432. package/src/cli/credentials.ts +236 -0
  433. package/src/cli/index.ts +70 -0
  434. package/src/cli/output.ts +75 -0
  435. package/src/cli/wxr/parser.ts +969 -0
  436. package/src/client/cf-access.ts +193 -0
  437. package/src/client/index.ts +854 -0
  438. package/src/client/portable-text.ts +413 -0
  439. package/src/client/transport.ts +200 -0
  440. package/src/comments/moderator.ts +46 -0
  441. package/src/comments/notifications.ts +144 -0
  442. package/src/comments/query.ts +105 -0
  443. package/src/comments/service.ts +213 -0
  444. package/src/components/Break.astro +45 -0
  445. package/src/components/Button.astro +71 -0
  446. package/src/components/Buttons.astro +49 -0
  447. package/src/components/Code.astro +59 -0
  448. package/src/components/Columns.astro +59 -0
  449. package/src/components/CommentForm.astro +315 -0
  450. package/src/components/Comments.astro +232 -0
  451. package/src/components/Cover.astro +128 -0
  452. package/src/components/EmDashBodyEnd.astro +32 -0
  453. package/src/components/EmDashBodyStart.astro +32 -0
  454. package/src/components/EmDashHead.astro +53 -0
  455. package/src/components/EmDashImage.astro +178 -0
  456. package/src/components/EmDashMedia.astro +167 -0
  457. package/src/components/Embed.astro +128 -0
  458. package/src/components/File.astro +122 -0
  459. package/src/components/Gallery.astro +93 -0
  460. package/src/components/HtmlBlock.astro +33 -0
  461. package/src/components/Image.astro +178 -0
  462. package/src/components/InlineEditor.astro +27 -0
  463. package/src/components/InlinePortableTextEditor.tsx +1905 -0
  464. package/src/components/LiveSearch.astro +614 -0
  465. package/src/components/PortableText.astro +51 -0
  466. package/src/components/Pullquote.astro +51 -0
  467. package/src/components/Table.astro +108 -0
  468. package/src/components/WidgetArea.astro +22 -0
  469. package/src/components/WidgetRenderer.astro +72 -0
  470. package/src/components/index.ts +116 -0
  471. package/src/components/marks/Link.astro +31 -0
  472. package/src/components/marks/StrikeThrough.astro +7 -0
  473. package/src/components/marks/Subscript.astro +7 -0
  474. package/src/components/marks/Superscript.astro +7 -0
  475. package/src/components/marks/Underline.astro +7 -0
  476. package/src/components/widgets/Archives.astro +65 -0
  477. package/src/components/widgets/Categories.astro +35 -0
  478. package/src/components/widgets/RecentPosts.astro +51 -0
  479. package/src/components/widgets/Search.astro +18 -0
  480. package/src/components/widgets/Tags.astro +38 -0
  481. package/src/content/converters/index.ts +9 -0
  482. package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
  483. package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
  484. package/src/content/converters/types.ts +120 -0
  485. package/src/content/index.ts +5 -0
  486. package/src/database/connection.ts +67 -0
  487. package/src/database/dialect-helpers.ts +138 -0
  488. package/src/database/index.ts +5 -0
  489. package/src/database/migrations/001_initial.ts +170 -0
  490. package/src/database/migrations/002_media_status.ts +26 -0
  491. package/src/database/migrations/003_schema_registry.ts +79 -0
  492. package/src/database/migrations/004_plugins.ts +62 -0
  493. package/src/database/migrations/005_menus.ts +67 -0
  494. package/src/database/migrations/006_taxonomy_defs.ts +51 -0
  495. package/src/database/migrations/007_widgets.ts +42 -0
  496. package/src/database/migrations/008_auth.ts +194 -0
  497. package/src/database/migrations/009_user_disabled.ts +27 -0
  498. package/src/database/migrations/011_sections.ts +65 -0
  499. package/src/database/migrations/012_search.ts +25 -0
  500. package/src/database/migrations/013_scheduled_publishing.ts +51 -0
  501. package/src/database/migrations/014_draft_revisions.ts +72 -0
  502. package/src/database/migrations/015_indexes.ts +82 -0
  503. package/src/database/migrations/016_api_tokens.ts +89 -0
  504. package/src/database/migrations/017_authorization_codes.ts +45 -0
  505. package/src/database/migrations/018_seo.ts +56 -0
  506. package/src/database/migrations/019_i18n.ts +618 -0
  507. package/src/database/migrations/020_collection_url_pattern.ts +23 -0
  508. package/src/database/migrations/021_remove_section_categories.ts +43 -0
  509. package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
  510. package/src/database/migrations/023_plugin_metadata.ts +33 -0
  511. package/src/database/migrations/024_media_placeholders.ts +32 -0
  512. package/src/database/migrations/025_oauth_clients.ts +28 -0
  513. package/src/database/migrations/026_cron_tasks.ts +49 -0
  514. package/src/database/migrations/027_comments.ts +87 -0
  515. package/src/database/migrations/028_drop_author_url.ts +9 -0
  516. package/src/database/migrations/029_redirects.ts +67 -0
  517. package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
  518. package/src/database/migrations/031_bylines.ts +90 -0
  519. package/src/database/migrations/032_rate_limits.ts +39 -0
  520. package/src/database/migrations/runner.ts +170 -0
  521. package/src/database/repositories/audit.ts +294 -0
  522. package/src/database/repositories/byline.ts +387 -0
  523. package/src/database/repositories/comment.ts +458 -0
  524. package/src/database/repositories/content.ts +1144 -0
  525. package/src/database/repositories/index.ts +30 -0
  526. package/src/database/repositories/media.ts +347 -0
  527. package/src/database/repositories/options.ts +150 -0
  528. package/src/database/repositories/plugin-storage.ts +373 -0
  529. package/src/database/repositories/redirect.ts +480 -0
  530. package/src/database/repositories/revision.ts +200 -0
  531. package/src/database/repositories/seo.ts +176 -0
  532. package/src/database/repositories/taxonomy.ts +294 -0
  533. package/src/database/repositories/types.ts +132 -0
  534. package/src/database/repositories/user.ts +258 -0
  535. package/src/database/transaction.ts +54 -0
  536. package/src/database/types.ts +501 -0
  537. package/src/database/validate.ts +138 -0
  538. package/src/db/adapters.ts +125 -0
  539. package/src/db/index.ts +37 -0
  540. package/src/db/libsql.ts +23 -0
  541. package/src/db/postgres.ts +30 -0
  542. package/src/db/sqlite.ts +27 -0
  543. package/src/emdash-runtime.ts +2096 -0
  544. package/src/fields/boolean.ts +34 -0
  545. package/src/fields/datetime.ts +44 -0
  546. package/src/fields/file.ts +41 -0
  547. package/src/fields/image.ts +34 -0
  548. package/src/fields/index.ts +42 -0
  549. package/src/fields/integer.ts +50 -0
  550. package/src/fields/json.ts +37 -0
  551. package/src/fields/multiselect.ts +48 -0
  552. package/src/fields/number.ts +52 -0
  553. package/src/fields/portable-text.ts +33 -0
  554. package/src/fields/reference.ts +29 -0
  555. package/src/fields/richtext.ts +31 -0
  556. package/src/fields/select.ts +46 -0
  557. package/src/fields/slug.ts +38 -0
  558. package/src/fields/text.ts +55 -0
  559. package/src/fields/textarea.ts +52 -0
  560. package/src/fields/types.ts +64 -0
  561. package/src/i18n/config.ts +68 -0
  562. package/src/import/index.ts +90 -0
  563. package/src/import/menus.ts +436 -0
  564. package/src/import/registry.ts +111 -0
  565. package/src/import/sections.ts +103 -0
  566. package/src/import/settings.ts +281 -0
  567. package/src/import/sources/wordpress-plugin.ts +641 -0
  568. package/src/import/sources/wordpress-rest.ts +191 -0
  569. package/src/import/sources/wxr.ts +330 -0
  570. package/src/import/ssrf.ts +260 -0
  571. package/src/import/types.ts +418 -0
  572. package/src/import/utils.ts +412 -0
  573. package/src/index.ts +481 -0
  574. package/src/loader.ts +770 -0
  575. package/src/mcp/server.ts +1463 -0
  576. package/src/media/index.ts +32 -0
  577. package/src/media/local-runtime.ts +213 -0
  578. package/src/media/local.ts +46 -0
  579. package/src/media/normalize.ts +190 -0
  580. package/src/media/placeholder.ts +150 -0
  581. package/src/media/provider-loader.ts +78 -0
  582. package/src/media/types.ts +279 -0
  583. package/src/menus/index.ts +324 -0
  584. package/src/menus/types.ts +112 -0
  585. package/src/page/context.ts +93 -0
  586. package/src/page/fragments.ts +89 -0
  587. package/src/page/index.ts +58 -0
  588. package/src/page/jsonld.ts +94 -0
  589. package/src/page/metadata.ts +185 -0
  590. package/src/page/seo-contributions.ts +136 -0
  591. package/src/plugin-utils.ts +80 -0
  592. package/src/plugins/adapt-sandbox-entry.ts +207 -0
  593. package/src/plugins/context.ts +833 -0
  594. package/src/plugins/cron.ts +361 -0
  595. package/src/plugins/define-plugin.ts +259 -0
  596. package/src/plugins/email-console.ts +73 -0
  597. package/src/plugins/email.ts +209 -0
  598. package/src/plugins/hooks.ts +1273 -0
  599. package/src/plugins/index.ts +193 -0
  600. package/src/plugins/manager.ts +595 -0
  601. package/src/plugins/manifest-schema.ts +230 -0
  602. package/src/plugins/marketplace.ts +460 -0
  603. package/src/plugins/request-meta.ts +139 -0
  604. package/src/plugins/routes.ts +302 -0
  605. package/src/plugins/sandbox/index.ts +18 -0
  606. package/src/plugins/sandbox/noop.ts +76 -0
  607. package/src/plugins/sandbox/types.ts +173 -0
  608. package/src/plugins/scheduler/node.ts +122 -0
  609. package/src/plugins/scheduler/piggyback.ts +71 -0
  610. package/src/plugins/scheduler/types.ts +27 -0
  611. package/src/plugins/state.ts +208 -0
  612. package/src/plugins/storage-indexes.ts +326 -0
  613. package/src/plugins/storage-query.ts +240 -0
  614. package/src/plugins/types.ts +1284 -0
  615. package/src/preview/helpers.ts +27 -0
  616. package/src/preview/index.ts +40 -0
  617. package/src/preview/tokens.ts +279 -0
  618. package/src/preview/urls.ts +118 -0
  619. package/src/query.ts +674 -0
  620. package/src/redirects/patterns.ts +224 -0
  621. package/src/request-context.ts +67 -0
  622. package/src/runtime.ts +21 -0
  623. package/src/schema/index.ts +29 -0
  624. package/src/schema/query.ts +44 -0
  625. package/src/schema/registry.ts +965 -0
  626. package/src/schema/types.ts +276 -0
  627. package/src/schema/zod-generator.ts +413 -0
  628. package/src/search/fts-manager.ts +452 -0
  629. package/src/search/index.ts +26 -0
  630. package/src/search/query.ts +396 -0
  631. package/src/search/text-extraction.ts +162 -0
  632. package/src/search/types.ts +114 -0
  633. package/src/sections/index.ts +226 -0
  634. package/src/sections/types.ts +86 -0
  635. package/src/seed/apply.ts +1141 -0
  636. package/src/seed/default.ts +86 -0
  637. package/src/seed/index.ts +28 -0
  638. package/src/seed/load.ts +35 -0
  639. package/src/seed/types.ts +341 -0
  640. package/src/seed/validate.ts +642 -0
  641. package/src/seo/index.ts +179 -0
  642. package/src/settings/index.ts +203 -0
  643. package/src/settings/types.ts +58 -0
  644. package/src/storage/index.ts +28 -0
  645. package/src/storage/local.ts +249 -0
  646. package/src/storage/s3.ts +263 -0
  647. package/src/storage/types.ts +204 -0
  648. package/src/taxonomies/index.ts +309 -0
  649. package/src/taxonomies/types.ts +61 -0
  650. package/src/ui.ts +75 -0
  651. package/src/utils/base64.ts +73 -0
  652. package/src/utils/hash.ts +36 -0
  653. package/src/utils/sanitize.ts +20 -0
  654. package/src/utils/slugify.ts +29 -0
  655. package/src/utils/url.ts +48 -0
  656. package/src/virtual-modules.d.ts +111 -0
  657. package/src/visual-editing/editable.ts +108 -0
  658. package/src/visual-editing/toolbar.ts +1229 -0
  659. package/src/widgets/components.ts +105 -0
  660. package/src/widgets/index.ts +131 -0
  661. package/src/widgets/types.ts +81 -0
@@ -0,0 +1,36 @@
1
+ /**
2
+ * GET /_emdash/api/dev/emails
3
+ * DELETE /_emdash/api/dev/emails
4
+ *
5
+ * Development-only endpoint to view and clear emails captured by
6
+ * the dev console email provider.
7
+ *
8
+ * ONLY available when import.meta.env.DEV is true.
9
+ *
10
+ */
11
+
12
+ import type { APIRoute } from "astro";
13
+
14
+ export const prerender = false;
15
+
16
+ import { apiError, apiSuccess } from "#api/error.js";
17
+
18
+ import { clearDevEmails, getDevEmails } from "../../../../plugins/email-console.js";
19
+
20
+ export const GET: APIRoute = async () => {
21
+ if (!import.meta.env.DEV) {
22
+ return apiError("FORBIDDEN", "Dev emails endpoint is only available in development mode", 403);
23
+ }
24
+
25
+ const emails = getDevEmails();
26
+ return apiSuccess({ items: emails });
27
+ };
28
+
29
+ export const DELETE: APIRoute = async () => {
30
+ if (!import.meta.env.DEV) {
31
+ return apiError("FORBIDDEN", "Dev emails endpoint is only available in development mode", 403);
32
+ }
33
+
34
+ clearDevEmails();
35
+ return apiSuccess({ success: true });
36
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * URL probe endpoint
3
+ *
4
+ * POST /_emdash/api/import/probe
5
+ *
6
+ * Probes a URL to detect what import source can handle it.
7
+ */
8
+
9
+ import type { APIRoute } from "astro";
10
+
11
+ import { requirePerm } from "#api/authorize.js";
12
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
13
+ import { isParseError, parseBody } from "#api/parse.js";
14
+ import { importProbeBody } from "#api/schemas.js";
15
+ import { probeUrl, type ProbeResult } from "#import/index.js";
16
+ import { SsrfError } from "#import/ssrf.js";
17
+
18
+ export const prerender = false;
19
+
20
+ export interface ProbeResponse {
21
+ success: boolean;
22
+ result?: ProbeResult;
23
+ error?: { message: string };
24
+ }
25
+
26
+ export const POST: APIRoute = async ({ request, locals }) => {
27
+ const { user } = locals;
28
+ const denied = requirePerm(user, "import:execute");
29
+ if (denied) return denied;
30
+
31
+ try {
32
+ const body = await parseBody(request, importProbeBody);
33
+ if (isParseError(body)) return body;
34
+
35
+ const result = await probeUrl(body.url);
36
+
37
+ return apiSuccess({
38
+ success: true,
39
+ result,
40
+ });
41
+ } catch (error) {
42
+ if (error instanceof SsrfError) {
43
+ return apiError("SSRF_BLOCKED", error.message, 400);
44
+ }
45
+ return handleError(error, "Failed to probe URL", "PROBE_ERROR");
46
+ }
47
+ };
@@ -0,0 +1,510 @@
1
+ /**
2
+ * WordPress WXR analyze endpoint
3
+ *
4
+ * POST /_emdash/api/import/wordpress/analyze
5
+ *
6
+ * Accepts a WXR file upload and returns analysis of its contents,
7
+ * including post types, counts, custom fields, and schema compatibility.
8
+ */
9
+
10
+ import type { APIRoute } from "astro";
11
+ import { parseWxrString, SchemaRegistry, type WxrData } from "emdash";
12
+ import mime from "mime/lite";
13
+
14
+ import { requirePerm } from "#api/authorize.js";
15
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
16
+ import type { EmDashHandlers } from "#types";
17
+
18
+ export const prerender = false;
19
+
20
+ const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
21
+
22
+ /** Field compatibility status */
23
+ export type FieldCompatibility =
24
+ | "compatible" // Field exists with compatible type
25
+ | "type_mismatch" // Field exists but type differs
26
+ | "missing"; // Field doesn't exist
27
+
28
+ /** Single field definition for import */
29
+ export interface ImportFieldDef {
30
+ slug: string;
31
+ label: string;
32
+ type: string;
33
+ required: boolean;
34
+ searchable?: boolean;
35
+ }
36
+
37
+ /** Schema status for a collection */
38
+ export interface CollectionSchemaStatus {
39
+ /** Whether collection exists */
40
+ exists: boolean;
41
+ /** If exists, per-field compatibility */
42
+ fieldStatus: Record<
43
+ string,
44
+ {
45
+ status: FieldCompatibility;
46
+ existingType?: string;
47
+ requiredType: string;
48
+ }
49
+ >;
50
+ /** Can we safely import to this collection? */
51
+ canImport: boolean;
52
+ /** Human-readable reason if canImport is false */
53
+ reason?: string;
54
+ }
55
+
56
+ /** Post type with full schema info */
57
+ export interface PostTypeAnalysis {
58
+ /** WordPress post type name */
59
+ name: string;
60
+ /** Number of items to import */
61
+ count: number;
62
+ /** Suggested collection slug */
63
+ suggestedCollection: string;
64
+ /** Fields we need to create */
65
+ requiredFields: ImportFieldDef[];
66
+ /** Schema compatibility status */
67
+ schemaStatus: CollectionSchemaStatus;
68
+ }
69
+
70
+ /** Individual attachment info for media import */
71
+ export interface AttachmentInfo {
72
+ id?: number;
73
+ title?: string;
74
+ url?: string;
75
+ filename?: string;
76
+ mimeType?: string;
77
+ }
78
+
79
+ /** Author info from WordPress */
80
+ export interface WpAuthorInfo {
81
+ id?: number;
82
+ login?: string;
83
+ email?: string;
84
+ displayName?: string;
85
+ postCount: number;
86
+ }
87
+
88
+ export interface WxrAnalysis {
89
+ site: {
90
+ title: string;
91
+ url: string;
92
+ };
93
+ postTypes: PostTypeAnalysis[];
94
+ attachments: {
95
+ count: number;
96
+ items: AttachmentInfo[];
97
+ };
98
+ categories: number;
99
+ tags: number;
100
+ authors: WpAuthorInfo[];
101
+ customFields: Array<{
102
+ key: string;
103
+ count: number;
104
+ samples: string[];
105
+ suggestedField: string;
106
+ suggestedType: "string" | "number" | "boolean" | "date" | "json";
107
+ isInternal: boolean;
108
+ }>;
109
+ }
110
+
111
+ export const POST: APIRoute = async ({ request, locals }) => {
112
+ const { emdash, user } = locals;
113
+
114
+ const denied = requirePerm(user, "import:execute");
115
+ if (denied) return denied;
116
+
117
+ try {
118
+ const formData = await request.formData();
119
+ const fileEntry = formData.get("file");
120
+ const file = fileEntry instanceof File ? fileEntry : null;
121
+
122
+ if (!file) {
123
+ return apiError("VALIDATION_ERROR", "No file provided", 400);
124
+ }
125
+
126
+ // Parse WXR
127
+ const text = await file.text();
128
+ const wxr = await parseWxrString(text);
129
+
130
+ // Fetch existing collections from schema registry
131
+ const existingCollections = await fetchExistingCollections(emdash?.db);
132
+
133
+ // Analyze content with schema compatibility
134
+ const analysis = analyzeWxr(wxr, existingCollections);
135
+
136
+ return apiSuccess(analysis);
137
+ } catch (error) {
138
+ return handleError(error, "Failed to analyze file", "WXR_ANALYZE_ERROR");
139
+ }
140
+ };
141
+
142
+ /** Existing collection info from schema registry */
143
+ interface ExistingCollection {
144
+ slug: string;
145
+ fields: Map<string, { type: string; columnType: string }>;
146
+ }
147
+
148
+ /** Fetch collections and their fields from schema registry */
149
+ async function fetchExistingCollections(
150
+ db: EmDashHandlers["db"] | undefined,
151
+ ): Promise<Map<string, ExistingCollection>> {
152
+ const result = new Map<string, ExistingCollection>();
153
+
154
+ if (!db) return result;
155
+
156
+ try {
157
+ const registry = new SchemaRegistry(db);
158
+
159
+ const collections = await registry.listCollections();
160
+
161
+ for (const collection of collections) {
162
+ const fields = await registry.listFields(collection.id);
163
+ const fieldMap = new Map<string, { type: string; columnType: string }>();
164
+
165
+ for (const field of fields) {
166
+ fieldMap.set(field.slug, {
167
+ type: field.type,
168
+ columnType: field.columnType,
169
+ });
170
+ }
171
+
172
+ result.set(collection.slug, {
173
+ slug: collection.slug,
174
+ fields: fieldMap,
175
+ });
176
+ }
177
+ } catch (error) {
178
+ console.warn("Could not fetch schema registry:", error);
179
+ }
180
+
181
+ return result;
182
+ }
183
+
184
+ /** Base fields required for any WordPress import */
185
+ const BASE_REQUIRED_FIELDS: ImportFieldDef[] = [
186
+ { slug: "title", label: "Title", type: "string", required: true, searchable: true },
187
+ { slug: "content", label: "Content", type: "portableText", required: false, searchable: true },
188
+ { slug: "excerpt", label: "Excerpt", type: "text", required: false },
189
+ ];
190
+
191
+ /** Featured image field - only added to post types that have _thumbnail_id */
192
+ const FEATURED_IMAGE_FIELD: ImportFieldDef = {
193
+ slug: "featured_image",
194
+ label: "Featured Image",
195
+ type: "image",
196
+ required: false,
197
+ };
198
+
199
+ function analyzeWxr(
200
+ wxr: WxrData,
201
+ existingCollections: Map<string, ExistingCollection>,
202
+ ): WxrAnalysis {
203
+ // Count post types and track which have featured images
204
+ const postTypeCounts = new Map<string, number>();
205
+ const postTypesWithThumbnails = new Set<string>();
206
+ const metaKeys = new Map<string, { count: number; samples: string[]; isInternal: boolean }>();
207
+ const authorPostCounts = new Map<string, number>();
208
+
209
+ for (const post of wxr.posts) {
210
+ const type = post.postType || "post";
211
+ postTypeCounts.set(type, (postTypeCounts.get(type) || 0) + 1);
212
+
213
+ // Count posts per author (by login)
214
+ if (post.creator) {
215
+ authorPostCounts.set(post.creator, (authorPostCounts.get(post.creator) || 0) + 1);
216
+ }
217
+
218
+ // Track if this post type has featured images
219
+ if (post.meta.has("_thumbnail_id")) {
220
+ postTypesWithThumbnails.add(type);
221
+ }
222
+
223
+ // Analyze meta keys
224
+ for (const [key, value] of post.meta) {
225
+ const existing = metaKeys.get(key);
226
+ if (existing) {
227
+ existing.count++;
228
+ if (existing.samples.length < 3 && value) {
229
+ existing.samples.push(value.slice(0, 100));
230
+ }
231
+ } else {
232
+ metaKeys.set(key, {
233
+ count: 1,
234
+ samples: value ? [value.slice(0, 100)] : [],
235
+ isInternal: isInternalMetaKey(key),
236
+ });
237
+ }
238
+ }
239
+ }
240
+
241
+ // Map meta keys to fields (for custom fields analysis)
242
+ const customFields = [...metaKeys.entries()]
243
+ .filter(([_, info]) => !info.isInternal)
244
+ .map(([key, info]) => ({
245
+ key,
246
+ count: info.count,
247
+ samples: info.samples,
248
+ suggestedField: mapMetaKeyToField(key),
249
+ suggestedType: inferMetaType(key, info.samples[0]),
250
+ isInternal: info.isInternal,
251
+ }))
252
+ .toSorted((a, b) => b.count - a.count);
253
+
254
+ // Build post type analysis with schema compatibility
255
+ const postTypes: PostTypeAnalysis[] = [...postTypeCounts.entries()]
256
+ .filter(([type]) => !isInternalPostType(type))
257
+ .map(([name, count]) => {
258
+ const suggestedCollection = mapPostTypeToCollection(name);
259
+ const existingCollection = existingCollections.get(suggestedCollection);
260
+
261
+ // Build required fields - add featured_image only if posts have thumbnails
262
+ const requiredFields = [...BASE_REQUIRED_FIELDS];
263
+ if (postTypesWithThumbnails.has(name)) {
264
+ requiredFields.push(FEATURED_IMAGE_FIELD);
265
+ }
266
+
267
+ const schemaStatus = checkSchemaCompatibility(requiredFields, existingCollection);
268
+
269
+ return {
270
+ name,
271
+ count,
272
+ suggestedCollection,
273
+ requiredFields,
274
+ schemaStatus,
275
+ };
276
+ })
277
+ .toSorted((a, b) => b.count - a.count);
278
+
279
+ // Build attachment info list
280
+ const attachmentItems: AttachmentInfo[] = wxr.attachments.map((att) => {
281
+ const filename = att.url ? getFilenameFromUrl(att.url) : undefined;
282
+ const mimeType = filename ? guessMimeType(filename) : undefined;
283
+ return {
284
+ id: att.id,
285
+ title: att.title,
286
+ url: att.url,
287
+ filename,
288
+ mimeType,
289
+ };
290
+ });
291
+
292
+ return {
293
+ site: {
294
+ title: wxr.site.title || "WordPress Site",
295
+ url: wxr.site.link || "",
296
+ },
297
+ postTypes,
298
+ attachments: {
299
+ count: wxr.attachments.length,
300
+ items: attachmentItems,
301
+ },
302
+ categories: wxr.categories.length,
303
+ tags: wxr.tags.length,
304
+ authors: wxr.authors.map((a) => ({
305
+ id: a.id,
306
+ login: a.login,
307
+ email: a.email,
308
+ displayName: a.displayName || a.login || "Unknown",
309
+ postCount: a.login ? authorPostCounts.get(a.login) || 0 : 0,
310
+ })),
311
+ customFields,
312
+ };
313
+ }
314
+
315
+ /** Extract filename from URL */
316
+ function getFilenameFromUrl(url: string): string | undefined {
317
+ try {
318
+ const parsed = new URL(url);
319
+ const segments = parsed.pathname.split("/").filter(Boolean);
320
+ return segments.pop();
321
+ } catch {
322
+ return undefined;
323
+ }
324
+ }
325
+
326
+ /** Guess MIME type from filename extension */
327
+ function guessMimeType(filename: string): string | undefined {
328
+ return mime.getType(filename) ?? undefined;
329
+ }
330
+
331
+ /** Check if a collection schema is compatible with import requirements */
332
+ function checkSchemaCompatibility(
333
+ requiredFields: ImportFieldDef[],
334
+ existingCollection: ExistingCollection | undefined,
335
+ ): CollectionSchemaStatus {
336
+ if (!existingCollection) {
337
+ // Collection doesn't exist - will need to create it
338
+ const fieldStatus: CollectionSchemaStatus["fieldStatus"] = {};
339
+ for (const field of requiredFields) {
340
+ fieldStatus[field.slug] = {
341
+ status: "missing",
342
+ requiredType: field.type,
343
+ };
344
+ }
345
+ return {
346
+ exists: false,
347
+ fieldStatus,
348
+ canImport: true, // We can create it
349
+ };
350
+ }
351
+
352
+ // Collection exists - check field compatibility
353
+ const fieldStatus: CollectionSchemaStatus["fieldStatus"] = {};
354
+ const incompatibleFields: string[] = [];
355
+
356
+ for (const field of requiredFields) {
357
+ const existingField = existingCollection.fields.get(field.slug);
358
+
359
+ if (!existingField) {
360
+ // Field missing - we can add it
361
+ fieldStatus[field.slug] = {
362
+ status: "missing",
363
+ requiredType: field.type,
364
+ };
365
+ } else if (isTypeCompatible(field.type, existingField.type)) {
366
+ // Field exists and is compatible
367
+ fieldStatus[field.slug] = {
368
+ status: "compatible",
369
+ existingType: existingField.type,
370
+ requiredType: field.type,
371
+ };
372
+ } else {
373
+ // Field exists but type doesn't match
374
+ fieldStatus[field.slug] = {
375
+ status: "type_mismatch",
376
+ existingType: existingField.type,
377
+ requiredType: field.type,
378
+ };
379
+ incompatibleFields.push(field.slug);
380
+ }
381
+ }
382
+
383
+ const canImport = incompatibleFields.length === 0;
384
+ const reason = canImport
385
+ ? undefined
386
+ : `Incompatible field types: ${incompatibleFields.join(", ")}. ` +
387
+ `Existing fields have different types than required for import.`;
388
+
389
+ return {
390
+ exists: true,
391
+ fieldStatus,
392
+ canImport,
393
+ reason,
394
+ };
395
+ }
396
+
397
+ /** Check if two field types are compatible for import */
398
+ function isTypeCompatible(requiredType: string, existingType: string): boolean {
399
+ // Exact match
400
+ if (requiredType === existingType) return true;
401
+
402
+ // Compatible mappings
403
+ const compatibleTypes: Record<string, string[]> = {
404
+ string: ["string", "text", "slug"],
405
+ text: ["string", "text"],
406
+ portableText: ["portableText", "json"],
407
+ number: ["number", "integer"],
408
+ integer: ["number", "integer"],
409
+ };
410
+
411
+ const compatible = compatibleTypes[requiredType];
412
+ return compatible?.includes(existingType) ?? false;
413
+ }
414
+
415
+ function isInternalPostType(type: string): boolean {
416
+ return [
417
+ "revision",
418
+ "nav_menu_item",
419
+ "custom_css",
420
+ "customize_changeset",
421
+ "oembed_cache",
422
+ "wp_global_styles",
423
+ "wp_navigation",
424
+ "wp_template",
425
+ "wp_template_part",
426
+ "attachment", // Handled separately as media
427
+ "wp_block", // Handled separately as sections (reusable blocks)
428
+ ].includes(type);
429
+ }
430
+
431
+ function isInternalMetaKey(key: string): boolean {
432
+ if (key.startsWith("_edit_")) return true;
433
+ if (key.startsWith("_wp_")) return true;
434
+ if (key === "_edit_last" || key === "_edit_lock") return true;
435
+ if (key === "_pingme" || key === "_encloseme") return true;
436
+
437
+ // Keep these useful ones
438
+ if (key === "_thumbnail_id") return false;
439
+ if (key.startsWith("_yoast_")) return false;
440
+ if (key.startsWith("_rank_math_")) return false;
441
+
442
+ // Other underscore prefixes are usually internal
443
+ if (key.startsWith("_")) return true;
444
+
445
+ return false;
446
+ }
447
+
448
+ function mapPostTypeToCollection(postType: string): string {
449
+ const mapping: Record<string, string> = {
450
+ post: "posts",
451
+ page: "pages",
452
+ attachment: "media",
453
+ product: "products",
454
+ portfolio: "portfolio",
455
+ testimonial: "testimonials",
456
+ team: "team",
457
+ event: "events",
458
+ faq: "faqs",
459
+ };
460
+ return mapping[postType] || postType;
461
+ }
462
+
463
+ function mapMetaKeyToField(key: string): string {
464
+ // SEO plugins
465
+ if (key === "_yoast_wpseo_title") return "seo_title";
466
+ if (key === "_yoast_wpseo_metadesc") return "seo_description";
467
+ if (key === "_rank_math_title") return "seo_title";
468
+ if (key === "_rank_math_description") return "seo_description";
469
+ if (key === "_thumbnail_id") return "featured_image";
470
+
471
+ // Remove leading underscore
472
+ if (key.startsWith("_")) return key.slice(1);
473
+
474
+ return key;
475
+ }
476
+
477
+ function inferMetaType(
478
+ key: string,
479
+ value: string | undefined,
480
+ ): "string" | "number" | "boolean" | "date" | "json" {
481
+ if (key.endsWith("_id") || key === "_thumbnail_id") return "string"; // reference
482
+ if (key.endsWith("_date") || key.endsWith("_time")) return "date";
483
+ if (key.endsWith("_count") || key.endsWith("_number")) return "number";
484
+
485
+ if (!value) return "string";
486
+
487
+ // Serialized PHP or JSON
488
+ if (value.startsWith("a:") || value.startsWith("{") || value.startsWith("[")) return "json";
489
+
490
+ // Number
491
+ if (NUMERIC_PATTERN.test(value)) return "number";
492
+
493
+ // Boolean
494
+ if (["0", "1", "true", "false"].includes(value)) return "boolean";
495
+
496
+ return "string";
497
+ }
498
+
499
+ function capitalize(str: string): string {
500
+ return str.charAt(0).toUpperCase() + str.slice(1);
501
+ }
502
+
503
+ function singularize(str: string): string {
504
+ if (str.endsWith("ies")) return str.slice(0, -3) + "y";
505
+ if (str.endsWith("s")) return str.slice(0, -1);
506
+ return str;
507
+ }
508
+
509
+ // Export helpers for use in prepare endpoint
510
+ export { capitalize, singularize, mapPostTypeToCollection };