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,108 @@
1
+ /**
2
+ * GET/POST /_emdash/api/admin/allowed-domains
3
+ *
4
+ * Admin endpoints for managing allowed signup domains.
5
+ * GET - List all allowed domains
6
+ * POST - Add a new allowed domain
7
+ */
8
+
9
+ import type { APIRoute } from "astro";
10
+
11
+ export const prerender = false;
12
+
13
+ import { Role, roleFromLevel } from "@emdash-cms/auth";
14
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
15
+
16
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
17
+ import { isParseError, parseBody } from "#api/parse.js";
18
+ import { allowedDomainCreateBody } from "#api/schemas.js";
19
+
20
+ const DOMAIN_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9-]+)+$/;
21
+
22
+ /**
23
+ * GET - List all allowed domains
24
+ */
25
+ export const GET: APIRoute = async ({ locals }) => {
26
+ const { emdash, user } = locals;
27
+
28
+ if (!emdash?.db) {
29
+ return apiError("NOT_CONFIGURED", "Database not configured", 500);
30
+ }
31
+
32
+ if (!user || user.role < Role.ADMIN) {
33
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
34
+ }
35
+
36
+ const adapter = createKyselyAdapter(emdash.db);
37
+
38
+ try {
39
+ const domains = await adapter.getAllowedDomains();
40
+
41
+ return apiSuccess({
42
+ domains: domains.map((d) => ({
43
+ domain: d.domain,
44
+ defaultRole: d.defaultRole,
45
+ roleName: roleFromLevel(d.defaultRole),
46
+ enabled: d.enabled,
47
+ createdAt: d.createdAt.toISOString(),
48
+ })),
49
+ });
50
+ } catch (error) {
51
+ return handleError(error, "Failed to list allowed domains", "DOMAIN_LIST_ERROR");
52
+ }
53
+ };
54
+
55
+ /**
56
+ * POST - Add a new allowed domain
57
+ */
58
+ export const POST: APIRoute = async ({ request, locals }) => {
59
+ const { emdash, user } = locals;
60
+
61
+ if (!emdash?.db) {
62
+ return apiError("NOT_CONFIGURED", "Database not configured", 500);
63
+ }
64
+
65
+ if (!user || user.role < Role.ADMIN) {
66
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
67
+ }
68
+
69
+ const adapter = createKyselyAdapter(emdash.db);
70
+
71
+ try {
72
+ const body = await parseBody(request, allowedDomainCreateBody);
73
+ if (isParseError(body)) return body;
74
+
75
+ // Role is already validated as RoleLevel by Zod schema
76
+ const defaultRole = body.defaultRole;
77
+
78
+ // Validate domain format (no protocol, just domain)
79
+ const cleanDomain = body.domain.toLowerCase().trim();
80
+ if (!DOMAIN_REGEX.test(cleanDomain)) {
81
+ return apiError("VALIDATION_ERROR", "Invalid domain format", 400);
82
+ }
83
+
84
+ // Check if domain already exists
85
+ const existing = await adapter.getAllowedDomain(cleanDomain);
86
+ if (existing) {
87
+ return apiError("CONFLICT", "Domain already exists", 409);
88
+ }
89
+
90
+ const domain = await adapter.createAllowedDomain(cleanDomain, defaultRole);
91
+
92
+ return apiSuccess(
93
+ {
94
+ success: true,
95
+ domain: {
96
+ domain: domain.domain,
97
+ defaultRole: domain.defaultRole,
98
+ roleName: roleFromLevel(domain.defaultRole),
99
+ enabled: domain.enabled,
100
+ createdAt: domain.createdAt.toISOString(),
101
+ },
102
+ },
103
+ 201,
104
+ );
105
+ } catch (error) {
106
+ return handleError(error, "Failed to create allowed domain", "DOMAIN_CREATE_ERROR");
107
+ }
108
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Single API token endpoint
3
+ *
4
+ * DELETE /_emdash/api/admin/api-tokens/:id — Revoke a token
5
+ */
6
+
7
+ import { Role } from "@emdash-cms/auth";
8
+ import type { APIRoute } from "astro";
9
+
10
+ import { apiError, handleError, unwrapResult } from "#api/error.js";
11
+ import { handleApiTokenRevoke } from "#api/handlers/api-tokens.js";
12
+
13
+ export const prerender = false;
14
+
15
+ /**
16
+ * Revoke (delete) an API token.
17
+ */
18
+ export const DELETE: APIRoute = async ({ params, locals }) => {
19
+ const { emdash, user } = locals;
20
+
21
+ if (!emdash?.db) {
22
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
23
+ }
24
+
25
+ if (!user || user.role < Role.ADMIN) {
26
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
27
+ }
28
+
29
+ const tokenId = params.id;
30
+ if (!tokenId) {
31
+ return apiError("VALIDATION_ERROR", "Token ID is required", 400);
32
+ }
33
+
34
+ try {
35
+ const result = await handleApiTokenRevoke(emdash.db, tokenId, user.id);
36
+ return unwrapResult(result);
37
+ } catch (error) {
38
+ return handleError(error, "Failed to revoke API token", "TOKEN_REVOKE_ERROR");
39
+ }
40
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * API token management endpoints
3
+ *
4
+ * GET /_emdash/api/admin/api-tokens — List tokens for current user
5
+ * POST /_emdash/api/admin/api-tokens — Create a new token
6
+ */
7
+
8
+ import { Role } from "@emdash-cms/auth";
9
+ import type { APIRoute } from "astro";
10
+ import { z } from "zod";
11
+
12
+ import { apiError, handleError, unwrapResult } from "#api/error.js";
13
+ import { handleApiTokenCreate, handleApiTokenList } from "#api/handlers/api-tokens.js";
14
+ import { isParseError, parseBody } from "#api/parse.js";
15
+ import { VALID_SCOPES } from "#auth/api-tokens.js";
16
+
17
+ export const prerender = false;
18
+
19
+ const createTokenSchema = z.object({
20
+ name: z.string().min(1).max(100),
21
+ scopes: z.array(z.enum(VALID_SCOPES)).min(1),
22
+ expiresAt: z.string().datetime().optional(),
23
+ });
24
+
25
+ /**
26
+ * List API tokens for the current user.
27
+ * Admins can list all tokens (future: add ?userId= filter).
28
+ */
29
+ export const GET: APIRoute = async ({ locals }) => {
30
+ const { emdash, user } = locals;
31
+
32
+ if (!emdash?.db) {
33
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
34
+ }
35
+
36
+ if (!user || user.role < Role.ADMIN) {
37
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
38
+ }
39
+
40
+ const result = await handleApiTokenList(emdash.db, user.id);
41
+ return unwrapResult(result);
42
+ };
43
+
44
+ /**
45
+ * Create a new API token.
46
+ * Returns the raw token once — it cannot be retrieved again.
47
+ */
48
+ export const POST: APIRoute = async ({ request, locals }) => {
49
+ const { emdash, user } = locals;
50
+
51
+ if (!emdash?.db) {
52
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
53
+ }
54
+
55
+ if (!user || user.role < Role.ADMIN) {
56
+ return apiError("FORBIDDEN", "Admin privileges required", 403);
57
+ }
58
+
59
+ try {
60
+ const body = await parseBody(request, createTokenSchema);
61
+ if (isParseError(body)) return body;
62
+
63
+ const result = await handleApiTokenCreate(emdash.db, user.id, body);
64
+ return unwrapResult(result, 201);
65
+ } catch (error) {
66
+ return handleError(error, "Failed to create API token", "TOKEN_CREATE_ERROR");
67
+ }
68
+ };
@@ -0,0 +1,87 @@
1
+ import { Role } from "@emdash-cms/auth";
2
+ import type { APIRoute } from "astro";
3
+
4
+ import { requirePerm } from "#api/authorize.js";
5
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
6
+ import { isParseError, parseBody } from "#api/parse.js";
7
+ import { bylineUpdateBody } from "#api/schemas.js";
8
+ import { BylineRepository } from "#db/repositories/byline.js";
9
+
10
+ export const prerender = false;
11
+
12
+ function requireEditor(user: { role: number } | undefined): Response | null {
13
+ if (!user || user.role < Role.EDITOR) {
14
+ return apiError("FORBIDDEN", "Editor privileges required", 403);
15
+ }
16
+ return null;
17
+ }
18
+
19
+ export const GET: APIRoute = async ({ params, locals }) => {
20
+ const { emdash, user } = locals;
21
+ // Read access uses content:read so all authenticated roles can view byline data
22
+ const denied = requirePerm(user, "content:read");
23
+ if (denied) return denied;
24
+
25
+ if (!emdash?.db) {
26
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
27
+ }
28
+
29
+ try {
30
+ const repo = new BylineRepository(emdash.db);
31
+ const byline = await repo.findById(params.id!);
32
+ if (!byline) return apiError("NOT_FOUND", "Byline not found", 404);
33
+ return apiSuccess(byline);
34
+ } catch (error) {
35
+ return handleError(error, "Failed to get byline", "BYLINE_GET_ERROR");
36
+ }
37
+ };
38
+
39
+ export const PUT: APIRoute = async ({ params, request, locals }) => {
40
+ const { emdash, user } = locals;
41
+ const denied = requireEditor(user);
42
+ if (denied) return denied;
43
+
44
+ if (!emdash?.db) {
45
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
46
+ }
47
+
48
+ const body = await parseBody(request, bylineUpdateBody);
49
+ if (isParseError(body)) return body;
50
+
51
+ try {
52
+ const repo = new BylineRepository(emdash.db);
53
+ const byline = await repo.update(params.id!, {
54
+ slug: body.slug,
55
+ displayName: body.displayName,
56
+ bio: body.bio ?? null,
57
+ avatarMediaId: body.avatarMediaId ?? null,
58
+ websiteUrl: body.websiteUrl ?? null,
59
+ userId: body.userId ?? null,
60
+ isGuest: body.isGuest,
61
+ });
62
+
63
+ if (!byline) return apiError("NOT_FOUND", "Byline not found", 404);
64
+ return apiSuccess(byline);
65
+ } catch (error) {
66
+ return handleError(error, "Failed to update byline", "BYLINE_UPDATE_ERROR");
67
+ }
68
+ };
69
+
70
+ export const DELETE: APIRoute = async ({ params, locals }) => {
71
+ const { emdash, user } = locals;
72
+ const denied = requireEditor(user);
73
+ if (denied) return denied;
74
+
75
+ if (!emdash?.db) {
76
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
77
+ }
78
+
79
+ try {
80
+ const repo = new BylineRepository(emdash.db);
81
+ const deleted = await repo.delete(params.id!);
82
+ if (!deleted) return apiError("NOT_FOUND", "Byline not found", 404);
83
+ return apiSuccess({ deleted: true });
84
+ } catch (error) {
85
+ return handleError(error, "Failed to delete byline", "BYLINE_DELETE_ERROR");
86
+ }
87
+ };
@@ -0,0 +1,72 @@
1
+ import { Role } from "@emdash-cms/auth";
2
+ import type { APIRoute } from "astro";
3
+
4
+ import { requirePerm } from "#api/authorize.js";
5
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
6
+ import { isParseError, parseBody, parseQuery } from "#api/parse.js";
7
+ import { bylineCreateBody, bylinesListQuery } from "#api/schemas.js";
8
+ import { BylineRepository } from "#db/repositories/byline.js";
9
+
10
+ export const prerender = false;
11
+
12
+ export const GET: APIRoute = async ({ url, locals }) => {
13
+ const { emdash, user } = locals;
14
+
15
+ if (!emdash?.db) {
16
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
17
+ }
18
+
19
+ // Read access uses content:read so all authenticated roles can view byline data
20
+ const denied = requirePerm(user, "content:read");
21
+ if (denied) return denied;
22
+
23
+ const query = parseQuery(url, bylinesListQuery);
24
+ if (isParseError(query)) return query;
25
+
26
+ try {
27
+ const repo = new BylineRepository(emdash.db);
28
+ const result = await repo.findMany({
29
+ search: query.search,
30
+ isGuest: query.isGuest,
31
+ userId: query.userId,
32
+ cursor: query.cursor,
33
+ limit: query.limit,
34
+ });
35
+
36
+ return apiSuccess(result);
37
+ } catch (error) {
38
+ return handleError(error, "Failed to list bylines", "BYLINE_LIST_ERROR");
39
+ }
40
+ };
41
+
42
+ export const POST: APIRoute = async ({ request, locals }) => {
43
+ const { emdash, user } = locals;
44
+
45
+ if (!emdash?.db) {
46
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
47
+ }
48
+
49
+ if (!user || user.role < Role.EDITOR) {
50
+ return apiError("FORBIDDEN", "Editor privileges required", 403);
51
+ }
52
+
53
+ const body = await parseBody(request, bylineCreateBody);
54
+ if (isParseError(body)) return body;
55
+
56
+ try {
57
+ const repo = new BylineRepository(emdash.db);
58
+ const byline = await repo.create({
59
+ slug: body.slug,
60
+ displayName: body.displayName,
61
+ bio: body.bio ?? null,
62
+ avatarMediaId: body.avatarMediaId ?? null,
63
+ websiteUrl: body.websiteUrl ?? null,
64
+ userId: body.userId ?? null,
65
+ isGuest: body.isGuest,
66
+ });
67
+
68
+ return apiSuccess(byline, 201);
69
+ } catch (error) {
70
+ return handleError(error, "Failed to create byline", "BYLINE_CREATE_ERROR");
71
+ }
72
+ };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Comment status change
3
+ *
4
+ * PUT /_emdash/api/admin/comments/:id/status - Change comment status
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { apiError, apiSuccess, handleError, requireDb, unwrapResult } from "#api/error.js";
11
+ import { handleCommentGet } from "#api/handlers/comments.js";
12
+ import { isParseError, parseBody } from "#api/parse.js";
13
+ import { commentStatusBody } from "#api/schemas.js";
14
+ import { getSiteBaseUrl } from "#api/site-url.js";
15
+ import { lookupContentAuthor, sendCommentNotification } from "#comments/notifications.js";
16
+ import { moderateComment, type CommentHookRunner } from "#comments/service.js";
17
+ import type { CommentStatus } from "#db/repositories/comment.js";
18
+ import type { ModerationDecision } from "#plugins/types.js";
19
+
20
+ export const prerender = false;
21
+
22
+ export const PUT: APIRoute = async ({ params, request, locals }) => {
23
+ const { emdash, user } = locals;
24
+ const { id } = params;
25
+
26
+ if (!id) {
27
+ return apiError("VALIDATION_ERROR", "Comment ID required", 400);
28
+ }
29
+
30
+ const dbErr = requireDb(emdash?.db);
31
+ if (dbErr) return dbErr;
32
+
33
+ const denied = requirePerm(user, "comments:moderate");
34
+ if (denied) return denied;
35
+
36
+ try {
37
+ const body = await parseBody(request, commentStatusBody);
38
+ if (isParseError(body)) return body;
39
+
40
+ const newStatus = body.status as CommentStatus;
41
+
42
+ // Build hook runner for the service
43
+ const hookRunner: CommentHookRunner = {
44
+ async runBeforeCreate(event) {
45
+ return emdash.hooks.runCommentBeforeCreate(event);
46
+ },
47
+ async runModerate(event) {
48
+ const result = await emdash.hooks.invokeExclusiveHook("comment:moderate", event);
49
+ if (!result) return { status: "pending" as const, reason: "No moderator configured" };
50
+ if (result.error) return { status: "pending" as const, reason: "Moderation error" };
51
+ return result.result as ModerationDecision;
52
+ },
53
+ fireAfterCreate(event) {
54
+ emdash.hooks
55
+ .runCommentAfterCreate(event)
56
+ .catch((err) =>
57
+ console.error(
58
+ "[comments] afterCreate error:",
59
+ err instanceof Error ? err.message : err,
60
+ ),
61
+ );
62
+ },
63
+ fireAfterModerate(event) {
64
+ emdash.hooks
65
+ .runCommentAfterModerate(event)
66
+ .catch((err) =>
67
+ console.error(
68
+ "[comments] afterModerate error:",
69
+ err instanceof Error ? err.message : err,
70
+ ),
71
+ );
72
+ },
73
+ };
74
+
75
+ // Read the comment before updating so we know the previous status
76
+ const existing = await handleCommentGet(emdash.db, id);
77
+ if (!existing.success) {
78
+ return unwrapResult(existing);
79
+ }
80
+ const previousStatus = existing.data.status;
81
+
82
+ const updated = await moderateComment(
83
+ emdash.db,
84
+ id,
85
+ newStatus,
86
+ { id: user!.id, name: user!.name ?? null },
87
+ hookRunner,
88
+ );
89
+
90
+ if (!updated) {
91
+ return apiError("NOT_FOUND", "Comment not found", 404);
92
+ }
93
+
94
+ // Send notification when a comment is newly approved
95
+ if (newStatus === "approved" && previousStatus !== "approved" && emdash.email) {
96
+ try {
97
+ const adminBaseUrl = await getSiteBaseUrl(emdash.db, request);
98
+ const content = await lookupContentAuthor(
99
+ emdash.db,
100
+ updated.collection,
101
+ updated.contentId,
102
+ );
103
+ if (content?.author) {
104
+ await sendCommentNotification({
105
+ email: emdash.email,
106
+ comment: updated,
107
+ contentAuthor: content.author,
108
+ adminBaseUrl,
109
+ });
110
+ }
111
+ } catch (err) {
112
+ console.error("[comments] notification error:", err instanceof Error ? err.message : err);
113
+ }
114
+ }
115
+
116
+ return apiSuccess(updated);
117
+ } catch (error) {
118
+ return handleError(error, "Failed to update comment status", "COMMENT_STATUS_ERROR");
119
+ }
120
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Single comment admin endpoints
3
+ *
4
+ * GET /_emdash/api/admin/comments/:id - Get comment detail
5
+ * DELETE /_emdash/api/admin/comments/:id - Hard delete (ADMIN only)
6
+ */
7
+
8
+ import type { APIRoute } from "astro";
9
+
10
+ import { requirePerm } from "#api/authorize.js";
11
+ import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
12
+ import { handleCommentGet, handleCommentDelete } from "#api/handlers/comments.js";
13
+
14
+ export const prerender = false;
15
+
16
+ /**
17
+ * Get single comment detail (includes moderation_metadata)
18
+ */
19
+ export const GET: APIRoute = async ({ params, locals }) => {
20
+ const { emdash, user } = locals;
21
+ const { id } = params;
22
+
23
+ if (!id) {
24
+ return apiError("VALIDATION_ERROR", "Comment ID required", 400);
25
+ }
26
+
27
+ const dbErr = requireDb(emdash?.db);
28
+ if (dbErr) return dbErr;
29
+
30
+ const denied = requirePerm(user, "comments:moderate");
31
+ if (denied) return denied;
32
+
33
+ try {
34
+ const result = await handleCommentGet(emdash.db, id);
35
+ return unwrapResult(result);
36
+ } catch (error) {
37
+ return handleError(error, "Failed to get comment", "COMMENT_GET_ERROR");
38
+ }
39
+ };
40
+
41
+ /**
42
+ * Hard delete a comment (ADMIN only)
43
+ */
44
+ export const DELETE: APIRoute = async ({ params, locals }) => {
45
+ const { emdash, user } = locals;
46
+ const { id } = params;
47
+
48
+ if (!id) {
49
+ return apiError("VALIDATION_ERROR", "Comment ID required", 400);
50
+ }
51
+
52
+ const dbErr = requireDb(emdash?.db);
53
+ if (dbErr) return dbErr;
54
+
55
+ const denied = requirePerm(user, "comments:delete");
56
+ if (denied) return denied;
57
+
58
+ try {
59
+ const result = await handleCommentDelete(emdash.db, id);
60
+ return unwrapResult(result);
61
+ } catch (error) {
62
+ return handleError(error, "Failed to delete comment", "COMMENT_DELETE_ERROR");
63
+ }
64
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Bulk comment operations
3
+ *
4
+ * POST /_emdash/api/admin/comments/bulk - Bulk status change or delete
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { handleError, requireDb, unwrapResult } from "#api/error.js";
11
+ import { handleCommentBulk } from "#api/handlers/comments.js";
12
+ import { isParseError, parseBody } from "#api/parse.js";
13
+ import { commentBulkBody } from "#api/schemas.js";
14
+
15
+ export const prerender = false;
16
+
17
+ export const POST: APIRoute = async ({ request, locals }) => {
18
+ const { emdash, user } = locals;
19
+
20
+ const dbErr = requireDb(emdash?.db);
21
+ if (dbErr) return dbErr;
22
+
23
+ try {
24
+ const body = await parseBody(request, commentBulkBody);
25
+ if (isParseError(body)) return body;
26
+
27
+ // Bulk delete requires ADMIN, bulk status change requires EDITOR
28
+ if (body.action === "delete") {
29
+ const denied = requirePerm(user, "comments:delete");
30
+ if (denied) return denied;
31
+ } else {
32
+ const denied = requirePerm(user, "comments:moderate");
33
+ if (denied) return denied;
34
+ }
35
+
36
+ const result = await handleCommentBulk(emdash.db, body.ids, body.action);
37
+
38
+ return unwrapResult(result);
39
+ } catch (error) {
40
+ return handleError(error, "Failed to perform bulk operation", "COMMENT_BULK_ERROR");
41
+ }
42
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Comment status counts for inbox badges
3
+ *
4
+ * GET /_emdash/api/admin/comments/counts
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { handleError, requireDb, unwrapResult } from "#api/error.js";
11
+ import { handleCommentCounts } from "#api/handlers/comments.js";
12
+
13
+ export const prerender = false;
14
+
15
+ export const GET: APIRoute = async ({ locals }) => {
16
+ const { emdash, user } = locals;
17
+
18
+ const dbErr = requireDb(emdash?.db);
19
+ if (dbErr) return dbErr;
20
+
21
+ const denied = requirePerm(user, "comments:moderate");
22
+ if (denied) return denied;
23
+
24
+ try {
25
+ const result = await handleCommentCounts(emdash.db);
26
+ return unwrapResult(result);
27
+ } catch (error) {
28
+ return handleError(error, "Failed to get comment counts", "COMMENT_COUNTS_ERROR");
29
+ }
30
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Admin comment inbox
3
+ *
4
+ * GET /_emdash/api/admin/comments - List comments (filterable by status, collection, search)
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { handleError, requireDb, unwrapResult } from "#api/error.js";
11
+ import { handleCommentInbox } from "#api/handlers/comments.js";
12
+ import { isParseError, parseQuery } from "#api/parse.js";
13
+ import { commentListQuery } from "#api/schemas.js";
14
+ import type { CommentStatus } from "#db/repositories/comment.js";
15
+
16
+ export const prerender = false;
17
+
18
+ /**
19
+ * List comments for moderation inbox
20
+ */
21
+ export const GET: APIRoute = async ({ url, locals }) => {
22
+ const { emdash, user } = locals;
23
+
24
+ const dbErr = requireDb(emdash?.db);
25
+ if (dbErr) return dbErr;
26
+
27
+ const denied = requirePerm(user, "comments:moderate");
28
+ if (denied) return denied;
29
+
30
+ try {
31
+ const query = parseQuery(url, commentListQuery);
32
+ if (isParseError(query)) return query;
33
+
34
+ const result = await handleCommentInbox(emdash.db, {
35
+ status: query.status as CommentStatus | undefined,
36
+ collection: query.collection,
37
+ search: query.search,
38
+ limit: query.limit,
39
+ cursor: query.cursor,
40
+ });
41
+
42
+ return unwrapResult(result);
43
+ } catch (error) {
44
+ return handleError(error, "Failed to list comments", "COMMENT_INBOX_ERROR");
45
+ }
46
+ };