emdash 0.0.0-a → 0.0.1

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 -1
  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 +1333 -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-B-u2F2b6.mjs +1412 -0
  127. package/dist/runner-B-u2F2b6.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 +687 -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 +353 -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 +328 -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 +120 -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 +117 -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 +105 -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 +62 -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 +72 -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 +699 -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 +288 -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 +136 -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 +42 -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 +253 -0
  646. package/src/storage/s3.ts +271 -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,62 @@
1
+ /**
2
+ * Marketplace plugin install endpoint
3
+ *
4
+ * POST /_emdash/api/admin/plugins/marketplace/:id/install - Install a marketplace plugin
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+ import { z } from "zod";
9
+
10
+ import { requirePerm } from "#api/authorize.js";
11
+ import { apiError, handleError, unwrapResult } from "#api/error.js";
12
+ import { handleMarketplaceInstall } from "#api/index.js";
13
+ import { isParseError, parseOptionalBody } from "#api/parse.js";
14
+
15
+ export const prerender = false;
16
+
17
+ const installBodySchema = z.object({
18
+ version: z.string().min(1).optional(),
19
+ });
20
+
21
+ export const POST: APIRoute = async ({ params, request, locals }) => {
22
+ try {
23
+ const { emdash, user } = locals;
24
+ const { id } = params;
25
+
26
+ if (!emdash?.db) {
27
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
28
+ }
29
+
30
+ const denied = requirePerm(user, "plugins:manage");
31
+ if (denied) return denied;
32
+
33
+ if (!id) {
34
+ return apiError("INVALID_REQUEST", "Plugin ID required", 400);
35
+ }
36
+
37
+ const body = await parseOptionalBody(request, installBodySchema, {});
38
+ if (isParseError(body)) return body;
39
+
40
+ const configuredPluginIds = new Set<string>(
41
+ emdash.configuredPlugins.map((p: { id: string }) => p.id),
42
+ );
43
+
44
+ const result = await handleMarketplaceInstall(
45
+ emdash.db,
46
+ emdash.storage,
47
+ emdash.getSandboxRunner(),
48
+ emdash.config.marketplace,
49
+ id,
50
+ { version: body.version, configuredPluginIds },
51
+ );
52
+
53
+ if (!result.success) return unwrapResult(result);
54
+
55
+ await emdash.syncMarketplacePlugins();
56
+
57
+ return unwrapResult(result, 201);
58
+ } catch (error) {
59
+ console.error("[marketplace-install] Unhandled error:", error);
60
+ return handleError(error, "Failed to install plugin from marketplace", "INSTALL_FAILED");
61
+ }
62
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Marketplace search proxy endpoint
3
+ *
4
+ * GET /_emdash/api/admin/plugins/marketplace - Search marketplace plugins
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { apiError, unwrapResult } from "#api/error.js";
11
+ import { handleMarketplaceSearch } from "#api/index.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const GET: APIRoute = async ({ url, locals }) => {
16
+ const { emdash, user } = locals;
17
+
18
+ if (!emdash?.db) {
19
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
20
+ }
21
+
22
+ const denied = requirePerm(user, "plugins:read");
23
+ if (denied) return denied;
24
+
25
+ const query = url.searchParams.get("q") ?? undefined;
26
+ const category = url.searchParams.get("category") ?? undefined;
27
+ const cursor = url.searchParams.get("cursor") ?? undefined;
28
+ const limitParam = url.searchParams.get("limit");
29
+ const limit = limitParam ? Math.min(Math.max(1, parseInt(limitParam, 10) || 50), 100) : undefined;
30
+
31
+ const result = await handleMarketplaceSearch(emdash.config.marketplace, query, {
32
+ category,
33
+ cursor,
34
+ limit,
35
+ });
36
+
37
+ return unwrapResult(result);
38
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Marketplace update check endpoint
3
+ *
4
+ * GET /_emdash/api/admin/plugins/updates - Check for marketplace plugin updates
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { apiError, unwrapResult } from "#api/error.js";
11
+ import { handleMarketplaceUpdateCheck } from "#api/index.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const GET: APIRoute = async ({ locals }) => {
16
+ const { emdash, user } = locals;
17
+
18
+ if (!emdash?.db) {
19
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
20
+ }
21
+
22
+ const denied = requirePerm(user, "plugins:read");
23
+ if (denied) return denied;
24
+
25
+ const result = await handleMarketplaceUpdateCheck(emdash.db, emdash.config.marketplace);
26
+
27
+ return unwrapResult(result);
28
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Theme marketplace detail proxy endpoint
3
+ *
4
+ * GET /_emdash/api/admin/themes/marketplace/:id - Get theme details
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { apiError, unwrapResult } from "#api/error.js";
11
+ import { handleThemeGetDetail } from "#api/index.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const GET: APIRoute = async ({ params, locals }) => {
16
+ const { emdash, user } = locals;
17
+ const { id } = params;
18
+
19
+ if (!emdash?.db) {
20
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
21
+ }
22
+
23
+ const denied = requirePerm(user, "plugins:read");
24
+ if (denied) return denied;
25
+
26
+ if (!id) {
27
+ return apiError("INVALID_REQUEST", "Theme ID required", 400);
28
+ }
29
+
30
+ const result = await handleThemeGetDetail(emdash.config.marketplace, id);
31
+
32
+ return unwrapResult(result);
33
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Theme marketplace thumbnail proxy
3
+ *
4
+ * GET /_emdash/api/admin/themes/marketplace/:id/thumbnail - Proxy thumbnail from marketplace
5
+ *
6
+ * Avoids CORS/auth issues when the marketplace Worker is behind Cloudflare Access
7
+ * or on a different origin. The admin UI uses this instead of linking directly.
8
+ */
9
+
10
+ import type { APIRoute } from "astro";
11
+
12
+ import { requirePerm } from "#api/authorize.js";
13
+ import { apiError } from "#api/error.js";
14
+
15
+ export const prerender = false;
16
+
17
+ export const GET: APIRoute = async ({ params, url, locals }) => {
18
+ const { emdash, user } = locals;
19
+ const { id } = params;
20
+
21
+ if (!emdash?.db) {
22
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
23
+ }
24
+
25
+ const denied = requirePerm(user, "plugins:read");
26
+ if (denied) return denied;
27
+
28
+ const marketplaceUrl = emdash.config.marketplace;
29
+ if (!marketplaceUrl || !id) {
30
+ return apiError("NOT_CONFIGURED", "Marketplace not configured", 400);
31
+ }
32
+
33
+ const width = url.searchParams.get("w");
34
+ const target = new URL(`/api/v1/themes/${encodeURIComponent(id)}/thumbnail`, marketplaceUrl);
35
+ if (width) target.searchParams.set("w", width);
36
+
37
+ try {
38
+ const resp = await fetch(target.href);
39
+ if (!resp.ok) {
40
+ // Allowlist: only forward Content-Type from upstream.
41
+ // Never copy all upstream headers (denylist approach leaks
42
+ // headers we haven't anticipated).
43
+ return new Response(resp.body, {
44
+ status: resp.status,
45
+ headers: {
46
+ "Content-Type": resp.headers.get("Content-Type") ?? "application/octet-stream",
47
+ "Cache-Control": "private, no-store",
48
+ },
49
+ });
50
+ }
51
+
52
+ return new Response(resp.body, {
53
+ headers: {
54
+ "Content-Type": resp.headers.get("Content-Type") ?? "image/png",
55
+ "Cache-Control": "private, no-store",
56
+ },
57
+ });
58
+ } catch {
59
+ return apiError("PROXY_ERROR", "Failed to fetch thumbnail", 502);
60
+ }
61
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Theme marketplace search proxy endpoint
3
+ *
4
+ * GET /_emdash/api/admin/themes/marketplace - Search marketplace themes
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { apiError, unwrapResult } from "#api/error.js";
11
+ import { handleThemeSearch } from "#api/index.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const GET: APIRoute = async ({ url, locals }) => {
16
+ const { emdash, user } = locals;
17
+
18
+ if (!emdash?.db) {
19
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
20
+ }
21
+
22
+ const denied = requirePerm(user, "plugins:read");
23
+ if (denied) return denied;
24
+
25
+ const query = url.searchParams.get("q") ?? undefined;
26
+ const keyword = url.searchParams.get("keyword") ?? undefined;
27
+ const sortParam = url.searchParams.get("sort");
28
+ const validSorts = new Set(["name", "created", "updated"]);
29
+ let sort: "name" | "created" | "updated" | undefined;
30
+ if (sortParam && validSorts.has(sortParam)) {
31
+ sort = sortParam as "name" | "created" | "updated"; // eslint-disable-line typescript-eslint(no-unsafe-type-assertion) -- validated by Set.has()
32
+ }
33
+ const cursor = url.searchParams.get("cursor") ?? undefined;
34
+ const limitParam = url.searchParams.get("limit");
35
+ const limit = limitParam ? Math.min(Math.max(1, parseInt(limitParam, 10) || 50), 100) : undefined;
36
+
37
+ const result = await handleThemeSearch(emdash.config.marketplace, query, {
38
+ keyword,
39
+ sort,
40
+ cursor,
41
+ limit,
42
+ });
43
+
44
+ return unwrapResult(result);
45
+ };
@@ -0,0 +1,69 @@
1
+ /**
2
+ * User disable endpoint
3
+ *
4
+ * POST /_emdash/api/admin/users/:id/disable - Soft-disable a user
5
+ */
6
+
7
+ import { Role } from "@emdash-cms/auth";
8
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
9
+ import type { APIRoute } from "astro";
10
+
11
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const POST: APIRoute = async ({ params, locals }) => {
16
+ const { emdash, user: currentUser } = locals;
17
+
18
+ if (!emdash?.db) {
19
+ return apiError("NOT_CONFIGURED", "Database not configured", 500);
20
+ }
21
+
22
+ if (!currentUser || currentUser.role < Role.ADMIN) {
23
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
24
+ }
25
+
26
+ const adapter = createKyselyAdapter(emdash.db);
27
+
28
+ const { id } = params;
29
+
30
+ if (!id) {
31
+ return apiError("VALIDATION_ERROR", "User ID required", 400);
32
+ }
33
+
34
+ // Prevent disabling self
35
+ if (id === currentUser.id) {
36
+ return apiError("VALIDATION_ERROR", "Cannot disable your own account", 400);
37
+ }
38
+
39
+ try {
40
+ // Get target user
41
+ const targetUser = await adapter.getUserById(id);
42
+ if (!targetUser) {
43
+ return apiError("NOT_FOUND", "User not found", 404);
44
+ }
45
+
46
+ // Check if this would leave no active admins
47
+ if (targetUser.role === Role.ADMIN) {
48
+ const adminCount = await adapter.countAdmins();
49
+ if (adminCount <= 1) {
50
+ return apiError(
51
+ "VALIDATION_ERROR",
52
+ "Cannot disable the last admin. Promote another user first.",
53
+ 400,
54
+ );
55
+ }
56
+ }
57
+
58
+ // Disable user
59
+ await adapter.updateUser(id, { disabled: true });
60
+
61
+ // SEC-43: Revoke all OAuth tokens for the disabled user.
62
+ // Without this, existing refresh tokens remain valid for up to 90 days.
63
+ await emdash.db.deleteFrom("_emdash_oauth_tokens").where("user_id", "=", id).execute();
64
+
65
+ return apiSuccess({ success: true });
66
+ } catch (error) {
67
+ return handleError(error, "Failed to disable user", "USER_DISABLE_ERROR");
68
+ }
69
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * User enable endpoint
3
+ *
4
+ * POST /_emdash/api/admin/users/:id/enable - Re-enable a disabled user
5
+ */
6
+
7
+ import { Role } from "@emdash-cms/auth";
8
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
9
+ import type { APIRoute } from "astro";
10
+
11
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const POST: APIRoute = async ({ params, locals }) => {
16
+ const { emdash, user } = locals;
17
+
18
+ if (!emdash?.db) {
19
+ return apiError("NOT_CONFIGURED", "Database not configured", 500);
20
+ }
21
+
22
+ if (!user || user.role < Role.ADMIN) {
23
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
24
+ }
25
+
26
+ const adapter = createKyselyAdapter(emdash.db);
27
+
28
+ const { id } = params;
29
+
30
+ if (!id) {
31
+ return apiError("VALIDATION_ERROR", "User ID required", 400);
32
+ }
33
+
34
+ try {
35
+ // Get target user
36
+ const targetUser = await adapter.getUserById(id);
37
+ if (!targetUser) {
38
+ return apiError("NOT_FOUND", "User not found", 404);
39
+ }
40
+
41
+ // Enable user
42
+ await adapter.updateUser(id, { disabled: false });
43
+
44
+ return apiSuccess({ success: true });
45
+ } catch (error) {
46
+ return handleError(error, "Failed to enable user", "USER_ENABLE_ERROR");
47
+ }
48
+ };
@@ -0,0 +1,146 @@
1
+ /**
2
+ * User management detail endpoint
3
+ *
4
+ * GET /_emdash/api/admin/users/:id - Get user details
5
+ * PUT /_emdash/api/admin/users/:id - Update user
6
+ */
7
+
8
+ import { Role } from "@emdash-cms/auth";
9
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
10
+ import type { APIRoute } from "astro";
11
+
12
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
13
+ import { isParseError, parseBody } from "#api/parse.js";
14
+ import { userUpdateBody } from "#api/schemas.js";
15
+
16
+ export const prerender = false;
17
+
18
+ export const GET: APIRoute = async ({ params, locals }) => {
19
+ const { emdash, user: currentUser } = locals;
20
+
21
+ if (!emdash?.db) {
22
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
23
+ }
24
+
25
+ if (!currentUser || currentUser.role < Role.ADMIN) {
26
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
27
+ }
28
+
29
+ const adapter = createKyselyAdapter(emdash.db);
30
+
31
+ const { id } = params;
32
+
33
+ if (!id) {
34
+ return apiError("MISSING_PARAM", "User ID required", 400);
35
+ }
36
+
37
+ try {
38
+ const result = await adapter.getUserWithDetails(id);
39
+
40
+ if (!result) {
41
+ return apiError("NOT_FOUND", "User not found", 404);
42
+ }
43
+
44
+ // Transform for JSON serialization
45
+ const item = {
46
+ id: result.user.id,
47
+ email: result.user.email,
48
+ name: result.user.name,
49
+ avatarUrl: result.user.avatarUrl,
50
+ role: result.user.role,
51
+ emailVerified: result.user.emailVerified,
52
+ disabled: result.user.disabled,
53
+ createdAt: result.user.createdAt.toISOString(),
54
+ updatedAt: result.user.updatedAt.toISOString(),
55
+ lastLogin: result.lastLogin?.toISOString() ?? null,
56
+ credentials: result.credentials.map((c) => ({
57
+ id: c.id,
58
+ name: c.name,
59
+ deviceType: c.deviceType,
60
+ createdAt: c.createdAt.toISOString(),
61
+ lastUsedAt: c.lastUsedAt.toISOString(),
62
+ })),
63
+ oauthAccounts: result.oauthAccounts.map((a) => ({
64
+ provider: a.provider,
65
+ createdAt: a.createdAt.toISOString(),
66
+ })),
67
+ };
68
+
69
+ return apiSuccess({ item });
70
+ } catch (error) {
71
+ return handleError(error, "Failed to get user details", "USER_DETAIL_ERROR");
72
+ }
73
+ };
74
+
75
+ export const PUT: APIRoute = async ({ params, request, locals }) => {
76
+ const { emdash, user: currentUser } = locals;
77
+
78
+ if (!emdash?.db) {
79
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
80
+ }
81
+
82
+ if (!currentUser || currentUser.role < Role.ADMIN) {
83
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
84
+ }
85
+
86
+ const adapter = createKyselyAdapter(emdash.db);
87
+
88
+ const { id } = params;
89
+
90
+ if (!id) {
91
+ return apiError("MISSING_PARAM", "User ID required", 400);
92
+ }
93
+
94
+ try {
95
+ // Get target user
96
+ const targetUser = await adapter.getUserById(id);
97
+ if (!targetUser) {
98
+ return apiError("NOT_FOUND", "User not found", 404);
99
+ }
100
+
101
+ const body = await parseBody(request, userUpdateBody);
102
+ if (isParseError(body)) return body;
103
+
104
+ // Role is already validated as RoleLevel by Zod schema
105
+ const role = body.role;
106
+
107
+ // Prevent editing own role (security: prevents self-demotion/lockout)
108
+ if (role !== undefined && id === currentUser.id) {
109
+ return apiError("SELF_ROLE_CHANGE", "Cannot change your own role", 400);
110
+ }
111
+
112
+ // Check email uniqueness if changing email
113
+ if (body.email && body.email !== targetUser.email) {
114
+ const existing = await adapter.getUserByEmail(body.email);
115
+ if (existing) {
116
+ return apiError("EMAIL_IN_USE", "Email already in use", 409);
117
+ }
118
+ }
119
+
120
+ // Update user
121
+ await adapter.updateUser(id, {
122
+ name: body.name,
123
+ email: body.email,
124
+ role,
125
+ });
126
+
127
+ // Fetch updated user
128
+ const updated = await adapter.getUserById(id);
129
+
130
+ return apiSuccess({
131
+ item: {
132
+ id: updated!.id,
133
+ email: updated!.email,
134
+ name: updated!.name,
135
+ avatarUrl: updated!.avatarUrl,
136
+ role: updated!.role,
137
+ emailVerified: updated!.emailVerified,
138
+ disabled: updated!.disabled,
139
+ createdAt: updated!.createdAt.toISOString(),
140
+ updatedAt: updated!.updatedAt.toISOString(),
141
+ },
142
+ });
143
+ } catch (error) {
144
+ return handleError(error, "Failed to update user", "USER_UPDATE_ERROR");
145
+ }
146
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Send recovery link endpoint
3
+ *
4
+ * POST /_emdash/api/admin/users/:id/send-recovery
5
+ *
6
+ * Admin-initiated account recovery — sends a recovery magic link to the user's email.
7
+ */
8
+
9
+ import { Role, sendMagicLink, type MagicLinkConfig } from "@emdash-cms/auth";
10
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
11
+ import type { APIRoute } from "astro";
12
+
13
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
14
+ import { getSiteBaseUrl } from "#api/site-url.js";
15
+ import { OptionsRepository } from "#db/repositories/options.js";
16
+
17
+ export const prerender = false;
18
+
19
+ export const POST: APIRoute = async ({ request, params, locals }) => {
20
+ const { emdash, user } = locals;
21
+
22
+ if (!emdash?.db) {
23
+ return apiError("NOT_CONFIGURED", "Database not configured", 500);
24
+ }
25
+
26
+ if (!user || user.role < Role.ADMIN) {
27
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
28
+ }
29
+
30
+ const { id } = params;
31
+
32
+ if (!id) {
33
+ return apiError("VALIDATION_ERROR", "User ID required", 400);
34
+ }
35
+
36
+ try {
37
+ const adapter = createKyselyAdapter(emdash.db);
38
+
39
+ // Verify target user exists
40
+ const targetUser = await adapter.getUserById(id);
41
+ if (!targetUser) {
42
+ return apiError("NOT_FOUND", "User not found", 404);
43
+ }
44
+
45
+ // Check if email pipeline is available
46
+ if (!emdash.email?.isAvailable()) {
47
+ return apiError(
48
+ "EMAIL_NOT_CONFIGURED",
49
+ "Email is not configured. Recovery links require an email provider.",
50
+ 503,
51
+ );
52
+ }
53
+
54
+ // Build config using stored site URL (not request Host header)
55
+ const options = new OptionsRepository(emdash.db);
56
+ const baseUrl = await getSiteBaseUrl(emdash.db, request);
57
+ const siteName = (await options.get<string>("emdash:site_title")) ?? "EmDash";
58
+
59
+ const config: MagicLinkConfig = {
60
+ baseUrl,
61
+ siteName,
62
+ email: (message) => emdash.email!.send(message, "system"),
63
+ };
64
+
65
+ // Send recovery link
66
+ await sendMagicLink(config, adapter, targetUser.email, "recovery");
67
+
68
+ return apiSuccess({ success: true, message: "Recovery link sent" });
69
+ } catch (error) {
70
+ return handleError(error, "Failed to send recovery link", "RECOVERY_SEND_ERROR");
71
+ }
72
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * User management list endpoint
3
+ *
4
+ * GET /_emdash/api/admin/users - List users with search, filter, pagination
5
+ */
6
+
7
+ import { Role } from "@emdash-cms/auth";
8
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
9
+ import type { APIRoute } from "astro";
10
+
11
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
12
+ import { isParseError, parseQuery } from "#api/parse.js";
13
+ import { usersListQuery } from "#api/schemas.js";
14
+
15
+ export const prerender = false;
16
+
17
+ export const GET: APIRoute = async ({ url, locals }) => {
18
+ const { emdash, user } = locals;
19
+
20
+ if (!emdash?.db) {
21
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
22
+ }
23
+
24
+ if (!user || user.role < Role.ADMIN) {
25
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
26
+ }
27
+
28
+ const adapter = createKyselyAdapter(emdash.db);
29
+
30
+ try {
31
+ // Parse query parameters
32
+ const query = parseQuery(url, usersListQuery);
33
+ if (isParseError(query)) return query;
34
+
35
+ // Fetch users
36
+ const result = await adapter.getUsers({
37
+ search: query.search,
38
+ role: query.role ? parseInt(query.role, 10) : undefined,
39
+ cursor: query.cursor,
40
+ limit: query.limit,
41
+ });
42
+
43
+ // Transform dates to ISO strings for JSON serialization
44
+ const items = result.items.map((u) => ({
45
+ id: u.id,
46
+ email: u.email,
47
+ name: u.name,
48
+ avatarUrl: u.avatarUrl,
49
+ role: u.role,
50
+ emailVerified: u.emailVerified,
51
+ disabled: u.disabled,
52
+ createdAt: u.createdAt.toISOString(),
53
+ updatedAt: u.updatedAt.toISOString(),
54
+ lastLogin: u.lastLogin?.toISOString() ?? null,
55
+ credentialCount: u.credentialCount,
56
+ oauthProviders: u.oauthProviders,
57
+ }));
58
+
59
+ return apiSuccess({
60
+ items,
61
+ nextCursor: result.nextCursor,
62
+ });
63
+ } catch (error) {
64
+ return handleError(error, "Failed to list users", "USER_LIST_ERROR");
65
+ }
66
+ };