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,58 @@
1
+ /**
2
+ * WordPress Application Password OAuth callback
3
+ *
4
+ * GET /_emdash/api/import/wordpress-plugin/callback
5
+ *
6
+ * WordPress redirects here after user approves the application password.
7
+ * We receive the credentials and redirect to the admin import UI with a token.
8
+ */
9
+
10
+ import type { APIRoute } from "astro";
11
+
12
+ import { encodeBase64 } from "#utils/base64.js";
13
+
14
+ export const prerender = false;
15
+
16
+ export const GET: APIRoute = async ({ url, cookies, redirect }) => {
17
+ // WordPress sends these params on success:
18
+ // - site_url: The WordPress site URL
19
+ // - user_login: The username
20
+ // - password: The newly created application password
21
+ //
22
+ // On rejection, it redirects to reject_url (if provided) or just doesn't include credentials
23
+
24
+ const siteUrl = url.searchParams.get("site_url");
25
+ const userLogin = url.searchParams.get("user_login");
26
+ const password = url.searchParams.get("password");
27
+
28
+ // Check if this is a rejection (no credentials)
29
+ if (!siteUrl || !userLogin || !password) {
30
+ return redirect("/_emdash/admin/import/wordpress?error=auth_rejected");
31
+ }
32
+
33
+ // Create the Basic Auth token
34
+ const token = encodeBase64(`${userLogin}:${password}`);
35
+
36
+ // Store credentials in a short-lived cookie (5 minutes)
37
+ // This allows the import UI to retrieve them
38
+ const authData = JSON.stringify({
39
+ siteUrl,
40
+ userLogin,
41
+ token,
42
+ timestamp: Date.now(),
43
+ });
44
+
45
+ // Base64 encode the auth data for cookie storage
46
+ const encodedAuth = encodeBase64(authData);
47
+
48
+ cookies.set("emdash_wp_auth", encodedAuth, {
49
+ path: "/_emdash/",
50
+ maxAge: 300, // 5 minutes
51
+ httpOnly: false, // Needs to be readable by JS
52
+ secure: url.protocol === "https:",
53
+ sameSite: "lax",
54
+ });
55
+
56
+ // Redirect to import UI - it will pick up the cookie
57
+ return redirect("/_emdash/admin/import/wordpress?auth=success");
58
+ };
@@ -0,0 +1,347 @@
1
+ /**
2
+ * WordPress Plugin execute import endpoint
3
+ *
4
+ * POST /_emdash/api/import/wordpress-plugin/execute
5
+ *
6
+ * Imports content from WordPress via EmDash Exporter plugin API.
7
+ */
8
+
9
+ import type { APIRoute } from "astro";
10
+ import { ContentRepository, SchemaRegistry } from "emdash";
11
+
12
+ import { requirePerm } from "#api/authorize.js";
13
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
14
+ import { isParseError, parseBody } from "#api/parse.js";
15
+ import { wpPluginExecuteBody } from "#api/schemas.js";
16
+ import { BylineRepository } from "#db/repositories/byline.js";
17
+ import { getSource } from "#import/index.js";
18
+ import { validateExternalUrl, SsrfError } from "#import/ssrf.js";
19
+ import type { ImportConfig, ImportResult, NormalizedItem } from "#import/types.js";
20
+ import { resolveImportByline } from "#import/utils.js";
21
+ import type { FieldType } from "#schema/types.js";
22
+ import type { EmDashHandlers, EmDashManifest } from "#types";
23
+ import { slugify } from "#utils/slugify.js";
24
+
25
+ export const prerender = false;
26
+
27
+ export interface WpPluginImportConfig extends ImportConfig {
28
+ /** Author mappings (WP author login -> EmDash user ID) */
29
+ authorMappings?: Record<string, string | null>;
30
+ }
31
+
32
+ export interface WpPluginImportResponse {
33
+ success: boolean;
34
+ result?: ImportResult;
35
+ error?: { message: string };
36
+ }
37
+
38
+ export const POST: APIRoute = async ({ request, locals }) => {
39
+ const { emdash, emdashManifest, user } = locals;
40
+
41
+ const denied = requirePerm(user, "import:execute");
42
+ if (denied) return denied;
43
+
44
+ if (!emdash?.handleContentCreate) {
45
+ return apiError("NOT_CONFIGURED", "EmDash not configured", 500);
46
+ }
47
+
48
+ try {
49
+ const body = await parseBody(request, wpPluginExecuteBody);
50
+ if (isParseError(body)) return body;
51
+
52
+ // SSRF: reject internal/private network targets
53
+ try {
54
+ validateExternalUrl(body.url);
55
+ } catch (e) {
56
+ const msg = e instanceof SsrfError ? e.message : "Invalid URL";
57
+ return apiError("SSRF_BLOCKED", msg, 400);
58
+ }
59
+
60
+ // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Zod schema output narrowed to WpPluginImportConfig
61
+ const config = body.config as unknown as WpPluginImportConfig;
62
+
63
+ // Get the WordPress plugin source
64
+ const source = getSource("wordpress-plugin");
65
+ if (!source) {
66
+ return apiError("NOT_CONFIGURED", "WordPress plugin source not available", 500);
67
+ }
68
+
69
+ // Build the list of post types to fetch
70
+ const postTypes = Object.entries(config.postTypeMappings)
71
+ .filter(([_, mapping]) => mapping.enabled)
72
+ .map(([postType]) => postType);
73
+
74
+ if (postTypes.length === 0) {
75
+ return apiError("VALIDATION_ERROR", "No post types selected for import", 400);
76
+ }
77
+
78
+ console.log("[WP Plugin Import] Starting import for:", body.url);
79
+ console.log("[WP Plugin Import] Post types:", postTypes);
80
+
81
+ // Import content (including drafts since we have auth)
82
+ const result = await importContent(
83
+ source.fetchContent(
84
+ { type: "url", url: body.url, token: body.token },
85
+ { postTypes, includeDrafts: true },
86
+ ),
87
+ config,
88
+ emdash,
89
+ emdashManifest,
90
+ );
91
+
92
+ console.log("[WP Plugin Import] Import result:", JSON.stringify(result, null, 2));
93
+
94
+ return apiSuccess({
95
+ success: true,
96
+ result,
97
+ });
98
+ } catch (error) {
99
+ return handleError(error, "Failed to import from WordPress", "WP_PLUGIN_IMPORT_ERROR");
100
+ }
101
+ };
102
+
103
+ /** Fields that should be auto-created if they don't exist */
104
+ const IMPORT_FIELDS: Array<{
105
+ slug: string;
106
+ label: string;
107
+ type: FieldType;
108
+ check: (item: NormalizedItem) => boolean;
109
+ }> = [
110
+ {
111
+ slug: "title",
112
+ label: "Title",
113
+ type: "string",
114
+ check: () => true,
115
+ },
116
+ {
117
+ slug: "content",
118
+ label: "Content",
119
+ type: "portableText",
120
+ check: () => true,
121
+ },
122
+ {
123
+ slug: "excerpt",
124
+ label: "Excerpt",
125
+ type: "text",
126
+ check: (item) => !!item.excerpt,
127
+ },
128
+ {
129
+ slug: "featured_image",
130
+ label: "Featured Image",
131
+ type: "image",
132
+ check: (item) => !!item.featuredImage,
133
+ },
134
+ ];
135
+
136
+ async function importContent(
137
+ items: AsyncGenerator<NormalizedItem>,
138
+ config: WpPluginImportConfig,
139
+ emdash: EmDashHandlers,
140
+ manifest: EmDashManifest,
141
+ ): Promise<ImportResult> {
142
+ const result: ImportResult = {
143
+ success: true,
144
+ imported: 0,
145
+ skipped: 0,
146
+ errors: [],
147
+ byCollection: {},
148
+ };
149
+
150
+ // Create content repository for checking existing items
151
+ const contentRepo = new ContentRepository(emdash.db);
152
+ const bylineRepo = new BylineRepository(emdash.db);
153
+ const bylineCache = new Map<string, string>();
154
+ const schemaRegistry = new SchemaRegistry(emdash.db);
155
+
156
+ // Track which collections have had fields ensured
157
+ const ensuredCollections = new Set<string>();
158
+
159
+ // Track source translationGroup -> EmDash item ID for translation linking.
160
+ // Maps source-side translation group ID to the EmDash ID of the first item
161
+ // imported for that group (the default-locale item).
162
+ const translationGroupMap = new Map<string, string>();
163
+
164
+ for await (const item of items) {
165
+ console.log("[WP Plugin Import] Processing item:", {
166
+ sourceId: item.sourceId,
167
+ title: item.title,
168
+ postType: item.postType,
169
+ status: item.status,
170
+ contentBlocks: Array.isArray(item.content) ? item.content.length : 0,
171
+ featuredImage: item.featuredImage,
172
+ locale: item.locale,
173
+ translationGroup: item.translationGroup,
174
+ });
175
+
176
+ const mapping = config.postTypeMappings[item.postType];
177
+
178
+ // Skip if not mapped or disabled
179
+ if (!mapping || !mapping.enabled) {
180
+ result.skipped++;
181
+ continue;
182
+ }
183
+
184
+ const collection = mapping.collection;
185
+
186
+ // Check if collection exists in manifest
187
+ if (!manifest?.collections[collection]) {
188
+ result.errors.push({
189
+ title: item.title || "Untitled",
190
+ error: `Collection "${collection}" does not exist`,
191
+ });
192
+ continue;
193
+ }
194
+
195
+ try {
196
+ // Ensure required fields exist in the collection schema (once per collection)
197
+ if (!ensuredCollections.has(collection)) {
198
+ for (const field of IMPORT_FIELDS) {
199
+ if (field.check(item)) {
200
+ const existingField = await schemaRegistry.getField(collection, field.slug);
201
+ if (!existingField) {
202
+ console.log(
203
+ `[WP Plugin Import] Creating missing field "${field.slug}" in collection "${collection}"`,
204
+ );
205
+ try {
206
+ await schemaRegistry.createField(collection, {
207
+ slug: field.slug,
208
+ label: field.label,
209
+ type: field.type,
210
+ required: false,
211
+ });
212
+ } catch (e) {
213
+ // Field might already exist from concurrent creation
214
+ console.log(
215
+ `[WP Plugin Import] Field "${field.slug}" creation skipped:`,
216
+ e instanceof Error ? e.message : e,
217
+ );
218
+ }
219
+ }
220
+ }
221
+ }
222
+ ensuredCollections.add(collection);
223
+ }
224
+
225
+ // Generate slug from item slug or title
226
+ const slug = item.slug || slugify(item.title || `post-${item.sourceId}`);
227
+
228
+ // Check if already exists (idempotency) — locale-aware lookup
229
+ if (config.skipExisting) {
230
+ const existing = await contentRepo.findBySlug(collection, slug, item.locale);
231
+ if (existing) {
232
+ // Still track the translation group mapping for later items
233
+ if (item.translationGroup) {
234
+ translationGroupMap.set(item.translationGroup, existing.id);
235
+ }
236
+ result.skipped++;
237
+ continue;
238
+ }
239
+ }
240
+
241
+ // Map WordPress status to EmDash status
242
+ const status = mapStatus(item.status);
243
+
244
+ // Build data object - add all applicable fields
245
+ const data: Record<string, unknown> = {};
246
+
247
+ // Add standard fields
248
+ data.title = item.title || "Untitled";
249
+ data.content = item.content;
250
+
251
+ if (item.excerpt) {
252
+ data.excerpt = item.excerpt;
253
+ }
254
+ if (item.featuredImage) {
255
+ data.featured_image = item.featuredImage;
256
+ console.log("[WP Plugin Import] Adding featured_image:", item.featuredImage);
257
+ }
258
+
259
+ // Note: ACF/Yoast/RankMath fields are not added automatically
260
+ // They would need matching fields in the EmDash schema
261
+
262
+ // Resolve author ID from mappings
263
+ let authorId: string | undefined;
264
+ if (config.authorMappings && item.author) {
265
+ const mappedUserId = config.authorMappings[item.author];
266
+ if (mappedUserId !== undefined && mappedUserId !== null) {
267
+ authorId = mappedUserId;
268
+ }
269
+ }
270
+
271
+ const bylineId = await resolveImportByline(
272
+ item.author,
273
+ item.author, // display name fallback is the login
274
+ authorId,
275
+ bylineRepo,
276
+ bylineCache,
277
+ );
278
+
279
+ // Resolve translation link: if this item has a translationGroup and
280
+ // we've already imported another item in the same group, link them.
281
+ let translationOf: string | undefined;
282
+ if (item.translationGroup) {
283
+ const existingGroupItem = translationGroupMap.get(item.translationGroup);
284
+ if (existingGroupItem) {
285
+ translationOf = existingGroupItem;
286
+ }
287
+ }
288
+
289
+ // Create the content item
290
+ const createResult = await emdash.handleContentCreate(collection, {
291
+ data,
292
+ slug,
293
+ status,
294
+ authorId,
295
+ bylines: bylineId ? [{ bylineId }] : undefined,
296
+ locale: item.locale,
297
+ translationOf,
298
+ });
299
+
300
+ if (createResult.success) {
301
+ result.imported++;
302
+ result.byCollection[collection] = (result.byCollection[collection] || 0) + 1;
303
+
304
+ // Track translation group: first item in a group establishes the mapping
305
+ if (item.translationGroup && !translationGroupMap.has(item.translationGroup)) {
306
+ // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler success data includes id
307
+ const createdData = createResult.data as { id?: string } | undefined;
308
+ if (createdData?.id) {
309
+ translationGroupMap.set(item.translationGroup, createdData.id);
310
+ }
311
+ }
312
+ } else {
313
+ result.errors.push({
314
+ title: item.title || "Untitled",
315
+ error:
316
+ typeof createResult.error === "object" && createResult.error !== null
317
+ ? (createResult.error as { message?: string }).message || "Unknown error"
318
+ : String(createResult.error),
319
+ });
320
+ }
321
+ } catch (error) {
322
+ console.error(`Import error for "${item.title || "Untitled"}":`, error);
323
+ result.errors.push({
324
+ title: item.title || "Untitled",
325
+ error: "Failed to import item",
326
+ });
327
+ }
328
+ }
329
+
330
+ result.success = result.errors.length === 0;
331
+ return result;
332
+ }
333
+
334
+ function mapStatus(wpStatus: string | undefined): string {
335
+ switch (wpStatus) {
336
+ case "publish":
337
+ return "published";
338
+ case "draft":
339
+ return "draft";
340
+ case "pending":
341
+ return "draft";
342
+ case "private":
343
+ return "draft";
344
+ default:
345
+ return "draft";
346
+ }
347
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Admin manifest endpoint - injected by EmDash integration
3
+ *
4
+ * GET /_emdash/api/manifest
5
+ *
6
+ * Returns the admin manifest with collection definitions and plugin info.
7
+ * The manifest is generated from the user's live.config.ts at runtime.
8
+ */
9
+
10
+ import type { APIRoute } from "astro";
11
+
12
+ import { getAuthMode } from "#auth/mode.js";
13
+
14
+ import type { EmDashManifest } from "../../types.js";
15
+
16
+ export const prerender = false;
17
+
18
+ export const GET: APIRoute = async ({ locals }) => {
19
+ const { emdashManifest, emdash } = locals;
20
+
21
+ // Determine auth mode from config
22
+ const authMode = getAuthMode(emdash?.config);
23
+
24
+ // Check if self-signup is enabled (any allowed domain with enabled = 1)
25
+ // Only relevant for passkey auth — external auth providers handle their own signup
26
+ let signupEnabled = false;
27
+ if (emdash?.db && authMode.type === "passkey") {
28
+ try {
29
+ const { sql } = await import("kysely");
30
+ const result = await sql<{ cnt: unknown }>`
31
+ SELECT COUNT(*) as cnt FROM allowed_domains WHERE enabled = 1
32
+ `.execute(emdash.db);
33
+ signupEnabled = Number(result.rows[0]?.cnt ?? 0) > 0;
34
+ } catch {
35
+ // Table may not exist yet, that's fine
36
+ }
37
+ }
38
+
39
+ const manifest: EmDashManifest = emdashManifest
40
+ ? {
41
+ ...emdashManifest,
42
+ authMode: authMode.type === "external" ? authMode.providerType : "passkey",
43
+ signupEnabled,
44
+ }
45
+ : {
46
+ version: "0.1.0",
47
+ hash: "default",
48
+ collections: {},
49
+ plugins: {},
50
+ authMode: "passkey",
51
+ signupEnabled,
52
+ };
53
+
54
+ return Response.json(
55
+ { data: manifest },
56
+ {
57
+ headers: {
58
+ "Cache-Control": "private, no-store",
59
+ },
60
+ },
61
+ );
62
+ };
@@ -0,0 +1,124 @@
1
+ /**
2
+ * MCP Streamable HTTP endpoint
3
+ *
4
+ * Exposes an MCP server at /_emdash/api/mcp using the Streamable HTTP
5
+ * transport (Web Standard variant). The server runs stateless — each
6
+ * request creates a fresh transport, so no session tracking is needed.
7
+ * Authentication is handled by the existing EmDash auth middleware.
8
+ *
9
+ * POST /_emdash/api/mcp — JSON-RPC tool calls
10
+ * GET /_emdash/api/mcp — SSE stream (not used in stateless mode)
11
+ * DELETE /_emdash/api/mcp — Session close (not used in stateless mode)
12
+ */
13
+
14
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
15
+ import type { APIRoute } from "astro";
16
+
17
+ import { apiError } from "#api/error.js";
18
+ import { createMcpServer } from "#mcp/server.js";
19
+
20
+ export const prerender = false;
21
+
22
+ export const POST: APIRoute = async ({ request, locals }) => {
23
+ const { emdash, user } = locals;
24
+
25
+ if (!emdash) {
26
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
27
+ }
28
+
29
+ if (!user) {
30
+ return apiError("UNAUTHORIZED", "Authentication required", 401);
31
+ }
32
+
33
+ const server = createMcpServer();
34
+
35
+ try {
36
+ const transport = new WebStandardStreamableHTTPServerTransport({
37
+ // Stateless: no session management
38
+ sessionIdGenerator: undefined,
39
+ });
40
+
41
+ await server.connect(transport);
42
+
43
+ return await transport.handleRequest(request, {
44
+ authInfo: {
45
+ token: "",
46
+ clientId: "emdash-admin",
47
+ scopes: [],
48
+ extra: {
49
+ emdash,
50
+ userId: user.id,
51
+ userRole: user.role,
52
+ tokenScopes: locals.tokenScopes,
53
+ },
54
+ },
55
+ });
56
+ } catch (error) {
57
+ console.error("[MCP]", error);
58
+ await server.close().catch(() => {});
59
+
60
+ return new Response(
61
+ JSON.stringify({
62
+ jsonrpc: "2.0",
63
+ error: {
64
+ code: -32603,
65
+ message: "Internal server error",
66
+ },
67
+ id: null,
68
+ }),
69
+ {
70
+ status: 500,
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ "Cache-Control": "private, no-store",
74
+ },
75
+ },
76
+ );
77
+ }
78
+ };
79
+
80
+ /**
81
+ * GET — SSE stream. Not used in stateless mode.
82
+ */
83
+ export const GET: APIRoute = async () => {
84
+ return new Response(
85
+ JSON.stringify({
86
+ jsonrpc: "2.0",
87
+ error: {
88
+ code: -32000,
89
+ message: "Method not allowed. This is a stateless MCP endpoint — use POST.",
90
+ },
91
+ id: null,
92
+ }),
93
+ {
94
+ status: 405,
95
+ headers: {
96
+ "Content-Type": "application/json",
97
+ "Cache-Control": "private, no-store",
98
+ },
99
+ },
100
+ );
101
+ };
102
+
103
+ /**
104
+ * DELETE — Session close. Not used in stateless mode.
105
+ */
106
+ export const DELETE: APIRoute = async () => {
107
+ return new Response(
108
+ JSON.stringify({
109
+ jsonrpc: "2.0",
110
+ error: {
111
+ code: -32000,
112
+ message: "Method not allowed. This is a stateless MCP endpoint.",
113
+ },
114
+ id: null,
115
+ }),
116
+ {
117
+ status: 405,
118
+ headers: {
119
+ "Content-Type": "application/json",
120
+ "Cache-Control": "private, no-store",
121
+ },
122
+ },
123
+ );
124
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Confirm media upload endpoint
3
+ *
4
+ * POST /_emdash/api/media/{id}/confirm
5
+ *
6
+ * Confirms that the client has successfully uploaded the file to storage.
7
+ * Marks the media record as ready and optionally updates metadata.
8
+ */
9
+
10
+ import type { APIRoute } from "astro";
11
+ import { MediaRepository } from "emdash";
12
+
13
+ import { requirePerm } from "#api/authorize.js";
14
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
15
+ import { isParseError, parseOptionalBody } from "#api/parse.js";
16
+ import { mediaConfirmBody } from "#api/schemas.js";
17
+ import type { MediaItem } from "#types";
18
+
19
+ export const prerender = false;
20
+
21
+ /**
22
+ * Add URL to media item (relative URL for portability)
23
+ */
24
+ function addUrlToMedia(item: MediaItem): MediaItem & { url: string } {
25
+ return {
26
+ ...item,
27
+ url: `/_emdash/api/media/file/${item.storageKey}`,
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Confirm upload completion
33
+ */
34
+ export const POST: APIRoute = async ({ params, request, locals }) => {
35
+ const { emdash, user } = locals;
36
+ const { id } = params;
37
+
38
+ const denied = requirePerm(user, "media:upload");
39
+ if (denied) return denied;
40
+
41
+ if (!id) {
42
+ return apiError("INVALID_REQUEST", "Media ID is required", 400);
43
+ }
44
+
45
+ if (!emdash?.db) {
46
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
47
+ }
48
+
49
+ try {
50
+ const body = await parseOptionalBody(request, mediaConfirmBody, {});
51
+ if (isParseError(body)) return body;
52
+
53
+ const repo = new MediaRepository(emdash.db);
54
+
55
+ // Get the media item first to check status
56
+ const existing = await repo.findById(id);
57
+ if (!existing) {
58
+ return apiError("NOT_FOUND", `Media item not found: ${id}`, 404);
59
+ }
60
+
61
+ if (existing.status !== "pending") {
62
+ return apiError("INVALID_STATE", `Media item is not pending: ${existing.status}`, 400);
63
+ }
64
+
65
+ // Optionally verify the file exists in storage
66
+ if (emdash.storage) {
67
+ const exists = await emdash.storage.exists(existing.storageKey);
68
+ if (!exists) {
69
+ // Mark as failed
70
+ await repo.markFailed(id);
71
+ return apiError("FILE_NOT_FOUND", "File was not uploaded to storage", 400);
72
+ }
73
+ }
74
+
75
+ // Confirm the upload
76
+ const item = await repo.confirmUpload(id, {
77
+ size: body.size,
78
+ width: body.width,
79
+ height: body.height,
80
+ });
81
+
82
+ if (!item) {
83
+ return apiError("CONFIRM_FAILED", "Failed to confirm upload", 500);
84
+ }
85
+
86
+ // Add URL to the response (relative URL for portability)
87
+ const itemWithUrl = addUrlToMedia(item);
88
+
89
+ return apiSuccess({ item: itemWithUrl });
90
+ } catch (error) {
91
+ return handleError(error, "Failed to confirm upload", "CONFIRM_ERROR");
92
+ }
93
+ };